From 14c1b8fd542beabba68646dab93f4862b364a4b3 Mon Sep 17 00:00:00 2001 From: Terry Ellison Date: Thu, 18 Jul 2019 17:02:02 +0100 Subject: [PATCH 01/59] Lua 5.1 to 5.3 realignement phase 1 --- .gdbinitlua | 20 +- app/Makefile | 4 +- app/driver/Makefile | 2 +- app/driver/input.c | 196 +++++++++++ app/driver/pwm.c | 6 +- app/driver/readline.c | 111 ------ app/driver/rotary.c | 5 +- app/driver/spi.c | 19 +- app/driver/switec.c | 2 +- app/driver/uart.c | 39 ++- app/include/driver/input.h | 11 + app/include/driver/readline.h | 6 - app/include/driver/uart.h | 3 +- app/include/task/task.h | 47 +-- app/include/user_config.h | 4 +- app/lua/Makefile | 2 +- app/lua/lauxlib.c | 5 +- app/lua/lauxlib.h | 4 +- app/lua/lbaselib.c | 21 +- app/lua/ldblib.c | 4 +- app/lua/lflash.c | 30 +- app/lua/lnodemcu.c | 116 +++++++ app/lua/loadlib.c | 2 +- app/lua/lobject.h | 2 +- app/lua/lstate.c | 11 +- app/lua/lstate.h | 1 + app/lua/lua.c | 611 +++++++++++----------------------- app/lua/lua.h | 27 +- app/modules/gpio.c | 1 + app/modules/gpio_pulse.c | 8 +- app/modules/net.c | 22 +- app/modules/node.c | 114 +++---- app/modules/pipe.c | 286 ++++++++++++---- app/modules/somfy.c | 1 + app/modules/uart.c | 92 ++--- app/platform/platform.c | 110 +++++- app/platform/platform.h | 25 +- app/platform/vfs.h | 22 +- app/pm/swtimer.c | 1 + app/task/Makefile | 41 --- app/task/task.c | 72 ---- app/user/user_main.c | 56 +--- docs/modules/node.md | 45 +-- docs/modules/pipe.md | 6 +- 44 files changed, 1115 insertions(+), 1098 deletions(-) create mode 100644 app/driver/input.c delete mode 100644 app/driver/readline.c create mode 100644 app/include/driver/input.h delete mode 100644 app/include/driver/readline.h create mode 100644 app/lua/lnodemcu.c delete mode 100644 app/task/Makefile delete mode 100644 app/task/task.c diff --git a/.gdbinitlua b/.gdbinitlua index b832fab5f1..ef467354b6 100644 --- a/.gdbinitlua +++ b/.gdbinitlua @@ -3,9 +3,9 @@ set pagination off set print null-stop define prTS - set $o = &(((TString *)($arg0))->tsv) + set $o = &(((TString *)(($arg0).value))->tsv) printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked - printf "String: hash = 0x%08x, len = %u : %s\n", $o->hash, $o->len, (char *)(&$o[1]) + printf "String: hash = 0x%08x, len = %u : %s\n", $o->hash, $o->len, (char *)($o+1) end define prTnodes @@ -24,6 +24,18 @@ define prTnodes set $i = $i +1 end end + +define prTarray + set $o = (Table *)($arg0) + set $n = $o->sizearray + set $i = 0 + while $i < $n + set $nd = ($o->array) + $i + prTV $nd + set $i = $i +1 + end +end + define prTV if $arg0 set $type = ($arg0).tt @@ -78,6 +90,10 @@ define prTV end if $type == 9 # UserData + set $o = &($val->gc.u.uv) + printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked + printf "UD = %p Userdata: metatable = ", ($o+1)) + print ($o)->metatable end if $type == 10 # Thread diff --git a/app/Makefile b/app/Makefile index 4fab0eedaa..a419c52602 100644 --- a/app/Makefile +++ b/app/Makefile @@ -36,7 +36,6 @@ SUBDIRS= \ libc \ lua \ lwip \ - task \ smart \ modules \ spiffs \ @@ -64,8 +63,7 @@ COMPONENTS_eagle.app.v6 = \ user/libuser.a \ crypto/libcrypto.a \ driver/libdriver.a \ - platform/libplatform.a \ - task/libtask.a \ + platform/libplatform.a \ libc/liblibc.a \ lua/liblua.a \ lwip/liblwip.a \ diff --git a/app/driver/Makefile b/app/driver/Makefile index 5dbd685374..cee238339e 100644 --- a/app/driver/Makefile +++ b/app/driver/Makefile @@ -15,7 +15,7 @@ ifndef PDIR GEN_LIBS = libdriver.a endif -STD_CFLAGS=-std=gnu11 -Wimplicit +STD_CFLAGS=-std=gnu11 -Wimplicit -Wall ############################################################# # Configuration i.e. compile options etc. diff --git a/app/driver/input.c b/app/driver/input.c new file mode 100644 index 0000000000..79a522f8ef --- /dev/null +++ b/app/driver/input.c @@ -0,0 +1,196 @@ +#include "platform.h" +#include "driver/uart.h" +#include "driver/input.h" +#include +#include "mem.h" + +/**DEBUG**/extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); + +static void input_handler(platform_task_param_t flag, uint8 priority); + +static struct input_state { + char *data; + int line_pos; + size_t len; + const char *prompt; + uart_cb_t uart_cb; + platform_task_handle_t input_sig; + int data_len; + bool run_input; + bool uart_echo; + char last_char; + char end_char; + uint8 input_sig_flag; +} ins = {0}; + +#define NUL '\0' +#define BS '\010' +#define CR '\r' +#define LF '\n' +#define DEL 0x7f +#define BS_OVER "\010 \010" + +#define sendStr(s) uart0_sendStr(s) +#define putc(c) uart0_putc(c) + +// UartDev is defined and initialized in rom code. +extern UartDevice UartDev; + +static bool uart_getc(char *c){ + RcvMsgBuff *pRxBuff = &(UartDev.rcv_buff); + if(pRxBuff->pWritePos == pRxBuff->pReadPos){ // empty + return false; + } + // ETS_UART_INTR_DISABLE(); + ETS_INTR_LOCK(); + *c = (char)*(pRxBuff->pReadPos); + if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) { + pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ; + } else { + pRxBuff->pReadPos++; + } + // ETS_UART_INTR_ENABLE(); + ETS_INTR_UNLOCK(); + return true; +} + +/* +** input_handler at high-priority is a system post task used to process pending Rx +** data on UART0. The flag is used as a latch to stop the interrupt handler posting +** multiple pending requests. At low priority it is used the trigger interactive +** compile. +** +** The ins.data check detects up the first task call which used to initialise +** everything. +*/ +int lua_main (void); +static bool input_readline(void); + +static void input_handler(platform_task_param_t flag, uint8 priority) { + (void) priority; + if (!ins.data) { + lua_main(); + return; + } + ins.input_sig_flag = flag & 0x1; + while (input_readline()) {} +} + +/* +** The input state (ins) is private, so input_setup() exposes the necessary +** access to public properties and is called in user_init() before the Lua +** enviroment is initialised. The second routine input_setup_receive() is +** called in lua.c after the Lua environment is available to bind the Lua +** input handler. Any UART input before this receive setup is ignored. +*/ +void input_setup(int bufsize, const char *prompt) { + // Initialise non-zero elements + ins.run_input = true; + ins.uart_echo = true; + ins.data = os_malloc(bufsize); + ins.len = bufsize; + ins.prompt = prompt; + ins.input_sig = platform_task_get_id(input_handler); + // pass the task CB parameters to the uart driver + uart_init_task(ins.input_sig, &ins.input_sig_flag); + ETS_UART_INTR_ENABLE(); +} + +void input_setup_receive(uart_cb_t uart_on_data_cb, int data_len, char end_char, bool run_input) { + ins.uart_cb = uart_on_data_cb; + ins.data_len = data_len; + ins.end_char = end_char; + ins.run_input = run_input; +} + +void input_setecho (bool flag) { + ins.uart_echo = flag; +} + +void input_setprompt (const char *prompt) { + ins.prompt = prompt; +} + +/* +** input_readline() is called from the input_handler() event routine which is +** posted by the UART Rx ISR posts. This works in one of two modes depending on +** the bool ins.run_input. +** - TRUE: it clears the UART FIFO up to EOL, doing any callback and sending +** the line to Lua. +** - FALSE: it clears the UART FIFO doing callbacks according to the data_len / +** end_char break. +*/ +void lua_input_string (const char *line, int len); + +static bool input_readline(void) { + char ch = NUL; + if (ins.run_input) { + while (uart_getc(&ch)) { + /* handle CR & LF characters and aggregate \n\r and \r\n pairs */ + if ((ch == CR && ins.last_char == LF) || + (ch == LF && ins.last_char == CR)) { + ins.last_char = NUL; + continue; + } + + /* backspace key */ + if (ch == DEL || ch == BS) { + if (ins.line_pos > 0) { + if(ins.uart_echo) sendStr(BS_OVER); + ins.line_pos--; + } + ins.data[ins.line_pos] = 0; + ins.last_char = NUL; + continue; + } + ins.last_char = ch; + + /* end of data */ + if (ch == CR || ch == LF) { + if (ins.uart_echo) putc(LF); + if (ins.uart_cb) ins.uart_cb(ins.data, ins.line_pos); + if (ins.line_pos == 0) { + /* Get a empty data, then go to get a new data */ + + sendStr(ins.prompt); + continue; + } else { + ins.data[ins.line_pos++] = LF; + lua_input_string(ins.data, ins.line_pos); + ins.line_pos = 0; + return true; + } + } + + if(ins.uart_echo) putc(ch); + + /* it's a large data, discard it */ + if ( ins.line_pos + 1 >= ins.len ){ + ins.line_pos = 0; + } + ins.data[ins.line_pos++] = ch; + } + + } else { + + if (!ins.uart_cb) { + while (uart_getc(&ch)) {} + } else if (ins.data_len == 0) { + while (uart_getc(&ch)) { + ins.uart_cb(&ch, 1); + } + } else { + while (uart_getc(&ch)) { + ins.data[ins.line_pos++] = ch; + if( ins.line_pos >= ins.len || + (ins.data_len > 0 && ins.line_pos >= ins.data_len) || + ch == ins.end_char ) { + ins.uart_cb(ins.data, ins.line_pos); + ins.line_pos = 0; + } + } + } + } + return false; +} + diff --git a/app/driver/pwm.c b/app/driver/pwm.c index 6422cc92e7..75b5d068aa 100644 --- a/app/driver/pwm.c +++ b/app/driver/pwm.c @@ -20,7 +20,7 @@ #include "driver/pwm.h" // #define PWM_DBG os_printf -#define PWM_DBG +#define PWM_DBG( ... ) // Enabling the next line will cause the interrupt handler to toggle // this output pin during processing so that the timing is obvious @@ -253,7 +253,7 @@ pwm_set_freq(uint16 freq, uint8 channel) pwm.period = PWM_1S / pwm.freq; } - +#if 0 /****************************************************************************** * FunctionName : pwm_set_freq_duty * Description : set pwm frequency and each channel's duty @@ -274,7 +274,7 @@ pwm_set_freq_duty(uint16 freq, uint16 *duty) pwm_set_duty(duty[i], pwm_out_io_num[i]); } } - +#endif /****************************************************************************** * FunctionName : pwm_get_duty * Description : get duty of each channel diff --git a/app/driver/readline.c b/app/driver/readline.c deleted file mode 100644 index 99192bbc85..0000000000 --- a/app/driver/readline.c +++ /dev/null @@ -1,111 +0,0 @@ -#include "ets_sys.h" -#include "os_type.h" -#include "osapi.h" -#include "driver/uart.h" -#include - -LOCAL os_timer_t readline_timer; - -// UartDev is defined and initialized in rom code. -extern UartDevice UartDev; - -#define uart_putc uart0_putc - -bool uart_getc(char *c){ - RcvMsgBuff *pRxBuff = &(UartDev.rcv_buff); - if(pRxBuff->pWritePos == pRxBuff->pReadPos){ // empty - return false; - } - // ETS_UART_INTR_DISABLE(); - ETS_INTR_LOCK(); - *c = (char)*(pRxBuff->pReadPos); - if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) { - pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ; - } else { - pRxBuff->pReadPos++; - } - // ETS_UART_INTR_ENABLE(); - ETS_INTR_UNLOCK(); - return true; -} - -#if 0 -int readline4lua(const char *prompt, char *buffer, int length){ - char ch; - int line_position; - -start: - /* show prompt */ - uart0_sendStr(prompt); - - line_position = 0; - os_memset(buffer, 0, length); - while (1) - { - while (uart_getc(&ch)) - { - /* handle CR key */ - if (ch == '\r') - { - char next; - if (uart_getc(&next)) - ch = next; - } - /* backspace key */ - else if (ch == 0x7f || ch == 0x08) - { - if (line_position > 0) - { - uart_putc(0x08); - uart_putc(' '); - uart_putc(0x08); - line_position--; - } - buffer[line_position] = 0; - continue; - } - /* EOF(ctrl+d) */ - else if (ch == 0x04) - { - if (line_position == 0) - /* No input which makes lua interpreter close */ - return 0; - else - continue; - } - - /* end of line */ - if (ch == '\r' || ch == '\n') - { - buffer[line_position] = 0; - uart_putc('\n'); - if (line_position == 0) - { - /* Get a empty line, then go to get a new line */ - goto start; - } - else - { - return line_position; - } - } - - /* other control character or not an acsii character */ - if (ch < 0x20 || ch >= 0x80) - { - continue; - } - - /* echo */ - uart_putc(ch); - buffer[line_position] = ch; - ch = 0; - line_position++; - - /* it's a large line, discard it */ - if (line_position >= length) - line_position = 0; - } - } -} -#endif diff --git a/app/driver/rotary.c b/app/driver/rotary.c index c54bda555e..5b8eb5eea1 100644 --- a/app/driver/rotary.c +++ b/app/driver/rotary.c @@ -14,9 +14,9 @@ #include #include #include +#include "task/task.h" #include "driver/rotary.h" #include "user_interface.h" -#include "task/task.h" #include "ets_sys.h" // @@ -37,7 +37,7 @@ #define GET_READ_STATUS(d) (d->queue[d->read_offset & (QUEUE_SIZE - 1)]) #define ADVANCE_IF_POSSIBLE(d) if (d->read_offset < d->write_offset) { d->read_offset++; } -#define STATUS_IS_PRESSED(x) ((x & 0x80000000) != 0) +#define STATUS_IS_PRESSED(x) (((x) & 0x80000000) != 0) typedef struct { int8_t phase_a_pin; @@ -213,7 +213,6 @@ int rotary_setup(uint32_t channel, int phase_a, int phase_b, int press, task_han } data[channel] = d; - int i; d->tasknumber = tasknumber; diff --git a/app/driver/spi.c b/app/driver/spi.c index 2cd05eee04..32abf114c0 100644 --- a/app/driver/spi.c +++ b/app/driver/spi.c @@ -15,7 +15,6 @@ static uint32_t spi_clkdiv[2]; *******************************************************************************/ void spi_lcd_mode_init(uint8 spi_no) { - uint32 regvalue; if(spi_no>1) return; //handle invalid input number //bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock //bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock @@ -112,8 +111,6 @@ uint32_t spi_set_clkdiv(uint8 spi_no, uint32_t clock_div) *******************************************************************************/ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div) { - uint32 regvalue; - if(spi_no>1) return; //handle invalid input number SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER); @@ -258,7 +255,7 @@ void spi_mast_set_mosi(uint8 spi_no, uint16 offset, uint8 bitlen, uint32 data) } shift = 64 - (offset & 0x1f) - bitlen; - spi_buf.dword &= ~((1ULL << bitlen)-1 << shift); + spi_buf.dword &= ~(((1ULL << bitlen)-1) << shift); spi_buf.dword |= (uint64)data << shift; if (wn < 15) { @@ -344,7 +341,7 @@ void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8 uint16 cmd = cmd_data << (16 - cmd_bitlen); // align to MSB cmd = (cmd >> 8) | (cmd << 8); // swap byte order WRITE_PERI_REG(SPI_USER2(spi_no), - ((cmd_bitlen - 1 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | + (((cmd_bitlen - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | (cmd & SPI_USR_COMMAND_VALUE)); SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND); } @@ -387,8 +384,6 @@ void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8 *******************************************************************************/ void spi_byte_write_espslave(uint8 spi_no,uint8 data) { - uint32 regvalue; - if(spi_no>1) return; //handle invalid input number while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); @@ -413,8 +408,6 @@ void spi_byte_write_espslave(uint8 spi_no,uint8 data) *******************************************************************************/ void spi_byte_read_espslave(uint8 spi_no,uint8 *data) { - uint32 regvalue; - if(spi_no>1) return; //handle invalid input number while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); @@ -440,7 +433,7 @@ void spi_byte_write_espslave(uint8 spi_no,uint8 data) *******************************************************************************/ void spi_slave_init(uint8 spi_no) { - uint32 regvalue; +// uint32 regvalue; if(spi_no>1) return; //handle invalid input number @@ -565,7 +558,6 @@ void hspi_master_readwrite_repeat(void) #include "mem.h" static uint8 spi_data[32] = {0}; static uint8 idx = 0; -static uint8 spi_flg = 0; #define SPI_MISO #define SPI_QUEUE_LEN 8 os_event_t * spiQueue; @@ -596,9 +588,8 @@ void ICACHE_FLASH_ATTR void spi_slave_isr_handler(void *para) { - uint32 regvalue,calvalue; - static uint8 state =0; - uint32 recv_data,send_data; + uint32 regvalue; + uint32 recv_data; if(READ_PERI_REG(0x3ff00020)&BIT4){ //following 3 lines is to clear isr signal diff --git a/app/driver/switec.c b/app/driver/switec.c index d776749aec..04242b594f 100644 --- a/app/driver/switec.c +++ b/app/driver/switec.c @@ -18,13 +18,13 @@ #include #include #include +#include "task/task.h" #include "driver/switec.h" #include "ets_sys.h" #include "os_type.h" #include "osapi.h" #include "hw_timer.h" #include "user_interface.h" -#include "task/task.h" #define N_STATES 6 // diff --git a/app/driver/uart.c b/app/driver/uart.c index 944e34000a..5b50d194b9 100644 --- a/app/driver/uart.c +++ b/app/driver/uart.c @@ -12,7 +12,7 @@ #include "ets_sys.h" #include "osapi.h" #include "driver/uart.h" -#include "task/task.h" +#include "platform.h" #include "user_config.h" #include "user_interface.h" #include "osapi.h" @@ -29,15 +29,15 @@ // For event signalling -static task_handle_t sig = 0; +static platform_task_handle_t sig = 0; static uint8 *sig_flag; static uint8 isr_flag = 0; // UartDev is defined and initialized in rom code. extern UartDevice UartDev; - +#ifdef BIT_RATE_AUTOBAUD static os_timer_t autobaud_timer; - +#endif static void (*alt_uart0_tx)(char txchar); LOCAL void ICACHE_RAM_ATTR @@ -165,7 +165,7 @@ uart_tx_one_char(uint8 uart, uint8 TxChar) WRITE_PERI_REG(UART_FIFO(uart) , TxChar); return OK; } - +#if 0 /****************************************************************************** * FunctionName : uart1_write_char * Description : Internal used function @@ -189,7 +189,7 @@ uart1_write_char(char c) uart_tx_one_char(UART1, c); } } - +#endif /****************************************************************************** * FunctionName : uart0_tx_buffer * Description : use uart0 to transfer buffer @@ -300,13 +300,15 @@ uart0_rx_intr_handler(void *para) } if (got_input && sig) { + // Only post a new handler request once the handler has fired clearing the last post if (isr_flag == *sig_flag) { isr_flag ^= 0x01; - task_post_low (sig, 0x8000 | isr_flag << 14 | false); + platform_post_high(sig, isr_flag); } } } +#ifdef BIT_RATE_AUTOBAUD static void uart_autobaud_timeout(void *timer_arg) { @@ -324,7 +326,6 @@ uart_autobaud_timeout(void *timer_arg) } } #include "pm/swtimer.h" - static void uart_init_autobaud(uint32_t uart_no) { @@ -339,22 +340,17 @@ uart_stop_autobaud() { os_timer_disarm(&autobaud_timer); } - +#endif /****************************************************************************** * FunctionName : uart_init * Description : user interface for init uart * Parameters : UartBautRate uart0_br - uart0 bautrate * UartBautRate uart1_br - uart1 bautrate - * os_signal_t sig_input - signal to post - * uint8 *flag_input - flag of consumer task * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input, uint8 *flag_input) +uart_init(UartBautRate uart0_br, UartBautRate uart1_br) { - sig = sig_input; - sig_flag = flag_input; - // rom use 74880 baut_rate, here reinitialize UartDev.baut_rate = uart0_br; uart_config(UART0); @@ -378,6 +374,19 @@ uart_setup(uint8 uart_no) ETS_UART_INTR_ENABLE(); } +/****************************************************************************** + * FunctionName : uart_init_task + * Description : user interface for init uart task callback + * Parameters : os_signal_t sig_input - signal to post + * uint8 *flag_input - flag of consumer task + * Returns : NONE +*******************************************************************************/ + +void ICACHE_FLASH_ATTR uart_init_task(os_signal_t sig_input, uint8 *flag_input) { + sig = sig_input; + sig_flag = flag_input; +} + void ICACHE_FLASH_ATTR uart_set_alt_output_uart0(void (*fn)(char)) { alt_uart0_tx = fn; } diff --git a/app/include/driver/input.h b/app/include/driver/input.h new file mode 100644 index 0000000000..f18f48b6af --- /dev/null +++ b/app/include/driver/input.h @@ -0,0 +1,11 @@ +#ifndef READLINE_APP_H +#define READLINE_APP_H +typedef void (*uart_cb_t)(const char *buf, size_t len); + +extern void input_setup(int bufsize, const char *prompt); +extern void input_setup_receive(uart_cb_t uart_on_data_cb, int data_len, char end_char, bool run_input); +extern void input_setecho (bool flag); +extern void input_setprompt (const char *prompt); +extern void input_process_arm(void); + +#endif /* READLINE_APP_H */ diff --git a/app/include/driver/readline.h b/app/include/driver/readline.h deleted file mode 100644 index ae92cfd170..0000000000 --- a/app/include/driver/readline.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef READLINE_APP_H -#define READLINE_APP_H - -bool uart_getc(char *c); - -#endif /* READLINE_APP_H */ diff --git a/app/include/driver/uart.h b/app/include/driver/uart.h index 310f605417..eb9c4aad98 100644 --- a/app/include/driver/uart.h +++ b/app/include/driver/uart.h @@ -110,7 +110,8 @@ typedef struct { UartStopBitsNum stop_bits; } UartConfig; -void uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input, uint8 *flag_input); +void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); +void uart_init_task(os_signal_t sig_input, uint8 *flag_input); UartConfig uart_get_config(uint8 uart_no); void uart0_alt(uint8 on); void uart0_sendStr(const char *str); diff --git a/app/include/task/task.h b/app/include/task/task.h index b090e54f28..5292d1dc35 100644 --- a/app/include/task/task.h +++ b/app/include/task/task.h @@ -1,35 +1,24 @@ #ifndef _TASK_H_ #define _TASK_H_ - -#include "ets_sys.h" -#include "osapi.h" -#include "os_type.h" -#include "user_interface.h" - -/* use LOW / MEDIUM / HIGH since it isn't clear from the docs which is higher */ - -#define TASK_PRIORITY_LOW 0 -#define TASK_PRIORITY_MEDIUM 1 -#define TASK_PRIORITY_HIGH 2 -#define TASK_PRIORITY_COUNT 3 - /* -* Signals are a 32-bit number of the form header:14; count:16, priority:2. The header -* is just a fixed fingerprint and the count is allocated serially by the task get_id() -* function. -*/ -#define task_post(priority,handle,param) system_os_post(priority, ((handle) | priority), param) -#define task_post_low(handle,param) task_post(TASK_PRIORITY_LOW, handle, param) -#define task_post_medium(handle,param) task_post(TASK_PRIORITY_MEDIUM, handle, param) -#define task_post_high(handle,param) task_post(TASK_PRIORITY_HIGH, handle, param) - -#define task_handle_t os_signal_t -#define task_param_t os_param_t - -typedef void (*task_callback_t)(task_param_t param, uint8 prio); - -bool task_init_handler(uint8 priority, uint8 qlen); -task_handle_t task_get_id(task_callback_t t); +** The task interface is now part of the core platform interface. +** This header is preserved for backwards compatability only. +*/ +#include "platform.h" + +#define TASK_PRIORITY_LOW PLATFORM_TASK_PRIORITY_LOW +#define TASK_PRIORITY_MEDIUM PLATFORM_TASK_PRIORITY_MEDIUM +#define TASK_PRIORITY_HIGH PLATFORM_TASK_PRIORITY_HIGH + +#define task_post(priority,handle,param) platform_post(priority,handle,param) +#define task_post_low(handle,param) platform_post_low(handle,param) +#define task_post_medium(handle,param) platform_post_medium(handle,param) +#define task_post_high(handle,param) platform_post_high(handle,param) + +#define task_handle_t platform_task_handle_t +#define task_param_t platform_task_param_t +#define task_callback_t platform_task_callback_t +#define task_get_id platform_task_get_id #endif diff --git a/app/include/user_config.h b/app/include/user_config.h index 4866e6a91d..d0b923b51c 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -263,14 +263,14 @@ extern void dbg_printf(const char *fmt, ...); #ifdef NODE_DEBUG #define NODE_DBG dbg_printf #else -#define NODE_DBG +#define NODE_DBG( ... ) #endif /* NODE_DEBUG */ #define NODE_ERROR #ifdef NODE_ERROR #define NODE_ERR dbg_printf #else -#define NODE_ERR +#define NODE_ERR( ... ) #endif /* NODE_ERROR */ // #define GPIO_SAFE_NO_INTR_ENABLE diff --git a/app/lua/Makefile b/app/lua/Makefile index 16d97ab05d..aeb66d1755 100644 --- a/app/lua/Makefile +++ b/app/lua/Makefile @@ -16,7 +16,7 @@ SUBDIRS = luac_cross GEN_LIBS = liblua.a endif -STD_CFLAGS=-std=gnu11 -Wimplicit +STD_CFLAGS=-std=gnu11 -Wimplicit -Wall ############################################################# # Configuration i.e. compile options etc. diff --git a/app/lua/lauxlib.c b/app/lua/lauxlib.c index 773d01a35f..07835a19e7 100644 --- a/app/lua/lauxlib.c +++ b/app/lua/lauxlib.c @@ -824,10 +824,9 @@ static int errfsfile (lua_State *L, const char *what, int fnameindex) { } -LUALIB_API int luaL_loadfsfile (lua_State *L, const char *filename) { +LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { LoadFSF lf; - int status, readstatus; - int c; + int status, c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ lf.extraline = 0; if (filename == NULL) { diff --git a/app/lua/lauxlib.h b/app/lua/lauxlib.h index 09dbd2c097..b769ad2ffb 100644 --- a/app/lua/lauxlib.h +++ b/app/lua/lauxlib.h @@ -79,7 +79,7 @@ LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); #ifdef LUA_CROSS_COMPILER LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); #else -LUALIB_API int (luaL_loadfsfile) (lua_State *L, const char *filename); +LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); #endif LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); @@ -119,7 +119,7 @@ LUALIB_API void luaL_assertfail(const char *file, int line, const char *message) (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) #else #define luaL_dofile(L, fn) \ - (luaL_loadfsfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) #endif #define luaL_dostring(L, s) \ diff --git a/app/lua/lbaselib.c b/app/lua/lbaselib.c index 02b69bc872..00e6959f66 100644 --- a/app/lua/lbaselib.c +++ b/app/lua/lbaselib.c @@ -19,8 +19,6 @@ #include "lrotable.h" - - /* ** If your system does not support `stdout', you can just remove this function. ** If you need, you can define your own `print' function, following this @@ -40,20 +38,11 @@ static int luaB_print (lua_State *L) { if (s == NULL) return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); -#if defined(LUA_USE_STDIO) - if (i>1) fputs("\t", c_stdout); - fputs(s, c_stdout); -#else - if (i>1) luai_writestring("\t", 1); - luai_writestring(s, strlen(s)); -#endif + if (i>1) puts("\t"); + puts(s); lua_pop(L, 1); /* pop result */ } -#if defined(LUA_USE_STDIO) - fputs("\n", c_stdout); -#else - luai_writeline(); -#endif + puts("\n"); return 0; } @@ -296,7 +285,7 @@ static int luaB_loadfile (lua_State *L) { #ifdef LUA_CROSS_COMPILER return load_aux(L, luaL_loadfile(L, fname)); #else - return load_aux(L, luaL_loadfsfile(L, fname)); + return load_aux(L, luaL_loadfile(L, fname)); #endif } @@ -343,7 +332,7 @@ static int luaB_dofile (lua_State *L) { #ifdef LUA_CROSS_COMPILER if (luaL_loadfile(L, fname) != 0) lua_error(L); #else - if (luaL_loadfsfile(L, fname) != 0) lua_error(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); #endif lua_call(L, 0, LUA_MULTRET); return lua_gettop(L) - n; diff --git a/app/lua/ldblib.c b/app/lua/ldblib.c index d3926e9d0f..f5193bdcbf 100644 --- a/app/lua/ldblib.c +++ b/app/lua/ldblib.c @@ -365,7 +365,7 @@ static int db_debug (lua_State *L) { #define LEVELS1 12 /* size of the first part of the stack */ #define LEVELS2 10 /* size of the second part of the stack */ -static int db_errorfb (lua_State *L) { +int debug_errorfb (lua_State *L) { int level; int firstpart = 1; /* still before eventual `...' */ int arg; @@ -436,7 +436,7 @@ LROT_PUBLIC_BEGIN(dblib) LROT_FUNCENTRY( setmetatable, db_setmetatable ) LROT_FUNCENTRY( setupvalue, db_setupvalue ) #endif - LROT_FUNCENTRY( traceback, db_errorfb ) + LROT_FUNCENTRY( traceback, debug_errorfb ) LROT_END(dblib, NULL, 0) LUALIB_API int luaopen_debug (lua_State *L) { diff --git a/app/lua/lflash.c b/app/lua/lflash.c index ba1c46d336..d2bf5cc2d5 100644 --- a/app/lua/lflash.c +++ b/app/lua/lflash.c @@ -70,7 +70,7 @@ struct OUTPUT { outBlock buffer; int ndx; uint32_t crc; - int (*fullBlkCB) (void); + void (*fullBlkCB) (void); int flashLen; int flagsLen; int flagsNdx; @@ -79,7 +79,6 @@ struct OUTPUT { } *out; #ifdef NODE_DEBUG -extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); void dumpStrt(stringtable *tb, const char *type) { int i,j; GCObject *o; @@ -173,15 +172,15 @@ LUAI_FUNC void luaN_init (lua_State *L) { } if ((fh->flash_sig & (~FLASH_SIG_ABSOLUTE)) != FLASH_SIG ) { - NODE_ERR("Flash sig not correct: %p vs %p\n", + NODE_ERR("Flash sig not correct: 0x%08x vs 0x%08x\n", fh->flash_sig & (~FLASH_SIG_ABSOLUTE), FLASH_SIG); return; } if (fh->pROhash == ALL_SET || ((fh->mainProto - cast(FlashAddr, fh)) >= fh->flash_size)) { - NODE_ERR("Flash size check failed: %p vs 0xFFFFFFFF; %p >= %p\n", - fh->mainProto - cast(FlashAddr, fh), fh->flash_size); + NODE_ERR("Flash size check failed: 0x%08x vs 0xFFFFFFFF; 0x%08x >= 0x%08x\n", + fh->pROhash, fh->mainProto - cast(FlashAddr, fh), fh->flash_size); return; } @@ -194,7 +193,7 @@ LUAI_FUNC void luaN_init (lua_State *L) { //extern void software_reset(void); static int loadLFS (lua_State *L); static int loadLFSgc (lua_State *L); -static int procFirstPass (void); +static void procFirstPass (void); /* * Library function called by node.flashreload(filename). @@ -270,7 +269,6 @@ LUALIB_API int luaN_reload_reboot (lua_State *L) { * - An array of the module names in the LFS */ LUAI_FUNC int luaN_index (lua_State *L) { - int i; int n = lua_gettop(L); /* Return nil + the LFS base address if the LFS size > 0 and it isn't loaded */ @@ -406,11 +404,10 @@ static uint8_t recall_byte (unsigned offset) { * - Once the flags array is in-buffer this is also captured. * This logic is slightly complicated by the last buffer is typically short. */ -int procFirstPass (void) { +void procFirstPass (void) { int len = (out->ndx % WRITE_BLOCKSIZE) ? out->ndx % WRITE_BLOCKSIZE : WRITE_BLOCKSIZE; if (out->ndx <= WRITE_BLOCKSIZE) { - uint32_t fl; /* Process the flash header and cache the FlashHeader fields we need */ FlashHeader *fh = cast(FlashHeader *, out->block[0]); out->flashLen = fh->flash_size; /* in bytes */ @@ -442,12 +439,10 @@ int procFirstPass (void) { memcpy(out->flags + out->flagsNdx, out->block[0]->byte + start, len - start); out->flagsNdx += (len -start) / WORDSIZE; /* flashLen and len are word aligned */ } - - return 1; } -int procSecondPass (void) { +void procSecondPass (void) { /* * The length rules are different for the second pass since this only processes * upto the flashLen and not the full image. This also works in word units. @@ -456,7 +451,7 @@ int procSecondPass (void) { int i, len = (out->ndx > out->flashLen) ? (out->flashLen % WRITE_BLOCKSIZE) / WORDSIZE : WRITE_BLOCKSIZE / WORDSIZE; - uint32_t *buf = (uint32_t *) out->buffer.byte, flags; + uint32_t *buf = (uint32_t *) out->buffer.byte, flags = 0; /* * Relocate all the addresses tagged in out->flags. This can't be done in * place because the out->blocks are still in use as dictionary content so @@ -492,7 +487,7 @@ int procSecondPass (void) { */ static int loadLFS (lua_State *L) { const char *fn = cast(const char *, lua_touserdata(L, 1)); - int i, n, res; + int i, res; uint32_t crc; /* Allocate and zero in and out structures */ @@ -541,12 +536,11 @@ static int loadLFS (lua_State *L) { flashErase(0,(out->flashLen - 1)/FLASH_PAGE_SIZE); flashSetPosition(0); - if (uzlib_inflate(get_byte, put_byte, recall_byte, - in->len, &crc, &in->inflate_state) != UZLIB_OK) - if (res < 0) { + if ((res = uzlib_inflate(get_byte, put_byte, recall_byte, + in->len, &crc, &in->inflate_state)) != UZLIB_OK) { const char *err[] = {"Data_error during decompression", "Chksum_error during decompression", - "Dictionary error during decompression" + "Dictionary error during decompression", "Memory_error during decompression"}; flash_error(err[UZLIB_DATA_ERROR - res]); } diff --git a/app/lua/lnodemcu.c b/app/lua/lnodemcu.c new file mode 100644 index 0000000000..6d8cf1a236 --- /dev/null +++ b/app/lua/lnodemcu.c @@ -0,0 +1,116 @@ +/* +** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + + +#define lnodemcu_c +#define LUA_CORE + +#include "lua.h" +#include + +#include "lobject.h" +#include "lstate.h" +#include "lauxlib.h" +#include "lgc.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lrotable.h" +#include "platform.h" + +extern int debug_errorfb (lua_State *L); +#if 0 +extern int pipe_create(lua_State *L); +extern int pipe_read(lua_State *L); +extern int pipe_unread(lua_State *L); +extern int pipe_write(lua_State *L); +#endif +/* +** Error Reporting Task. We can't pass a string parameter to the error reporter +** directly through the task interface the call is wrapped in a C closure with +** the error string as an Upval and this is posted to call the Lua reporter. +*/ +static int report_traceback (lua_State *L) { +// **Temp** lua_rawgeti(L, LUA_REGISTRYINDEX, G(L)->error_reporter); + lua_getglobal(L, "print"); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_call(L, 1, 0); /* Using an error handler would cause an infinite loop! */ + return 0; +} + +/* +** Catch all error handler for CB calls. This uses debug.traceback() to +** generate a full Lua traceback. +*/ +int luaN_traceback (lua_State *L) { + if (lua_isstring(L, 1)) { + lua_pushlightfunction(L, &debug_errorfb); + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback and return it as a string */ + lua_pushcclosure(L, report_traceback, 1); /* report with str as upval */ + luaN_posttask(L, LUA_TASK_HIGH); + } + return 0; +} + +/* +** Use in CBs and other C functions to call a Lua function. This includes +** an error handler which will catch any error and then post this to the +** registered reporter function as a separate follow-on task. +*/ +int luaN_call (lua_State *L, int narg, int res, int doGC) { // [-narg, +0, v] + int status; + int base = lua_gettop(L) - narg; + lua_pushcfunction(L, luaN_traceback); + lua_insert(L, base); /* put under args */ + status = lua_pcall(L, narg, (res < 0 ? LUA_MULTRET : res), base); + lua_remove(L, base); /* remove traceback function */ + /* force a complete garbage collection if requested */ + if (doGC) + lua_gc(L, LUA_GCCOLLECT, 0); + return status; +} + +static platform_task_handle_t task_handle = 0; + +/* +** Task callback handler. Uses luaN_call to do a protected call with full traceback +*/ +static void do_task (platform_task_param_t task_fn_ref, uint8_t prio) { + lua_State* L = lua_getstate(); + if (prio < 0|| prio > 2) + luaL_error(L, "invalid posk task"); + +/* Pop the CB func from the Reg */ +//dbg_printf("calling Reg[%u]\n", task_fn_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, (int) task_fn_ref); + luaL_checkanyfunction(L, -1); + luaL_unref(L, LUA_REGISTRYINDEX, (int) task_fn_ref); + lua_pushinteger(L, prio); + luaN_call (L, 1, 0, 1); +} + +/* +** Schedule a Lua function for task execution +*/ +#include "lstate.h" /*DEBUG*/ +LUA_API int luaN_posttask( lua_State* L, int prio ) { // [-1, +0, -] + if (!task_handle) + task_handle = platform_task_get_id(do_task); + + if (!lua_isanyfunction(L, -1) || prio < LUA_TASK_LOW|| prio > LUA_TASK_HIGH) + luaL_error(L, "invalid posk task"); +//void *cl = clvalue(L->top-1); + int task_fn_ref = luaL_ref(L, LUA_REGISTRYINDEX); +//dbg_printf("posting Reg[%u]=%p\n",task_fn_ref,cl); + if(!platform_post(prio, task_handle, (platform_task_param_t)task_fn_ref)) { + luaL_unref(L, LUA_REGISTRYINDEX, task_fn_ref); + luaL_error(L, "Task queue overflow. Task not posted"); + } + return task_fn_ref; +} + diff --git a/app/lua/loadlib.c b/app/lua/loadlib.c index a4ab42c97a..5005969b0d 100644 --- a/app/lua/loadlib.c +++ b/app/lua/loadlib.c @@ -397,7 +397,7 @@ static int loader_Lua (lua_State *L) { #ifdef LUA_CROSS_COMPILER if (luaL_loadfile(L, filename) != 0) #else - if (luaL_loadfsfile(L, filename) != 0) + if (luaL_loadfile(L, filename) != 0) #endif loaderror(L, filename); return 1; /* library loaded successfully */ diff --git a/app/lua/lobject.h b/app/lua/lobject.h index 7741ddbf2d..62bf224f70 100644 --- a/app/lua/lobject.h +++ b/app/lua/lobject.h @@ -113,7 +113,7 @@ typedef struct lua_TValue { #define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) #define ttisrotable(o) (ttype(o) == LUA_TROTABLE) #define ttislightfunction(o) (ttype(o) == LUA_TLIGHTFUNCTION) - +#define ttisanyfunction(o) (ttisfunction(o) || ttislightfunction(o)) /* Macros to access values */ diff --git a/app/lua/lstate.c b/app/lua/lstate.c index 55e107a666..13600f8374 100644 --- a/app/lua/lstate.c +++ b/app/lua/lstate.c @@ -197,11 +197,12 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->memlimit = 0; #endif #ifndef LUA_CROSS_COMPILER - g->ROstrt.size = 0; - g->ROstrt.nuse = 0; - g->ROstrt.hash = NULL; - g->ROpvmain = NULL; - g->LFSsize = 0; + g->ROstrt.size = 0; + g->ROstrt.nuse = 0; + g->ROstrt.hash = NULL; + g->ROpvmain = NULL; + g->LFSsize = 0; + g->error_reporter = 0; #endif for (i=0; imt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { diff --git a/app/lua/lstate.h b/app/lua/lstate.h index 88b7d57f5a..bd9b3660a8 100644 --- a/app/lua/lstate.h +++ b/app/lua/lstate.h @@ -98,6 +98,7 @@ typedef struct global_State { stringtable ROstrt; /* Flash-based hash table for RO strings */ Proto *ROpvmain; /* Flash-based Proto main */ int LFSsize; /* Size of Lua Flash Store */ + int error_reporter; /* Registry Index of error reporter task */ #endif } global_State; diff --git a/app/lua/lua.c b/app/lua/lua.c index 81b04751c2..80afc690b2 100644 --- a/app/lua/lua.c +++ b/app/lua/lua.c @@ -1,18 +1,16 @@ /* -** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $ -** Lua stand-alone interpreter +** NodeMCU Lua 5.1 main initiator and comand interpreter ** See Copyright Notice in lua.h +** +** Note this is largely a backport of some new Lua 5.3 version but +** with API changes for Lua 5.1 compatability */ - #include #include #include -#include "user_interface.h" #include "user_version.h" -#include "driver/readline.h" -#include "driver/uart.h" -#include "platform.h" +#include "driver/input.h" #define lua_c @@ -21,498 +19,283 @@ #include "lauxlib.h" #include "lualib.h" #include "legc.h" -#include "lflash.h" #include "os_type.h" +extern int debug_errorfb (lua_State *L); +extern int pipe_create(lua_State *L); +extern int pipe_read(lua_State *L); +extern int pipe_unread(lua_State *L); + +#ifndef LUA_INIT_STRING +#define LUA_INIT_STRING "@init.lua" +#endif + +static int MLref = LUA_NOREF; lua_State *globalL = NULL; -static lua_Load gLoad; -static const char *progname = LUA_PROGNAME; +static int pmain (lua_State *L); +static int dojob (lua_State *L); -static void l_message (const char *pname, const char *msg) { -#if defined(LUA_USE_STDIO) - if (pname) fprintf(c_stderr, "%s: ", pname); - fprintf(c_stderr, "%s\n", msg); - fflush(c_stderr); -#else - if (pname) luai_writestringerror("%s: ", pname); +static void l_message (const char *msg) { luai_writestringerror("%s\n", msg); -#endif } - static int report (lua_State *L, int status) { if (status && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; - l_message(progname, msg); + l_message(msg); lua_pop(L, 1); } return status; } +static void l_print(lua_State *L, int n) { + lua_getglobal(L, "print"); + lua_insert(L, -n-1); + if (lua_pcall(L, n, 0, 0) != 0) + l_message(lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); +} static int traceback (lua_State *L) { - if (!lua_isstring(L, 1)) /* 'message' not a string? */ - return 1; /* keep it intact */ - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); - if (!lua_istable(L, -1) && !lua_isrotable(L, -1)) { - lua_pop(L, 1); - return 1; - } - lua_getfield(L, -1, "traceback"); - if (!lua_isfunction(L, -1) && !lua_islightfunction(L, -1)) { - lua_pop(L, 2); - return 1; + if (lua_isstring(L, 1)) { + lua_pushlightfunction(L, &debug_errorfb); + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ } - lua_pushvalue(L, 1); /* pass error message */ - lua_pushinteger(L, 2); /* skip this function and traceback */ - lua_call(L, 2, 1); /* call debug.traceback */ + lua_settop(L, 1); return 1; } - static int docall (lua_State *L, int narg, int clear) { int status; - int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, traceback); /* push traceback function */ - lua_insert(L, base); /* put it under chunk and args */ - // signal(SIGINT, laction); + int base = lua_gettop(L) - narg; /* function index */ + lua_pushlightfunction(L, &traceback); /* push traceback function */ + lua_insert(L, base); /* put it under chunk and args */ status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); - // signal(SIGINT, SIG_DFL); - lua_remove(L, base); /* remove traceback function */ + lua_remove(L, base); /* remove traceback function */ /* force a complete garbage collection in case of errors */ if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); return status; } - static void print_version (lua_State *L) { - lua_pushliteral (L, "\n" NODE_VERSION " build " BUILD_DATE " powered by " LUA_RELEASE " on SDK "); + lua_pushliteral (L, "\n" NODE_VERSION " build " BUILD_DATE + " powered by " LUA_RELEASE " on SDK "); lua_pushstring (L, SDK_VERSION); lua_concat (L, 2); const char *msg = lua_tostring (L, -1); - l_message (NULL, msg); + l_message (msg); lua_pop (L, 1); } - -static int getargs (lua_State *L, char **argv, int n) { - int narg; - int i; - int argc = 0; - while (argv[argc]) argc++; /* count total number of arguments */ - narg = argc - (n + 1); /* number of arguments to the script */ - luaL_checkstack(L, narg + 3, "too many arguments to script"); - for (i=n+1; i < argc; i++) - lua_pushstring(L, argv[i]); - lua_createtable(L, narg, n + 1); - for (i=0; i < argc; i++) { - lua_pushstring(L, argv[i]); - lua_rawseti(L, -2, i - n); - } - return narg; -} - -static int dofsfile (lua_State *L, const char *name) { - int status = luaL_loadfsfile(L, name) || docall(L, 0, 1); +static int dofile (lua_State *L, const char *name) { + int status = luaL_loadfile(L, name) || docall(L, 0, 1); return report(L, status); } - static int dostring (lua_State *L, const char *s, const char *name) { int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); return report(L, status); } - -static int dolibrary (lua_State *L, const char *name) { - lua_getglobal(L, "require"); - lua_pushstring(L, name); - return report(L, docall(L, 1, 1)); -} - static const char *get_prompt (lua_State *L, int firstline) { const char *p; - lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ return p; } - +#define EOFMARK LUA_QL("") static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); - const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); - if (strstr(msg, LUA_QL("")) == tp) { + if (!strcmp(msg+lmsg-sizeof(EOFMARK)+1, EOFMARK)) { lua_pop(L, 1); return 1; } } - return 0; /* else... */ + return 0; } +/* +** dojob is the CB reader for the input pipe and follows the calling convention +** for pipe reader CBs. It has one argument: the stdin pipe that it is reading. +*/ +static int dojob (lua_State *L) { + size_t l; + int status; + const char *prompt; + +//dbg_printf("dojob entered\n"); + lua_settop(L, 1); /* pipe obj at S[1] */ + lua_pushlightfunction(L, &pipe_read); /* pobj:read at S[2] */ + lua_pushvalue(L, 1); /* dup pobj to S[3] */ + lua_pushliteral(L, "\n+"); /* S[4] = "\n+" */ + lua_call(L, 2, 1); /* S[2] = pobj:read("\n+") */ + const char* b = lua_tolstring(L, 2, &l); /* b = NULL if S[2] is nil */ + + if ((lua_isnil(L, 2) || l == 0)) { + /* If the pipe is empty then return false to suppress automatic reposting */ +//dbg_printf("stdin empty\n"); + lua_pushboolean(L, false); + return 1; /* return false */ + } -/* check that argument has no extra characters at the end */ -#define notail(x) {if ((x)[2] != '\0') return -1;} - - -static int collectargs (char **argv, int *pi, int *pv, int *pe) { - int i; - for (i = 1; argv[i] != NULL; i++) { - if (argv[i][0] != '-') /* not an option? */ - return i; - switch (argv[i][1]) { /* option */ - case '-': - notail(argv[i]); - return (argv[i+1] != NULL ? i+1 : 0); - case '\0': - return i; - case 'i': - notail(argv[i]); - *pi = 1; /* go through */ - case 'v': - notail(argv[i]); - *pv = 1; - break; - case 'e': - *pe = 1; /* go through */ - case 'm': /* go through */ - case 'l': - if (argv[i][2] == '\0') { - i++; - if (argv[i] == NULL) return -1; - } - break; - default: return -1; /* invalid option */ - } + if (b[l-1] != '\n') { +//dbg_printf("unreading part line\n"); + /* likewise if not CR terminated, then unread and ditto */ + lua_pushlightfunction(L, &pipe_unread); /* pobj:read at S[1] */ + lua_insert(L, 1); + lua_call(L, 2, 0); /* pobj:unread(line) */ + lua_pushboolean(L, false); + return 1; /* return false */ + } else { +//dbg_printf("popping CR terminated string(%d) %s", l-1, b); } - return 0; -} + /* + * Now we can process a proper CR terminated line + */ + lua_pushlstring(L, b, --l); /* remove end CR */ + lua_remove(L, 2); + b = lua_tostring(L, 2); + + if (MLref != LUA_NOREF) { + /* processing multiline */ + lua_rawgeti(L, LUA_REGISTRYINDEX, MLref); /* insert prev lines(s) */ + lua_pushliteral(L, "\n"); /* insert CR */ + lua_pushvalue(L, 2); /* dup new line */ + lua_concat(L, 3); /* concat all 3 */ + lua_remove(L, 2); /* and shift down to S[2] */ + } else if (b[0] == '=') { + /* If firstline and of the format = */ + lua_pushfstring(L, "return %s", b+1); + lua_remove(L, 2); + } + + /* ToS is at S[2] which contains the putative chunk to be compiled */ + status = luaL_loadbuffer(L, lua_tostring(L, 2), lua_strlen(L, 2), "=stdin"); -static int runargs (lua_State *L, char **argv, int n) { - int i; - for (i = 1; i < n; i++) { - if (argv[i] == NULL) continue; - lua_assert(argv[i][0] == '-'); - switch (argv[i][1]) { /* option */ - case 'e': { - const char *chunk = argv[i] + 2; - if (*chunk == '\0') chunk = argv[++i]; - lua_assert(chunk != NULL); - if (dostring(L, chunk, "=(command line)") != 0) - return 1; - break; - } - case 'm': { - const char *limit = argv[i] + 2; - int memlimit=0; - if (*limit == '\0') limit = argv[++i]; - lua_assert(limit != NULL); - memlimit = atoi(limit); - lua_gc(L, LUA_GCSETMEMLIMIT, memlimit); - break; - } - case 'l': { - const char *filename = argv[i] + 2; - if (*filename == '\0') filename = argv[++i]; - lua_assert(filename != NULL); - if (dolibrary(L, filename)) - return 1; /* stop if file fails */ - break; - } - default: break; + if (incomplete(L, status)) { + /* Store line back in the Reg mlref sot */ + if (MLref == LUA_NOREF) { + MLref = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + lua_rawseti(L, LUA_REGISTRYINDEX, MLref); } + } else { + /* compile finished OK or with hard error */ + lua_remove(L, 2); /* remove line because now redundant */ + if (MLref!= LUA_NOREF) { /* also remove multiline if it exists */ + luaL_unref(L, LUA_REGISTRYINDEX, MLref); + MLref= LUA_NOREF; + } + /* Execute the compiled chunk of successful */ + if (status == 0) { + status = docall(L, 0, 0); + } + /* print any returned results or error message */ + if (status && !lua_isnil(L, -1)) + l_print(L, 1); + if (status == 0 && lua_gettop(L) - 1) + l_print(L, lua_gettop(L) - 1); + + lua_settop(L, 2); + if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); } - return 0; -} - -#ifndef LUA_INIT_STRING -#define LUA_INIT_STRING "@init.lua" -#endif + prompt = get_prompt(L, MLref!= LUA_NOREF ? 0 : 1); + input_setprompt(prompt); + puts(prompt); -static int handle_luainit (lua_State *L) { - const char *init = LUA_INIT_STRING; - if (init[0] == '@') - return dofsfile(L, init+1); - else - return dostring(L, init, LUA_INIT); + lua_pushnil(L); + return 1; /* return nil will retask if pipe not empty */ } -struct Smain { - int argc; - char **argv; - int status; -}; - +/* + * Kick off library and UART input handling before opening the module + * libraries. Note that as this is all done within a Lua task, so error + * handling is left to the Lua task traceback mechanism. + */ +extern void luaL_dbgbreak(void); static int pmain (lua_State *L) { - struct Smain *s = (struct Smain *)lua_touserdata(L, 1); - char **argv = s->argv; - int script; - int has_i = 0, has_v = 0, has_e = 0; + const char *init = LUA_INIT_STRING; globalL = L; - if (argv[0] && argv[0][0]) progname = argv[0]; - lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ - luaL_openlibs(L); /* open libraries */ - lua_gc(L, LUA_GCRESTART, 0); - print_version(L); - s->status = handle_luainit(L); - script = collectargs(argv, &has_i, &has_v, &has_e); - if (script < 0) { /* invalid args? */ - s->status = 1; - return 0; - } - s->status = runargs(L, argv, (script > 0) ? script : s->argc); - if (s->status != 0) return 0; - return 0; -} - -static void dojob(lua_Load *load); -static bool readline(lua_Load *load); -#ifdef LUA_RPC -int main (int argc, char **argv) { -#else -int lua_main (int argc, char **argv) { -#endif - int status; - struct Smain s; - -#if defined(NODE_DEBUG) && defined(DEVELOPMENT_USE_GDB) && \ - defined(DEVELOPMENT_BREAK_ON_STARTUP_PIN) && DEVELOPMENT_BREAK_ON_STARTUP_PIN > 0 - platform_gpio_mode( DEVELOPMENT_BREAK_ON_STARTUP_PIN, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP ); - lua_assert(platform_gpio_read(DEVELOPMENT_BREAK_ON_STARTUP_PIN)); // Break if pin pulled low -#endif - - lua_State *L = lua_open(); /* create state */ - if (L == NULL) { - l_message(argv[0], "cannot create state: not enough memory"); - return EXIT_FAILURE; - } - s.argc = argc; - s.argv = argv; - - status = lua_cpcall(L, &pmain, &s); - - report(L, status); - - gLoad.L = L; - gLoad.firstline = 1; - gLoad.done = 0; - gLoad.line = malloc(LUA_MAXINPUT); - gLoad.len = LUA_MAXINPUT; - gLoad.line_position = 0; - gLoad.prmt = get_prompt(L, 1); - - dojob(&gLoad); - - NODE_DBG("Heap size:%d.\n",system_get_free_heap_size()); + lua_gc(L, LUA_GCSTOP, 0); /* stop GC during initialization */ + luaL_openlibs(L); /* open libraries */ + lua_gc(L, LUA_GCRESTART, 0); /* restart GC and set EGC mode */ legc_set_mode( L, EGC_ALWAYS, 4096 ); - // legc_set_mode( L, EGC_ON_MEM_LIMIT, 4096 ); - // lua_close(L); - return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; -} - -int lua_put_line(const char *s, size_t l) { - if (s == NULL || ++l > LUA_MAXINPUT || gLoad.line_position > 0) - return 0; - memcpy(gLoad.line, s, l); - gLoad.line[l] = '\0'; - gLoad.line_position = l; - gLoad.done = 1; - NODE_DBG("Get command: %s\n", gLoad.line); - return 1; -} - -void lua_handle_input (bool force) -{ - while (gLoad.L && (force || readline (&gLoad))) { - NODE_DBG("Handle Input: first=%u, pos=%u, len=%u, actual=%u, line=%s\n", gLoad.firstline, - gLoad.line_position, gLoad.len, strlen(gLoad.line), gLoad.line); - dojob (&gLoad); - force = false; - } -} - -void donejob(lua_Load *load){ - lua_close(load->L); -} + lua_settop(L, 0); -static void dojob(lua_Load *load){ - size_t l, rs; - int status; - char *b = load->line; - lua_State *L = load->L; - - const char *oldprogname = progname; - progname = NULL; - - do{ - if(load->done == 1){ - l = strlen(b); - if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ - b[l-1] = '\0'; /* remove it */ - if (load->firstline && b[0] == '=') /* first line starts with `=' ? */ - lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ - else - lua_pushstring(L, b); - if(load->firstline != 1){ - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } - - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); - if (!incomplete(L, status)) { /* cannot try to add lines? */ - lua_remove(L, 1); /* remove line */ - if (status == 0) { - status = docall(L, 0, 0); - } - report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(progname, lua_pushfstring(L, - "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); - } - load->firstline = 1; - load->prmt = get_prompt(L, 1); - lua_settop(L, 0); - /* force a complete garbage collection in case of errors */ - if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); - } else { - load->firstline = 0; - load->prmt = get_prompt(L, 0); - } - } - }while(0); + lua_pushliteral(L, "stdin"); + lua_pushlightfunction(L, &pipe_create); + lua_pushlightfunction(L, &dojob); + lua_pushinteger(L, LUA_TASK_LOW); + lua_call(L, 2, 1); /* ToS = pipe.create(dojob, low_priority) */ + lua_rawset(L, LUA_REGISTRYINDEX); /* and stash input pipe in Reg["stdin"] */ - progname = oldprogname; + input_setup(LUA_MAXINPUT, get_prompt(L, 1)); + lua_input_string(" \n", 2); /* queue CR to issue first prompt */ + print_version(L); - load->done = 0; - load->line_position = 0; - memset(load->line, 0, load->len); - puts(load->prmt); + /* and last of all, kick off application initialisation */ + if (init[0] == '@') + dofile(L, init+1); + else + dostring(L, init, LUA_INIT); + return 0; } -#ifndef uart_putc -#define uart_putc uart0_putc -#endif -extern bool uart_on_data_cb(const char *buf, size_t len); -extern bool uart0_echo; -extern bool run_input; -extern uint16_t need_len; -extern int16_t end_char; -static char last_nl_char = '\0'; -static bool readline(lua_Load *load){ - // NODE_DBG("readline() is called.\n"); - bool need_dojob = false; - char ch; - while (uart_getc(&ch)) - { - if(run_input) - { - char tmp_last_nl_char = last_nl_char; - // reset marker, will be finally set below when newline is processed - last_nl_char = '\0'; - - /* handle CR & LF characters - filters second char of LF&CR (\n\r) or CR&LF (\r\n) sequences */ - if ((ch == '\r' && tmp_last_nl_char == '\n') || // \n\r sequence -> skip \r - (ch == '\n' && tmp_last_nl_char == '\r')) // \r\n sequence -> skip \n - { - continue; - } - - /* backspace key */ - else if (ch == 0x7f || ch == 0x08) - { - if (load->line_position > 0) - { - if(uart0_echo) uart_putc(0x08); - if(uart0_echo) uart_putc(' '); - if(uart0_echo) uart_putc(0x08); - load->line_position--; - } - load->line[load->line_position] = 0; - continue; - } - /* EOT(ctrl+d) */ - // else if (ch == 0x04) - // { - // if (load->line_position == 0) - // // No input which makes lua interpreter close - // donejob(load); - // else - // continue; - // } - - /* end of line */ - if (ch == '\r' || ch == '\n') - { - last_nl_char = ch; - - load->line[load->line_position] = 0; - if(uart0_echo) uart_putc('\n'); - uart_on_data_cb(load->line, load->line_position); - if (load->line_position == 0) - { - /* Get a empty line, then go to get a new line */ - puts(load->prmt); - continue; - } else { - load->done = 1; - need_dojob = true; - break; - } - } - - /* other control character or not an acsii character */ - // if (ch < 0x20 || ch >= 0x80) - // { - // continue; - // } - - /* echo */ - if(uart0_echo) uart_putc(ch); - - /* it's a large line, discard it */ - if ( load->line_position + 1 >= load->len ){ - load->line_position = 0; - } - } - - load->line[load->line_position] = ch; - load->line_position++; - - if(!run_input) - { - if( ((need_len!=0) && (load->line_position >= need_len)) || \ - (load->line_position >= load->len) || \ - ((end_char>=0) && ((unsigned char)ch==(unsigned char)end_char)) ) - { - uart_on_data_cb(load->line, load->line_position); - load->line_position = 0; - } - } - - ch = 0; - } - - if( (load->line_position > 0) && (!run_input) && (need_len==0) && (end_char<0) ) - { - uart_on_data_cb(load->line, load->line_position); - load->line_position = 0; +/* +** The system initialisation CB nodemcu_init() calls lua_main() to startup +** the Lua environment by calling lua_open() which initiates the core Lua VM. +** The initialisation of the libraries, etc. is carried out by pmain in a +** separate Lua task, which also kicks off the user application through the +** LUA_INIT_STRING hook. +*/ +void lua_main (void) { + lua_State *L = lua_open(); /* create state */ + if (L == NULL) { + l_message("cannot create state: not enough memory"); + return; } + lua_pushlightfunction(L, &pmain); /* Call 'pmain' as a high priority task */ + luaN_posttask(L, LUA_TASK_HIGH); +} - return need_dojob; +/* +** The Lua interpreter is event-driven and task-oriented in NodeMCU rather than +** based on a readline poll loop as in the standard implementation. Input lines +** can come from one of two sources: the application can "push" lines for the +** interpreter to compile and execute, or they can come from the UART. To +** minimise application blocking, the lines are queued in a pipe when received, +** with the Lua interpreter task attached to the pipe as its reader task. This +** CB processes one line of input per task execution. +** +** Even though lines can be emitted from independent sources (the UART and the +** node API), and they could in theory get interleaved, the strategy here is +** "let the programmer beware": interactive input will normally only occur in +** development and injected input occur in telnet type applications. If there +** is a need for interlocks, then the application should handle this. +*/ +//static int n = 0; +void lua_input_string (const char *line, int len) { + lua_State *L = globalL; + lua_getfield(L, LUA_REGISTRYINDEX, "stdin"); + lua_rawgeti(L, -1, 1); /* get the pipe_write from stdin[1] */ + lua_insert(L, -2); /* stick above the pipe */ + lua_pushlstring(L, line, len); + +//const char*b = lua_tostring(L, -1); +//dbg_printf("Pushing (%u): %s", len, b); + lua_call(L, 2, 0); /* stdin:write(line) */ } diff --git a/app/lua/lua.h b/app/lua/lua.h index a4b5c4e219..874f0fc43c 100644 --- a/app/lua/lua.h +++ b/app/lua/lua.h @@ -273,9 +273,11 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_islightfunction(L,n) (lua_type(L, (n)) == LUA_TLIGHTFUNCTION) +#define lua_isanyfunction(L,n) (lua_isfunction(L,n) || lua_islightfunction(L,n)) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) #define lua_isrotable(L,n) (lua_type(L, (n)) == LUA_TROTABLE) -#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isanytable(L,n) (lua_istable(L,n) || lua_isrotable(L,n)) +#define lua_islightuserdata(L,n) (lua_type(L, (n) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) #define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) #define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) @@ -375,20 +377,19 @@ struct lua_Debug { /* }====================================================================== */ -typedef struct __lua_load{ - lua_State *L; - int firstline; - char *line; - int line_position; - size_t len; - int done; - const char *prmt; -}lua_Load; - -int lua_main( int argc, char **argv ); #ifndef LUA_CROSS_COMPILER -void lua_handle_input (bool force); +#define LUA_QUEUE_APP 0 +#define LUA_QUEUE_UART 1 +#define LUA_TASK_LOW 0 +#define LUA_TASK_MEDIUM 1 +#define LUA_TASK_HIGH 2 + +void lua_main (void); +void lua_input_string (const char *line, int len); +int luaN_posttask (lua_State* L, int prio); +int luaN_call (lua_State *L, int narg, int res, int dogc); +/**DEBUG**/extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); #endif /****************************************************************************** diff --git a/app/modules/gpio.c b/app/modules/gpio.c index 939d3d25f5..626ce18648 100644 --- a/app/modules/gpio.c +++ b/app/modules/gpio.c @@ -5,6 +5,7 @@ #include "lauxlib.h" #include "lmem.h" #include "platform.h" +#include "task/task.h" #include "user_interface.h" #include #include diff --git a/app/modules/gpio_pulse.c b/app/modules/gpio_pulse.c index 15909572f4..5032d4426e 100644 --- a/app/modules/gpio_pulse.c +++ b/app/modules/gpio_pulse.c @@ -45,7 +45,7 @@ typedef struct { static int active_pulser_ref; static pulse_t *active_pulser; -static task_handle_t tasknumber; +static platform_task_handle_t tasknumber; static int gpio_pulse_push_state(lua_State *L, pulse_t *pulser) { uint32_t now; @@ -321,7 +321,7 @@ static void ICACHE_RAM_ATTR gpio_pulse_timeout(os_param_t p) { active_pulser->steps++; } platform_hw_timer_close(TIMER_OWNER); - task_post_low(tasknumber, (task_param_t)0); + platform_post_low(tasknumber, 0); return; } active_pulser->steps++; @@ -341,7 +341,7 @@ static void ICACHE_RAM_ATTR gpio_pulse_timeout(os_param_t p) { int16_t stop = active_pulser->stop_pos; if (stop == -2 || stop == active_pulser->entry_pos) { platform_hw_timer_close(TIMER_OWNER); - task_post_low(tasknumber, (task_param_t)0); + platform_post_low(tasknumber, 0); return; } @@ -488,7 +488,7 @@ LROT_END( gpio_pulse, gpio_pulse, LROT_MASK_INDEX ) int gpio_pulse_init(lua_State *L) { luaL_rometatable(L, "gpio.pulse", LROT_TABLEREF(pulse)); - tasknumber = task_get_id(gpio_pulse_task); + tasknumber = platform_task_get_id(gpio_pulse_task); return 0; } diff --git a/app/modules/net.c b/app/modules/net.c index fdbd575d8d..51efae715b 100644 --- a/app/modules/net.c +++ b/app/modules/net.c @@ -736,6 +736,14 @@ int net_getaddr( lua_State *L ) { lua_pushstring(L, addr_str); return 2; } +#if 0 +static void dbg_print_ud(const char *title, lnet_userdata *ud) { + int i; + dbg_printf("%s: Userdata %p:", title, ud); + for (i=0; i<(sizeof(*ud)/sizeof(uint32_t)); i++) + dbg_printf( " 0x%08x", ((uint32_t *)ud)[i]); + dbg_printf("\n"); +#endif // Lua: client/server/socket:close() int net_close( lua_State *L ) { @@ -764,11 +772,14 @@ int net_close( lua_State *L ) { } if (ud->type == TYPE_TCP_SERVER || (ud->pcb == NULL && ud->client.wait_dns == 0)) { - lua_gc(L, LUA_GCSTOP, 0); +// lua_gc(L, LUA_GCSTOP, 0); luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); ud->self_ref = LUA_NOREF; - lua_gc(L, LUA_GCRESTART, 0); +// lua_gc(L, LUA_GCRESTART, 0); } +#if 0 + dbg_print_ud("close exit", ud); +#endif return 0; } @@ -813,10 +824,13 @@ int net_delete( lua_State *L ) { ud->server.cb_accept_ref = LUA_NOREF; break; } - lua_gc(L, LUA_GCSTOP, 0); +// lua_gc(L, LUA_GCSTOP, 0); luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); ud->self_ref = LUA_NOREF; - lua_gc(L, LUA_GCRESTART, 0); +// lua_gc(L, LUA_GCRESTART, 0); +#if 0 + dbg_print_ud("delete end", ud); +#endif return 0; } diff --git a/app/modules/node.c b/app/modules/node.c index a44f3fa43c..d3f59a4bcd 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -171,69 +171,59 @@ static int node_heap( lua_State* L ) return 1; } -extern int lua_put_line(const char *s, size_t l); -extern bool user_process_input(bool force); - // Lua: input("string") static int node_input( lua_State* L ) { - size_t l = 0; - const char *s = luaL_checklstring(L, 1, &l); - if (lua_put_line(s, l)) { - NODE_DBG("Result (if any):\n"); - user_process_input(true); - } + luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "stdin"); + lua_rawgeti(L, -1, 1); /* get the pipe_write func from stdin[1] */ + lua_insert(L, -2); /* and move above the pipe ref */ + lua_pushvalue(L, 1); + lua_call(L, 2, 0); /* stdin:write(line) */ return 0; } -static int output_redir_ref = LUA_NOREF; static int serial_debug = 1; + void output_redirect(const char *str) { lua_State *L = lua_getstate(); - // if(strlen(str)>=TX_BUFF_SIZE){ - // NODE_ERR("output too long.\n"); - // return; - // } - - if (output_redir_ref == LUA_NOREF) { - uart0_sendStr(str); - return; - } + int n = lua_gettop(L); + lua_pushliteral(L, "stdout"); + lua_rawget(L, LUA_REGISTRYINDEX); /* fetch reg.stdout */ + if (lua_istable(L, -1)) { /* reg.stdout is pipe */ + if (serial_debug) { + uart0_sendStr(str); + } + lua_rawgeti(L, -1, 1); /* get the pipe_write func from stdout[1] */ + lua_insert(L, -2); /* and move above the pipe ref */ + lua_pushstring(L, str); + lua_call(L, 2, 0); /* Reg.stdout:write(str) */ - if (serial_debug != 0) { + } else { /* reg.stdout == nil */ uart0_sendStr(str); } - - lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir_ref); - lua_pushstring(L, str); - lua_call(L, 1, 0); // this call back function should never user output. + lua_settop(L, n); /* Make sure all code paths leave stack unchanged */ } +extern int pipe_create(lua_State *L); + // Lua: output(function(c), debug) static int node_output( lua_State* L ) { - // luaL_checkanyfunction(L, 1); - if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION) { - lua_pushvalue(L, 1); // copy argument (func) to the top of stack - if (output_redir_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref); - output_redir_ref = luaL_ref(L, LUA_REGISTRYINDEX); - } else { // unref the key press function - if (output_redir_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref); - output_redir_ref = LUA_NOREF; + serial_debug = (lua_isnumber(L, 2) && lua_tointeger(L, 2) == 0) ? 0 : 1; + lua_settop(L, 1); + if (lua_isanyfunction(L, 1)) { + lua_pushlightfunction(L, &pipe_create); + lua_insert(L, 1); + lua_pushinteger(L, LUA_TASK_MEDIUM); + lua_call(L, 2, 1); /* T[1] = pipe.create(dojob, low_priority) */ + } else { // remove the stdout pipe + lua_pop(L,1); + lua_pushnil(L); /* T[1] = nil */ serial_debug = 1; - return 0; - } - - if ( lua_isnumber(L, 2) ) - { - serial_debug = lua_tointeger(L, 2); - if (serial_debug != 0) - serial_debug = 1; - } else { - serial_debug = 1; // default to 1 } - + lua_pushliteral(L, "stdout"); + lua_insert(L, 1); + lua_rawset(L, LUA_REGISTRYINDEX); /* Reg.stdout = nil or pipe */ return 0; } @@ -274,7 +264,7 @@ static int node_compile( lua_State* L ) output[strlen(output) - 1] = '\0'; NODE_DBG(output); NODE_DBG("\n"); - if (luaL_loadfsfile(L, fname) != 0) { + if (luaL_loadfile(L, fname) != 0) { luaM_free( L, output ); return luaL_error(L, lua_tostring(L, -1)); } @@ -315,39 +305,19 @@ static int node_compile( lua_State* L ) return 0; } -// Task callback handler for node.task.post() -static task_handle_t do_node_task_handle; -static void do_node_task (task_param_t task_fn_ref, uint8_t prio) -{ - lua_State* L = lua_getstate(); - lua_rawgeti(L, LUA_REGISTRYINDEX, (int)task_fn_ref); - luaL_unref(L, LUA_REGISTRYINDEX, (int)task_fn_ref); - lua_pushinteger(L, prio); - lua_call(L, 1, 0); -} - // Lua: node.task.post([priority],task_cb) -- schedule a task for execution next static int node_task_post( lua_State* L ) { - int n = 1, Ltype = lua_type(L, 1); + int n=1; unsigned priority = TASK_PRIORITY_MEDIUM; - if (Ltype == LUA_TNUMBER) { + if (lua_type(L, 1) == LUA_TNUMBER) { priority = (unsigned) luaL_checkint(L, 1); luaL_argcheck(L, priority <= TASK_PRIORITY_HIGH, 1, "invalid priority"); - Ltype = lua_type(L, ++n); - } - luaL_argcheck(L, Ltype == LUA_TFUNCTION || Ltype == LUA_TLIGHTFUNCTION, n, "invalid function"); - lua_pushvalue(L, n); - - int task_fn_ref = luaL_ref(L, LUA_REGISTRYINDEX); - - if (!do_node_task_handle) // bind the task handle to do_node_task on 1st call - do_node_task_handle = task_get_id(do_node_task); - - if(!task_post(priority, do_node_task_handle, (task_param_t)task_fn_ref)) { - luaL_unref(L, LUA_REGISTRYINDEX, task_fn_ref); - luaL_error(L, "Task queue overflow. Task not posted"); + n++; } + luaL_checkanyfunction(L, n); + lua_settop(L, n); + (void) luaN_posttask(L, priority); return 0; } diff --git a/app/modules/pipe.c b/app/modules/pipe.c index 7e300eaf01..322c3603d9 100644 --- a/app/modules/pipe.c +++ b/app/modules/pipe.c @@ -3,15 +3,45 @@ ** table to store the LUAL_BUFFERSIZE byte array chunks instead of the stack. ** Writing is always to the last UD in the table and overflow pushes a new UD to ** the end of the table. Reading is always from the first UD in the table and -** underrun removes the first UD to shift a new one into slot 1. +** underrun removes the first UD to shift a new one into slot 2. (Slot 1 of the +** table is reserved for the pipe reader function with 0 denoting no reader.) ** ** Reads and writes may span multiple UD buffers and if the read spans multiple UDs ** then the parts are collected as strings on the Lua stack and then concatenated -** with a `lua_concat()`. +** with a lua_concat(). ** -** Note that pipes also support the undocumented length and tostring operators -** for debugging puposes, so if p is a pipe then #p[1] gives the effective -** length of pipe slot 1 and printing p[1] gives its contents +** Note that pipe tables also support the undocumented length and tostring +** operators for debugging puposes, so if p is a pipe then #p[i] gives the +** effective length of pipe slot i and printing p[i] gives its contents. +** +** The pipe library also supports the automatic scheduling of a reader task. This +** is declared by including a Lua CB function and an optional prioirty for it to +** execute at in the pipe.create() call. The reader task may or may not empty the +** FIFO (and there is also nothing to stop the task also writing to the FIFO. The +** reader automatically reschedules itself if the pipe contains unread content. +** +** The reader tasks may be interleaved with other tasks that write to the pipe and +** others that don't. Any task writing to the pipe will also trigger the posting +** of a read task if one is not already pending. In this way at most only one +** pending reader task is pending, and this prevents overrun of the task queueing +** system. +** +** Implementation Notes: +** +** - The Pipe slot 1 is used to store the Lua CB function reference of the reader +** task. Note that is actually an auxiliary wrapper around the supplied Lua CB +** function, and this wrapper also uses upvals to store internal pipe state. +** The remaining slots are the Userdata buffer chunks. +** +** - This internal state needs to be shared with the pipe_write function, but a +** limitation of Lua 5.1 is that C functions cannot share upvals; to avoid this +** constraint, this function is also denormalised to act as the pipe_write +** function: if Arg1 is the pipe then its a pipe:write() otherwise its a +** CB wrapper. +** +** Also note that the pipe module is used by the Lua VM and therefore the create +** read, and unread methods are exposed as directly callable C functions. (Write +** is available throogh pipe[1].) ** ** Read the docs/modules/pipe.md documentation for a functional description. */ @@ -19,6 +49,8 @@ #include "module.h" #include "lauxlib.h" #include +#include "platform.h" +#include "lstate.h" #define INVALID_LEN ((unsigned)-1) @@ -31,10 +63,36 @@ typedef struct buffer { LROT_TABLE(pipe_meta) -/* Validation and utility functions */ +#define AT_TAIL 0x00 +#define AT_HEAD 0x01 +#define WRITING 0x02 + +static buffer_t *checkPipeUD (lua_State *L, int ndx); +static buffer_t *newPipeUD(lua_State *L, int ndx, int n); +static int pipe_write_aux(lua_State *L); -#define AT_HEAD 1 -#define AT_TAIL 0 +/* Validation and utility functions */ + // [-0, +0, v] +static buffer_t *checkPipeTable (lua_State *L, int tbl, int flags) { + int m = lua_gettop(L), n = lua_objlen(L, tbl); + if (lua_istable(L, tbl) && lua_getmetatable(L, tbl)) { + lua_pushrotable(L, LROT_TABLEREF(pipe_meta));/* push comparison metatable */ + if (lua_rawequal(L, -1, -2)) { /* check these match */ + buffer_t *ud; + if (n == 1) { + ud = (flags & WRITING) ? newPipeUD(L, tbl, 2) : NULL; + } else { + int i = flags & AT_HEAD ? 2 : n; /* point to head or tail of T */ + lua_rawgeti(L, tbl, i); /* and fetch UD */ + ud = checkPipeUD(L, -1); + } + lua_settop(L, m); + return ud; /* and return ptr to buffer_t rec */ + } + } + luaL_typerror(L, tbl, "pipe table"); + return NULL; /* NORETURN avoid compiler error */ +} static buffer_t *checkPipeUD (lua_State *L, int ndx) { // [-0, +0, v] buffer_t *ud = lua_touserdata(L, ndx); @@ -59,27 +117,6 @@ static buffer_t *newPipeUD(lua_State *L, int ndx, int n) { // [-0,+0,-] return ud; /* ud points to new T[#T] */ } -static buffer_t *checkPipeTable (lua_State *L, int tbl, int head) {//[-0, +0, v] - int m = lua_gettop(L), n = lua_objlen(L, tbl); - if (lua_type(L, tbl) == LUA_TTABLE && lua_getmetatable(L, tbl)) { - lua_pushrotable(L, LROT_TABLEREF(pipe_meta));/* push comparison metatable */ - if (lua_rawequal(L, -1, -2)) { /* check these match */ - buffer_t *ud; - if (n == 0) { - ud = head ? NULL : newPipeUD(L, tbl, 1); - } else { - int i = head ? 1 : n; /* point to head or tail of T */ - lua_rawgeti(L, tbl, i); /* and fetch UD */ - ud = checkPipeUD(L, -1); - } - lua_settop(L, m); - return ud; /* and return ptr to buffer_t rec */ - } - } - luaL_typerror(L, tbl, "pipe table"); - return NULL; /* NORETURN avoid compiler error */ -} - #define CHAR_DELIM -1 #define CHAR_DELIM_KEEP -2 static char getsize_delim (lua_State *L, int ndx, int *len) { // [-0, +0, v] @@ -104,22 +141,115 @@ static char getsize_delim (lua_State *L, int ndx, int *len) { // [-0, +0, v] return delim; } -/* Lua callable methods */ +/* +** Read CB Initiator AND pipe_write. If arg1 == the pipe, then this is a pipe +** write(); otherwise it is the Lua CB wapper for the task post. This botch allows +** these two functions to share Upvals within the Lua 5.1 VM: +*/ +#define UVpipe lua_upvalueindex(1) // The pipe table object +#define UVfunc lua_upvalueindex(2) // The CB's Lua function +#define UVprio lua_upvalueindex(3) // The task priority +#define UVstate lua_upvalueindex(4) // Pipe state; +#define CB_NOT_USED 0 +#define CB_ACTIVE 1 +#define CB_WRITE_UPDATED 2 +#define CB_QUIESCENT 4 +/* +** Note that nothing precludes the Lua CB function from itself writing to the +** pipe and in this case this routine will call itself recursively. +** +** The Lua CB itself takes the pipe object as a parameter and returns an optional +** boolean to force or to suppress automatic retasking if needed. If omitted, +** then the default is to repost if the pipe is not empty, otherwise the task +** chain is left to lapse. +*/ +static int pipe_write_and_read_poster (lua_State *L) { + int state = lua_tointeger(L, UVstate); + if (lua_rawequal(L, 1, UVpipe)) { + /* arg1 == the pipe, so this was invoked as a pipe_write() */ + if (pipe_write_aux(L) && state && !(state & CB_WRITE_UPDATED)) { + /* + * if this resulted in a write and not already in a CB and not already + * toggled the write update then post the task + */ + state |= CB_WRITE_UPDATED; + lua_pushinteger(L, state); + lua_replace(L, UVstate); /* Set CB state write updated flag */ + if (state == CB_QUIESCENT | CB_WRITE_UPDATED) { + lua_rawgeti(L, 1, 1); /* Get CB ref from pipe[1] */ + luaN_posttask(L, (int) lua_tointeger(L, UVprio)); /* and repost task */ + } + } -//Lua s = pipeUD:tostring() -static int pipe__tostring (lua_State *L) { - if (lua_type(L, 1) == LUA_TTABLE) { - lua_pushfstring(L, "Pipe: %p", lua_topointer(L, 1)); - } else { - buffer_t *ud = checkPipeUD(L, 1); - lua_pushlstring(L, ud->buf + ud->start, ud->end - ud->start); + } else if (state != CB_NOT_USED) { + /* invoked by the luaN_taskpost() so call the Lua CB */ + int repost; /* can take the values CB_WRITE_UPDATED or 0 */ + lua_pushinteger(L, CB_ACTIVE); /* CB state set to active only */ + lua_replace(L, UVstate); + lua_pushvalue(L, UVfunc); /* Lua CB function */ + lua_pushvalue(L, UVpipe); /* pipe table */ + lua_call(L, 1, 1); + /* + * On return from the Lua CB, the task is never reposted if the pipe is empty. + * If it is not empty then the Lua CB return status determines when reposting + * occurs: + * - true = repost + * - false = don't repost + * - nil = only repost if there has been a write update. + */ + if (lua_isboolean(L,-1)) { + repost = (lua_toboolean(L, -1) == true && + lua_objlen(L, UVpipe) > 1) ? CB_WRITE_UPDATED : 0; + } else { + repost = state & CB_WRITE_UPDATED; + } + state = CB_QUIESCENT | repost; + lua_pushinteger(L, state); /* Update the CB state */ + lua_replace(L, UVstate); + + if (repost) { + lua_rawgeti(L, UVpipe, 1); /* Get CB ref from pipe[1] */ + luaN_posttask(L, (int) lua_tointeger(L, UVprio)); /* and repost task */ + } } - return 1; + return 0; +} + +/* Lua callable methods. Since the metatable is linked to both the pipe table */ +/* and the userdata entries the __len & __tostring functions must handle both */ + +// Lua: buf = pipe.create() +int pipe_create(lua_State *L) { + int prio = -1; + lua_settop(L, 2); /* fix stack sze as 2 */ + + if (!lua_isnil(L, 1)) { + luaL_checkanyfunction(L, 1); /* non-nil arg1 must be a function */ + if (lua_isnil(L, 2)) { + prio = PLATFORM_TASK_PRIORITY_MEDIUM; + } else { + prio = (int) lua_tointeger(L, 2); + luaL_argcheck(L, prio >= PLATFORM_TASK_PRIORITY_LOW && + prio <= PLATFORM_TASK_PRIORITY_HIGH, 2, "invalid priority"); + } + } + + lua_createtable (L, 1, 0); /* create pipe table */ + lua_pushrotable(L, LROT_TABLEREF(pipe_meta)); + lua_setmetatable(L, -2); /* set pipe table's metabtable to pipe_meta */ + + lua_pushvalue(L, -1); /* UV1: pipe object */ + lua_pushvalue(L, 1); /* UV2: CB function */ + lua_pushinteger(L, prio); /* UV3: task priority */ + lua_pushinteger(L, prio == -1 ? CB_NOT_USED : CB_QUIESCENT); + lua_pushcclosure(L, pipe_write_and_read_poster, 4); /* post aux func as C task */ + lua_rawseti(L, -2, 1); /* and wrtie to T[1] */ + return 1; /* return the table */ } -// len = #pipeobj[1] +// len = #pipeobj[i] static int pipe__len (lua_State *L) { - if (lua_type(L, 1) == LUA_TTABLE) { + if (lua_type(L, 1) == LUA_TTABLE) { lua_pushinteger(L, lua_objlen(L, 1)); } else { buffer_t *ud = checkPipeUD(L, 1); @@ -128,16 +258,19 @@ static int pipe__len (lua_State *L) { return 1; } -// Lua: buf = pipe.create() -static int pipe_create(lua_State *L) { - lua_createtable (L, 1, 0); - lua_pushrotable(L, LROT_TABLEREF(pipe_meta)); - lua_setmetatable(L, 1); /* set table's metabtable to pipe_meta */ - return 1; /* return the table */ +//Lua s = pipeUD:tostring() +static int pipe__tostring (lua_State *L) { + if (lua_istable(L, 1)) { + lua_pushfstring(L, "Pipe: %p", lua_topointer(L, 1)); + } else { + buffer_t *ud = checkPipeUD(L, 1); + lua_pushlstring(L, ud->buf + ud->start, ud->end - ud->start); + } + return 1; } // Lua: rec = p:read(end_or_delim) // also [-2, +1,- ] -static int pipe_read(lua_State *L) { +int pipe_read(lua_State *L) { buffer_t *ud = checkPipeTable(L, 1, AT_HEAD); int i, k=0, n; lua_settop(L,2); @@ -158,6 +291,7 @@ static int pipe_read(lua_State *L) { want = used = i + 1 - ud->start; /* case where we've hit a delim */ if (n == CHAR_DELIM) want--; + n = 0; /* force loop exit because delim found */ } } else { want = used = (n < avail) ? n : avail; @@ -169,12 +303,12 @@ static int pipe_read(lua_State *L) { if (ud->start == ud->end) { /* shift the pipe array down overwriting T[1] */ int nUD = lua_objlen(L, 1); - for (i = 1; i < nUD; i++) { /* for i = 1, nUD-1 */ + for (i = 2; i < nUD; i++) { /* for i = 2, nUD-1 */ lua_rawgeti(L, 1, i+1); lua_rawseti(L, 1, i); /* T[i] = T[i+1] */ } lua_pushnil(L); lua_rawseti(L, 1, nUD--); /* T[n] = nil */ - if (nUD) { - lua_rawgeti(L, 1, 1); + if (nUD>1) { + lua_rawgeti(L, 1, 2); ud = checkPipeUD(L, -1); lua_pop(L, 1); } else { @@ -190,29 +324,33 @@ static int pipe_read(lua_State *L) { } // Lua: buf:unread(some_string) -static int pipe_unread(lua_State *L) { +int pipe_unread(lua_State *L) { size_t l = INVALID_LEN; const char *s = lua_tolstring(L, 2, &l); if (l==0) return 0; luaL_argcheck(L, l != INVALID_LEN, 2, "must be a string"); - buffer_t *ud = checkPipeTable(L, 1, AT_HEAD); + buffer_t *ud = checkPipeTable(L, 1, AT_HEAD | WRITING); do { - int used = ud->end - ud->start, lrem = LUAL_BUFFERSIZE-used; + int used = ud->end - ud->start; + int lrem = LUAL_BUFFERSIZE-used; if (used == LUAL_BUFFERSIZE) { + /* If the current UD is full insert a new UD at T[2] */ int i, nUD = lua_objlen(L, 1); for (i = nUD; i > 0; i--) { /* for i = nUD-1,1,-1 */ lua_rawgeti(L, 1, i); lua_rawseti(L, 1, i+1); /* T[i+1] = T[i] */ } ud = newPipeUD(L, 1, 1); used = 0; lrem = LUAL_BUFFERSIZE; - } else if (ud->end < LUAL_BUFFERSIZE) { + + } else if (ud->start < l) { + /* If the unread can't fit it before the start then shift content to end */ memmove(ud->buf + lrem, ud->buf + ud->start, used); /* must be memmove not cpy */ + ud->start = lrem; ud->end = LUAL_BUFFERSIZE; } - ud->start = lrem; ud->end = LUAL_BUFFERSIZE; if (l <= (unsigned )lrem) break; @@ -232,21 +370,24 @@ static int pipe_unread(lua_State *L) { } // Lua: buf:write(some_string) -static int pipe_write(lua_State *L) { +static int pipe_write_aux(lua_State *L) { size_t l = INVALID_LEN; const char *s = lua_tolstring(L, 2, &l); +//dbg_printf("pipe write(%u): %s", l, s); if (l==0) - return 0; + return false; luaL_argcheck(L, l != INVALID_LEN, 2, "must be a string"); - buffer_t *ud = checkPipeTable(L, 1, AT_TAIL); + buffer_t *ud = checkPipeTable(L, 1, AT_TAIL | WRITING); do { int used = ud->end - ud->start; if (used == LUAL_BUFFERSIZE) { + /* If the current UD is full insert a new UD at T[end] */ ud = newPipeUD(L, 1, lua_objlen(L, 1)+1); used = 0; - } else if (ud->start) { + } else if (LUAL_BUFFERSIZE - ud->end < l) { + /* If the write can't fit it at the end then shift content to the start */ memmove(ud->buf, ud->buf + ud->start, used); /* must be memmove not cpy */ ud->start = 0; ud->end = used; } @@ -267,7 +408,7 @@ static int pipe_write(lua_State *L) { /* Copy any residual tail to the UD buffer. Note that this is l>0 and */ memcpy(ud->buf + ud->end, s, l); ud->end += l; - return 0; + return true; } // Lua: fread = pobj:reader(1400) -- or other number @@ -289,21 +430,36 @@ static int pipe_reader(lua_State *L) { return 1; } - -LROT_BEGIN(pipe_meta) - LROT_TABENTRY( __index, pipe_meta) +LROT_BEGIN(pipe_funcs) LROT_FUNCENTRY( __len, pipe__len ) LROT_FUNCENTRY( __tostring, pipe__tostring ) LROT_FUNCENTRY( read, pipe_read ) LROT_FUNCENTRY( reader, pipe_reader ) LROT_FUNCENTRY( unread, pipe_unread ) - LROT_FUNCENTRY( write, pipe_write ) LROT_END( pipe_meta, NULL, LROT_MASK_INDEX ) +/* Using a index func is needed because the write method is at pipe[1] */ +static int pipe__index(lua_State *L) { + lua_settop(L,2); + const char *k=lua_tostring(L,2); + if(!strcmp(k,"write")){ + lua_rawgeti(L, 1, 1); + } else { + lua_pushrotable(L, LROT_TABLEREF(pipe_funcs)); + lua_replace(L, 1); + lua_rawget(L, 1); + } + return 1; +} + +LROT_BEGIN(pipe_meta) + LROT_FUNCENTRY( __index, pipe__index) + LROT_FUNCENTRY( __len, pipe__len ) + LROT_FUNCENTRY( __tostring, pipe__tostring ) +LROT_END( pipe_meta, NULL, LROT_MASK_INDEX ) LROT_BEGIN(pipe) LROT_FUNCENTRY( create, pipe_create ) LROT_END( lb, NULL, 0 ) - NODEMCU_MODULE(PIPE, "pipe", pipe, NULL); diff --git a/app/modules/somfy.c b/app/modules/somfy.c index 79abf50ef2..7ba0cd04b5 100644 --- a/app/modules/somfy.c +++ b/app/modules/somfy.c @@ -20,6 +20,7 @@ #include "lauxlib.h" #include "lmem.h" #include "platform.h" +#include "task/task.h" #include "hw_timer.h" #include "user_interface.h" diff --git a/app/modules/uart.c b/app/modules/uart.c index 5dcba1c4b0..a849095d7e 100644 --- a/app/modules/uart.c +++ b/app/modules/uart.c @@ -7,83 +7,57 @@ #include #include #include "rom.h" +#include "driver/input.h" static int uart_receive_rf = LUA_NOREF; -bool run_input = true; -bool uart_on_data_cb(const char *buf, size_t len){ - if(!buf || len==0) - return false; - if(uart_receive_rf == LUA_NOREF) - return false; + +void uart_on_data_cb(const char *buf, size_t len){ lua_State *L = lua_getstate(); - if(!L) - return false; lua_rawgeti(L, LUA_REGISTRYINDEX, uart_receive_rf); lua_pushlstring(L, buf, len); - lua_call(L, 1, 0); - return !run_input; + luaN_call(L, 1, 0, 0); } -uint16_t need_len = 0; -int16_t end_char = -1; // Lua: uart.on("method", [number/char], function, [run_input]) static int l_uart_on( lua_State* L ) { - size_t sl, el; - int32_t run = 1; - uint8_t stack = 1; - const char *method = luaL_checklstring( L, stack, &sl ); - stack++; - if (method == NULL) - return luaL_error( L, "wrong arg type" ); - - if( lua_type( L, stack ) == LUA_TNUMBER ) + size_t el; + int stack = 2, data_len = -1; + char end_char = 0; + const char *method = lua_tostring( L, 1); + bool run_input = true; + luaL_argcheck(L, method && !strcmp(method, "data"), 1, "method not supported"); + + if (lua_type( L, stack ) == LUA_TNUMBER) { - need_len = ( uint16_t )luaL_checkinteger( L, stack ); + data_len = luaL_checkinteger( L, stack ); + luaL_argcheck(L, data_len >= 0 && data_len <= LUA_MAXINPUT, stack, "wrong arg range"); stack++; - end_char = -1; - if( need_len > 255 ){ - need_len = 255; - return luaL_error( L, "wrong arg range" ); - } } - else if(lua_isstring(L, stack)) + else if (lua_isstring(L, stack)) { const char *end = luaL_checklstring( L, stack, &el ); + data_len = 0; + end_char = (int16_t) end[0]; stack++; - if(el!=1){ + if(el!=1) { return luaL_error( L, "wrong arg range" ); } - end_char = (int16_t)end[0]; - need_len = 0; } - // luaL_checkanyfunction(L, stack); - if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ - if ( lua_isnumber(L, stack+1) ){ - run = lua_tointeger(L, stack+1); + if (lua_anyfunction(L, stack)) { + if (lua_isnumber(L, stack+1) && lua_tointeger(L, stack+1) == 0) { + run_input = false; } - lua_pushvalue(L, stack); // copy argument (func) to the top of stack + lua_pushvalue(L, stack); + luaL_unref(L, LUA_REGISTRYINDEX, uart_receive_rf); + uart_receive_rf = luaL_ref(L, LUA_REGISTRYINDEX); + } else { - lua_pushnil(L); - } - if(sl == 4 && strcmp(method, "data") == 0){ - run_input = true; - if(uart_receive_rf != LUA_NOREF){ - luaL_unref(L, LUA_REGISTRYINDEX, uart_receive_rf); - uart_receive_rf = LUA_NOREF; - } - if(!lua_isnil(L, -1)){ - uart_receive_rf = luaL_ref(L, LUA_REGISTRYINDEX); - if(run==0) - run_input = false; - } else { - lua_pop(L, 1); - } - }else{ - lua_pop(L, 1); - return luaL_error( L, "method not supported" ); + luaL_unref(L, LUA_REGISTRYINDEX, uart_receive_rf); + uart_receive_rf = LUA_NOREF; } + input_setup_receive(uart_on_data_cb, data_len, end_char, run_input); return 0; } @@ -91,7 +65,7 @@ bool uart0_echo = true; // Lua: actualbaud = setup( id, baud, databits, parity, stopbits, echo ) static int l_uart_setup( lua_State* L ) { - uint32_t id, databits, parity, stopbits, echo = 1; + uint32_t id, databits, parity, stopbits; uint32_t baud, res; id = luaL_checkinteger( L, 1 ); @@ -101,12 +75,8 @@ static int l_uart_setup( lua_State* L ) databits = luaL_checkinteger( L, 3 ); parity = luaL_checkinteger( L, 4 ); stopbits = luaL_checkinteger( L, 5 ); - if(lua_isnumber(L,6)){ - echo = lua_tointeger(L,6); - if(echo!=0) - uart0_echo = true; - else - uart0_echo = false; + if (lua_isnumber(L,6)) { + input_setecho(lua_tointeger(L,6) ? true : false); } res = platform_uart_setup( id, baud, databits, parity, stopbits ); diff --git a/app/platform/platform.c b/app/platform/platform.c index a343652cbd..ad7c2c26be 100644 --- a/app/platform/platform.c +++ b/app/platform/platform.c @@ -17,7 +17,8 @@ #define INTERRUPT_TYPE_IS_LEVEL(x) ((x) >= GPIO_PIN_INTR_LOLEVEL) #ifdef GPIO_INTERRUPT_ENABLE -static task_handle_t gpio_task_handle; +static platform_task_handle_t gpio_task_handle; +static int task_init_handler(void); #ifdef GPIO_INTERRUPT_HOOK_ENABLE struct gpio_hook_entry { @@ -55,11 +56,13 @@ static const int uart_bitrates[] = { BIT_RATE_3686400 }; -int platform_init() +int platform_init () { // Setup the various forward and reverse mappings for the pins get_pin_map(); + (void) task_init_handler(); + cmn_platform_init(); // All done return PLATFORM_OK; @@ -83,7 +86,7 @@ uint8_t platform_key_led( uint8_t level){ /* * Set GPIO mode to output. Optionally in RAM helper because interrupts are dsabled */ -static void NO_INTR_CODE set_gpio_no_interrupt(uint8 pin, uint8_t push_pull) { +static void NO_INTR_CODE set_gpio_no_interrupt(uint8_t pin, uint8_t push_pull) { unsigned pnum = pin_num[pin]; ETS_GPIO_INTR_DISABLE(); #ifdef GPIO_INTERRUPT_ENABLE @@ -113,7 +116,7 @@ static void NO_INTR_CODE set_gpio_no_interrupt(uint8 pin, uint8_t push_pull) { * Set GPIO mode to interrupt. Optionally RAM helper because interrupts are dsabled */ #ifdef GPIO_INTERRUPT_ENABLE -static void NO_INTR_CODE set_gpio_interrupt(uint8 pin) { +static void NO_INTR_CODE set_gpio_interrupt(uint8_t pin) { ETS_GPIO_INTR_DISABLE(); PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]); GPIO_DIS_OUTPUT(pin_num[pin]); @@ -209,9 +212,9 @@ int platform_gpio_read( unsigned pin ) #ifdef GPIO_INTERRUPT_ENABLE static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){ - uint32 j=0; - uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); - uint32 now = system_get_time(); + uint32_t j=0; + uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + uint32_t now = system_get_time(); UNUSED(dummy); #ifdef GPIO_INTERRUPT_HOOK_ENABLE @@ -244,8 +247,8 @@ static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){ GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(j)); if (diff == 0 || diff & 0x8000) { - uint32 level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(j)); - if (!task_post_high (gpio_task_handle, (now << 8) + (i<<1) + level)) { + uint32_t level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(j)); + if (!platform_post_high (gpio_task_handle, (now << 8) + (i<<1) + level)) { // If we fail to post, then try on the next interrupt pin_counter[i].seen |= 0x8000; } @@ -260,7 +263,7 @@ static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){ } } -void platform_gpio_init( task_handle_t gpio_task ) +void platform_gpio_init( platform_task_handle_t gpio_task ) { gpio_task_handle = gpio_task; @@ -871,7 +874,7 @@ uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t siz memcpy(apbuf, from, size); } system_soft_wdt_feed (); - r = flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size); + r = flash_write(toaddr, apbuf?(uint32_t *)apbuf:(uint32_t *)from, size); if(apbuf) free(apbuf); if(SPI_FLASH_RESULT_OK == r) @@ -899,7 +902,7 @@ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size ) if( ((uint32_t)to) & blkmask ) { uint32_t size2=size-INTERNAL_FLASH_READ_UNIT_SIZE; - uint32* to2=(uint32*)((((uint32_t)to)&(~blkmask))+INTERNAL_FLASH_READ_UNIT_SIZE); + uint32_t* to2=(uint32_t*)((((uint32_t)to)&(~blkmask))+INTERNAL_FLASH_READ_UNIT_SIZE); r = flash_read(fromaddr, to2, size2); if(SPI_FLASH_RESULT_OK == r) { @@ -910,7 +913,7 @@ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size ) } } else - r = flash_read(fromaddr, (uint32 *)to, size); + r = flash_read(fromaddr, (uint32_t *)to, size); if(SPI_FLASH_RESULT_OK == r) return size; @@ -1079,3 +1082,84 @@ void* platform_print_deprecation_note( const char *msg, const char *time_frame) { printf( "Warning, deprecated API! %s. It will be removed %s. See documentation for details.\n", msg, time_frame ); } + +#define TH_MONIKER 0x68680000 +#define TH_MASK 0xFFF80000 +#define TH_UNMASK (~TH_MASK) +#define TH_SHIFT 2 +#define TH_ALLOCATION_BRICK 4 // must be a power of 2 +#define TASK_DEFAULT_QUEUE_LEN 8 +#define TASK_PRIORITY_MASK 3 +#define TASK_PRIORITY_COUNT 3 + +/* + * Private struct to hold the 3 event task queues and the dispatch callbacks + */ +static struct taskQblock { + os_event_t *task_Q[TASK_PRIORITY_COUNT]; + platform_task_callback_t *task_func; + int task_count; + } TQB = {0}; + +static void platform_task_dispatch (os_event_t *e) { + platform_task_handle_t handle = e->sig; + if ( (handle & TH_MASK) == TH_MONIKER) { + uint16_t entry = (handle & TH_UNMASK) >> TH_SHIFT; + uint8_t priority = handle & TASK_PRIORITY_MASK; + if ( priority <= PLATFORM_TASK_PRIORITY_HIGH && + TQB.task_func && + entry < TQB.task_count ){ + /* call the registered task handler with the specified parameter and priority */ + TQB.task_func[entry](e->par, priority); + return; + } + } + /* Invalid signals are ignored */ + NODE_DBG ( "Invalid signal issued: %08x", handle); +} + +/* + * Initialise the task handle callback for a given priority. + */ +static int task_init_handler (void) { + int p, qlen = TASK_DEFAULT_QUEUE_LEN; + for (p = 0; p < TASK_PRIORITY_COUNT; p++){ + TQB.task_Q[p] = (os_event_t *) c_malloc( sizeof(os_event_t)*qlen ); + if (TQB.task_Q[p]) { + os_memset(TQB.task_Q[p], 0, sizeof(os_event_t)*qlen); + system_os_task(platform_task_dispatch, p, TQB.task_Q[p], TASK_DEFAULT_QUEUE_LEN); + } else { + NODE_DBG ( "Malloc failure in platform_task_init_handler" ); + return PLATFORM_ERR; + } + } +} + + +/* + * Allocate a task handle in the relevant TCB.task_Q. Note that these Qs are resized + * as needed growing in 4 unit bricks. No GC is adopted so handles are permanently + * allocated during boot life. This isn't an issue in practice as only a few handles + * are created per priority during application init and the more volitile Lua tasks + * are allocated in the Lua registery using the luaX interface which is layered on + * this mechanism. + */ +platform_task_handle_t platform_task_get_id (platform_task_callback_t t) { + if ( (TQB.task_count & (TH_ALLOCATION_BRICK - 1)) == 0 ) { + TQB.task_func = (platform_task_callback_t *) os_realloc( + TQB.task_func, + sizeof(platform_task_callback_t) * (TQB.task_count+TH_ALLOCATION_BRICK)); + if (!TQB.task_func) { + NODE_DBG ( "Malloc failure in platform_task_get_id"); + return 0; + } + os_memset (TQB.task_func+TQB.task_count, 0, + sizeof(platform_task_callback_t)*TH_ALLOCATION_BRICK); + } + TQB.task_func[TQB.task_count++] = t; + return TH_MONIKER + ((TQB.task_count-1) << TH_SHIFT); +} + +bool platform_post (uint8 prio, platform_task_handle_t handle, platform_task_param_t par) { + return system_os_post(prio, handle | prio, par); +} diff --git a/app/platform/platform.h b/app/platform/platform.h index 3a41ddfc85..68c6811f5f 100644 --- a/app/platform/platform.h +++ b/app/platform/platform.h @@ -8,8 +8,6 @@ #include "driver/pwm.h" #include "driver/uart.h" -#include "task/task.h" - // Error / status codes enum { @@ -18,6 +16,9 @@ enum PLATFORM_UNDERFLOW = -1 }; +typedef uint32_t platform_task_handle_t; +typedef uint32_t platform_task_param_t; + // Platform initialization int platform_init(void); void platform_int_init(void); @@ -52,7 +53,7 @@ int platform_gpio_register_intr_hook(uint32_t gpio_bits, platform_hook_function #define platform_gpio_unregister_intr_hook(hook) \ platform_gpio_register_intr_hook(0, hook); void platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type ); -void platform_gpio_init( task_handle_t gpio_task ); +void platform_gpio_init( platform_task_handle_t gpio_task ); // ***************************************************************************** // Timer subsection @@ -353,4 +354,22 @@ typedef union { uint32_t platform_rcr_read (uint8_t rec_id, void **rec); uint32_t platform_rcr_write (uint8_t rec_id, const void *rec, uint8_t size); +#define PLATFORM_TASK_PRIORITY_LOW 0 +#define PLATFORM_TASK_PRIORITY_MEDIUM 1 +#define PLATFORM_TASK_PRIORITY_HIGH 2 + +/* +* Signals are a 32-bit number of the form header:14; count:16, priority:2. The header +* is just a fixed fingerprint and the count is allocated serially by the task get_id() +* function. +*/ +#define platform_post_low(handle,param) platform_post(PLATFORM_TASK_PRIORITY_LOW, handle, param) +#define platform_post_medium(handle,param) platform_post(PLATFORM_TASK_PRIORITY_MEDIUM, handle, param) +#define platform_post_high(handle,param) platform_post(PLATFORM_TASK_PRIORITY_HIGH, handle, param) + +typedef void (*platform_task_callback_t)(platform_task_param_t param, uint8 prio); +platform_task_handle_t platform_task_get_id(platform_task_callback_t t); + +bool platform_post(uint8 prio, platform_task_handle_t h, platform_task_param_t par); + #endif diff --git a/app/platform/vfs.h b/app/platform/vfs.h index e9784e9863..cf78811ac6 100644 --- a/app/platform/vfs.h +++ b/app/platform/vfs.h @@ -15,7 +15,7 @@ // vfs_close - close file descriptor and free memory // fd: file descriptor // Returns: VFS_RES_OK or negative value in case of error -static int32_t vfs_close( int fd ) { +static inline int32_t vfs_close( int fd ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->close( f ) : VFS_RES_ERR; } @@ -25,7 +25,7 @@ static int32_t vfs_close( int fd ) { // ptr: destination data buffer // len: requested length // Returns: Number of bytes read, or VFS_RES_ERR in case of error -static int32_t vfs_read( int fd, void *ptr, size_t len ) { +static inline int32_t vfs_read( int fd, void *ptr, size_t len ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->read( f, ptr, len ) : VFS_RES_ERR; } @@ -35,7 +35,7 @@ static int32_t vfs_read( int fd, void *ptr, size_t len ) { // ptr: source data buffer // len: requested length // Returns: Number of bytes written, or VFS_RES_ERR in case of error -static int32_t vfs_write( int fd, const void *ptr, size_t len ) { +static inline sint32_t vfs_write( int fd, const void *ptr, size_t len ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->write( f, ptr, len ) : VFS_RES_ERR; } @@ -51,7 +51,7 @@ int vfs_ungetc( int c, int fd ); // VFS_SEEK_CUR - set pointer to current position + off // VFS_SEEK_END - set pointer to end of file + off // Returns: New position, or VFS_RES_ERR in case of error -static int32_t vfs_lseek( int fd, int32_t off, int whence ) { +static inline int32_t vfs_lseek( int fd, sint32_t off, int whence ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->lseek( f, off, whence ) : VFS_RES_ERR; } @@ -59,7 +59,7 @@ static int32_t vfs_lseek( int fd, int32_t off, int whence ) { // vfs_eof - test for end-of-file // fd: file descriptor // Returns: 0 if not at end, != 0 if end of file -static int32_t vfs_eof( int fd ) { +static inline int32_t vfs_eof( int fd ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->eof( f ) : VFS_RES_ERR; } @@ -67,7 +67,7 @@ static int32_t vfs_eof( int fd ) { // vfs_tell - get read/write position // fd: file descriptor // Returns: Current position -static int32_t vfs_tell( int fd ) { +static inline int32_t vfs_tell( int fd ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->tell( f ) : VFS_RES_ERR; } @@ -75,7 +75,7 @@ static int32_t vfs_tell( int fd ) { // vfs_flush - flush write cache to file // fd: file descriptor // Returns: VFS_RES_OK, or VFS_RES_ERR in case of error -static int32_t vfs_flush( int fd ) { +static inline int32_t vfs_flush( int fd ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->flush( f ) : VFS_RES_ERR; } @@ -83,7 +83,7 @@ static int32_t vfs_flush( int fd ) { // vfs_size - get current file size // fd: file descriptor // Returns: File size -static uint32_t vfs_size( int fd ) { +static inline uint32_t vfs_size( int fd ) { vfs_file *f = (vfs_file *)fd; return f ? f->fns->size( f ) : 0; } @@ -100,13 +100,13 @@ int32_t vfs_ferrno( int fd ); // vfs_closedir - close directory descriptor and free memory // dd: dir descriptor // Returns: VFS_RES_OK, or VFS_RES_ERR in case of error -static int32_t vfs_closedir( vfs_dir *dd ) { return dd->fns->close( dd ); } +static inline int32_t vfs_closedir( vfs_dir *dd ) { return dd->fns->close( dd ); } // vfs_readdir - read next directory item // dd: dir descriptor // buf: pre-allocated stat structure to be filled in // Returns: VFS_RES_OK if next item found, otherwise VFS_RES_ERR -static int32_t vfs_readdir( vfs_dir *dd, struct vfs_stat *buf ) { return dd->fns->readdir( dd, buf ); } +static inline int32_t vfs_readdir( vfs_dir *dd, struct vfs_stat *buf ) { return dd->fns->readdir( dd, buf ); } // --------------------------------------------------------------------------- // volume functions @@ -115,7 +115,7 @@ static int32_t vfs_readdir( vfs_dir *dd, struct vfs_stat *buf ) { return dd->fns // vfs_umount - unmount logical drive and free memory // vol: volume object // Returns: VFS_RES_OK, or VFS_RES_ERR in case of error -static int32_t vfs_umount( vfs_vol *vol ) { return vol->fns->umount( vol ); } +static inline int32_t vfs_umount( vfs_vol *vol ) { return vol->fns->umount( vol ); } // --------------------------------------------------------------------------- // file system functions diff --git a/app/pm/swtimer.c b/app/pm/swtimer.c index 5e0bb38b3f..cc0654a9a9 100644 --- a/app/pm/swtimer.c +++ b/app/pm/swtimer.c @@ -41,6 +41,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "task/task.h" #include "user_interface.h" #include "user_modules.h" diff --git a/app/task/Makefile b/app/task/Makefile deleted file mode 100644 index b7db4b50c0..0000000000 --- a/app/task/Makefile +++ /dev/null @@ -1,41 +0,0 @@ - -############################################################# -# Required variables for each makefile -# Discard this section from all parent makefiles -# Expected variables (with automatic defaults): -# CSRCS (all "C" files in the dir) -# SUBDIRS (all subdirs with a Makefile) -# GEN_LIBS - list of libs to be generated () -# GEN_IMAGES - list of images to be generated () -# COMPONENTS_xxx - a list of libs/objs in the form -# subdir/lib to be extracted and rolled up into -# a generated lib/image xxx.a () -# -ifndef PDIR -GEN_LIBS = libtask.a -endif - -############################################################# -# Configuration i.e. compile options etc. -# Target specific stuff (defines etc.) goes in here! -# Generally values applying to a tree are captured in the -# makefile at its root level - these are then overridden -# for a subtree within the makefile rooted therein -# -#DEFINES += - -############################################################# -# Recursion Magic - Don't touch this!! -# -# Each subtree potentially has an include directory -# corresponding to the common APIs applicable to modules -# rooted at that subtree. Accordingly, the INCLUDE PATH -# of a module can only contain the include directories up -# its parent path, and not its siblings -# -# Required for each makefile to inherit from the parent -# - -PDIR := ../$(PDIR) -sinclude $(PDIR)Makefile - diff --git a/app/task/task.c b/app/task/task.c deleted file mode 100644 index e9bc9ef630..0000000000 --- a/app/task/task.c +++ /dev/null @@ -1,72 +0,0 @@ -/** - This file encapsulates the SDK-based task handling for the NodeMCU Lua firmware. - */ -#include "task/task.h" -#include "mem.h" -#include - -#define TASK_HANDLE_MONIKER 0x68680000 -#define TASK_HANDLE_MASK 0xFFF80000 -#define TASK_HANDLE_UNMASK (~TASK_HANDLE_MASK) -#define TASK_HANDLE_SHIFT 2 -#define TASK_HANDLE_ALLOCATION_BRICK 4 // must be a power of 2 -#define TASK_DEFAULT_QUEUE_LEN 8 -#define TASK_PRIORITY_MASK 3 - -#define CHECK(p,v,msg) if (!(p)) { NODE_DBG ( msg ); return (v); } - -/* - * Private arrays to hold the 3 event task queues and the dispatch callbacks - */ -LOCAL os_event_t *task_Q[TASK_PRIORITY_COUNT]; -LOCAL task_callback_t *task_func; -LOCAL int task_count; - -LOCAL void task_dispatch (os_event_t *e) { - task_handle_t handle = e->sig; - if ( (handle & TASK_HANDLE_MASK) == TASK_HANDLE_MONIKER) { - uint16 entry = (handle & TASK_HANDLE_UNMASK) >> TASK_HANDLE_SHIFT; - uint8 priority = handle & TASK_PRIORITY_MASK; - if ( priority <= TASK_PRIORITY_HIGH && task_func && entry < task_count ){ - /* call the registered task handler with the specified parameter and priority */ - task_func[entry](e->par, priority); - return; - } - } - /* Invalid signals are ignored */ - NODE_DBG ( "Invalid signal issued: %08x", handle); -} - -/* - * Initialise the task handle callback for a given priority. This doesn't need - * to be called explicitly as the get_id function will call this lazily. - */ -bool task_init_handler(uint8 priority, uint8 qlen) { - if (priority <= TASK_PRIORITY_HIGH && task_Q[priority] == NULL) { - task_Q[priority] = (os_event_t *) os_malloc( sizeof(os_event_t)*qlen ); - os_memset (task_Q[priority], 0, sizeof(os_event_t)*qlen); - if (task_Q[priority]) { - return system_os_task( task_dispatch, priority, task_Q[priority], qlen ); - } - } - return false; -} - -task_handle_t task_get_id(task_callback_t t) { - int p = TASK_PRIORITY_COUNT; - /* Initialise and uninitialised Qs with the default Q len */ - while(p--) if (!task_Q[p]) { - CHECK(task_init_handler( p, TASK_DEFAULT_QUEUE_LEN ), 0, "Task initialisation failed"); - } - - if ( (task_count & (TASK_HANDLE_ALLOCATION_BRICK - 1)) == 0 ) { - /* With a brick size of 4 this branch is taken at 0, 4, 8 ... and the new size is +4 */ - task_func =(task_callback_t *) os_realloc(task_func, - sizeof(task_callback_t)*(task_count+TASK_HANDLE_ALLOCATION_BRICK)); - CHECK(task_func, 0 , "Malloc failure in task_get_id"); - os_memset (task_func+task_count, 0, sizeof(task_callback_t)*TASK_HANDLE_ALLOCATION_BRICK); - } - - task_func[task_count++] = t; - return TASK_HANDLE_MONIKER + ((task_count-1) << TASK_HANDLE_SHIFT); -} diff --git a/app/user/user_main.c b/app/user/user_main.c index 9afb1fb8d1..ef717ece82 100644 --- a/app/user/user_main.c +++ b/app/user/user_main.c @@ -20,6 +20,7 @@ #include "ets_sys.h" #include "driver/uart.h" +#include "driver/input.h" #include "task/task.h" #include "mem.h" #include "espconn.h" @@ -29,9 +30,6 @@ #include "rtc/rtctime.h" #endif -static task_handle_t input_sig; -static uint8 input_sig_flag = 0; - /* Contents of esp_init_data_default.bin */ extern const uint32_t init_data[], init_data_end[]; #define INIT_DATA_SIZE ((init_data_end - init_data)*sizeof(uint32_t)) @@ -275,40 +273,11 @@ uint32 ICACHE_RAM_ATTR user_iram_memory_is_enabled(void) { return FALSE; // NodeMCU runs like a dog if iRAM is enabled } -// +================== New task interface ==================+ -static void start_lua(task_param_t param, uint8 priority) { - char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL }; - NODE_DBG("Task task_lua started.\n"); - lua_main( 2, lua_argv ); - // Only enable UART interrupts once we've successfully started up, - // otherwise the task queue might fill up with input events and prevent - // the start_lua task from being posted. - ETS_UART_INTR_ENABLE(); -} - -static void handle_input(task_param_t flag, uint8 priority) { - (void)priority; - if (flag & 0x8000) { - input_sig_flag = flag & 0x4000 ? 1 : 0; - } - lua_handle_input (flag & 0x01); -} - -bool user_process_input(bool force) { - return task_post_low(input_sig, force); -} - void nodemcu_init(void) { - NODE_ERR("\n"); - // Initialize platform first for lua modules. - if( platform_init() != PLATFORM_OK ) - { - // This should never happen - NODE_DBG("Can not init platform for modules.\n"); - return; - } - if (!task_post_low(task_get_id(start_lua),'s')) - NODE_ERR("Failed to post the start_lua task!\n"); + NODE_DBG("Task task_lua starting.\n"); + // Call the Lua bootstrap startup directly. This uses the task interface + // internally to carry out the main lua libraries initialisation. + lua_main(); } #ifdef LUA_USE_MODULES_WIFI @@ -328,18 +297,17 @@ void user_rf_pre_init(void) * Parameters : none * Returns : none *******************************************************************************/ -void user_init(void) -{ - +void user_init(void) { #ifdef LUA_USE_MODULES_RTCTIME rtctime_late_startup (); #endif - + if( platform_init() != PLATFORM_OK ) { + // This should never happen + NODE_DBG("Can not init platform for modules.\n"); + return; + } UartBautRate br = BIT_RATE_DEFAULT; - - input_sig = task_get_id(handle_input); - uart_init (br, br, input_sig, &input_sig_flag); - + uart_init (br, br); #ifndef NODE_DEBUG system_set_os_print(0); #endif diff --git a/docs/modules/node.md b/docs/modules/node.md index deaa007e83..326cd48bb5 100644 --- a/docs/modules/node.md +++ b/docs/modules/node.md @@ -298,11 +298,7 @@ print("NodeMCU "..majorVer.."."..minorVer.."."..devVer) ## node.input() -Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, but without the single-line limitation. - -!!! attention - - This function only has an effect when invoked from a callback. Using it directly on the console **does not work**. +Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, but without the single-line limitation. Note that the Line interpreter only actions complete Lua chunks. A Lue Lua chunk must comprise one or more complete `'\n'` terminaed lines that form a complete compilation unit. #### Syntax `node.input(str)` @@ -317,56 +313,29 @@ Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, bu ```lua sk:on("receive", function(conn, payload) node.input(payload) end) ``` +See the `telnet/telnet.lua` in `lua_examples` for a more comprehensive example. #### See also [`node.output()`](#nodeoutput) ## node.output() -Redirects the Lua interpreter output to a callback function. Optionally also prints it to the serial console. - -!!! caution - - Do **not** attempt to `print()` or otherwise induce the Lua interpreter to produce output from within the callback function. Doing so results in infinite recursion, and leads to a watchdog-triggered restart. +Redirects the Lua interpreter to a `stdout` pipe when a CB function is specified (See `pipe` module) and resets output to normal otherwise. Optionally also prints to the serial console. #### Syntax -`node.output(function(str), serial_debug)` +`node.output(function(pipe), serial_debug)` #### Parameters - - `output_fn(str)` a function accept every output as str, and can send the output to a socket (or maybe a file). + - `output_fn(pipe)` a function accept every output as str, and can send the output to a socket (or maybe a file). Note that this function must conform to the fules for a pipe reader callback. - `serial_debug` 1 output also show in serial. 0: no serial output. #### Returns `nil` #### Example -```lua -function tonet(str) - sk:send(str) -end -node.output(tonet, 1) -- serial also get the Lua output. -``` -```lua --- a simple telnet server -s=net.createServer(net.TCP) -s:listen(2323,function(c) - con_std = c - function s_output(str) - if(con_std~=nil) - then con_std:send(str) - end - end - node.output(s_output, 0) -- re-direct output to function s_ouput. - c:on("receive",function(c,l) - node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line - end) - c:on("disconnection",function(c) - con_std = nil - node.output(nil) -- un-regist the redirect output function, output goes to serial - end) -end) -``` +See the `telnet/telnet.lua` in `lua_examples` for a more comprehensive example of its use. + #### See also [`node.input()`](#nodeinput) diff --git a/docs/modules/pipe.md b/docs/modules/pipe.md index 2eb87fa4b1..439276007a 100644 --- a/docs/modules/pipe.md +++ b/docs/modules/pipe.md @@ -11,15 +11,15 @@ task to another. Create a pipe. #### Syntax -`pobj = pipe.create()` +`pobj = pipe.create([CB_function],[task_priority])` #### Parameters -None +- `CB_function` optional reader callback which is called through the `ǹode.task.post()` when the pipe is written to. If the CB returns a boolean, then the reposting action is forced: it is reposted if true and not if false. If the return is nil or omitted then the deault is to repost if a pipe write has occured since the last call. +- `task_priority` See `ǹode.task.post()` #### Returns A pipe resource. - ## pobj:read() Read a record from a pipe object. From ba03cb0ef4bec5ba6758af8bb30bd5a62e929488 Mon Sep 17 00:00:00 2001 From: Terry Ellison Date: Fri, 19 Jul 2019 03:53:53 +0100 Subject: [PATCH 02/59] Add telnet example --- lua_examples/telnet/README.md | 51 ++++---------- lua_examples/telnet/simple_telnet.lua | 35 ---------- .../{telnet.lua => telnet_fifosock.lua} | 0 lua_examples/telnet/telnet_pipe.lua | 68 +++++++++++++++++++ 4 files changed, 82 insertions(+), 72 deletions(-) delete mode 100644 lua_examples/telnet/simple_telnet.lua rename lua_examples/telnet/{telnet.lua => telnet_fifosock.lua} (100%) create mode 100644 lua_examples/telnet/telnet_pipe.lua diff --git a/lua_examples/telnet/README.md b/lua_examples/telnet/README.md index 5029da2978..85075c7b75 100644 --- a/lua_examples/telnet/README.md +++ b/lua_examples/telnet/README.md @@ -6,42 +6,19 @@ | 2018-05-24 | [Terry Ellison](https://github.com/TerryE) | [Terry Ellison](https://github.com/TerryE) | [telnet.lua](./telnet.lua) | -The Lua telnet example previously provided in our distro has been moved to this -file `simple_telnet.lua` in this folder. This README discusses the version complex -implementation at the Lua module `telnet.lua`. The main reason for this complex -alternative is that a single Lua command can produce a LOT of output, and the -telnet server has to work within four constraints: - -- The SDK rules are that you can only issue one send per task invocation, so any -overflow must be buffered, and the buffer emptied using an on:sent callback (CB). - -- Since the interpeter invokes a node.output CB per field, you have a double whammy -that these fields are typically small, so using a simple array FIFO would rapidly -exhaust RAM. - -- For network efficiency, the module aggregates any FIFO buffered into sensible -sized packet, say 1024 bytes, but it must also need to handle the case when larger -string span multiple packets. However, you must flush the buffer if necessary. - -- The overall buffering strategy needs to be reasonably memory efficient and avoid -hitting the GC too hard, so where practical avoid aggregating small strings to more -than 256 chars (as NodeMCU handles \<256 using stack buffers), and avoid serial -aggregation such as buf = buf .. str as this hammers the GC. - -So this server adopts a simple buffering scheme using a two level FIFO. The -`node.output` CB adds records to the 1st level FIFO until the #recs is \> 32 or the -total size would exceed 256 bytes. Once over this threashold, the contents of the -FIFO are concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st -level FIFO cleared down to any residue. - -The sender dumps the 2nd level FIFO aggregating records up to 1024 bytes and once this -is empty dumps an aggrate of the 1st level. - -Lastly remember that owing to architectural limitations of the firmware, this server -can only service stdin and stdout. Lua errors are still sent to stderr which is -the UART0 device. Hence errors will fail silently. If you want to capture -errors then you will need to wrap any commands in a `pcall()` and print any -error return. +This README discusses the packet marshalling versions of telnet. The first (fifosock) +version was written for SDK 2 implementations, with all of the marshalling imlemented +in Lua; the second (pipe) version uses the latest features added to the SDK 3 version +that have been added to prepare for the `lua53` implementation. These exploit the +stdin / stdout pipe functionality and task integration that is now build into the +NodeNMCU Lua core. + +There are two nice advantages of this core implementation: + +- Errors are now written to stdout in a spearate task execution. +- The pipes pretty much eliminate uart and telnet overrun. + +Both have the same interface if required into the variable `telnet` ## telnet:open() @@ -64,7 +41,7 @@ Nothing returned (this is evaluted as `nil` in a scalar context). ## telnet:close() -Close a telnet server and release all resources. +Close a telnet server and release all resources. Also set the variable `telnet` to nil to fully reference and GC the resources. #### Syntax diff --git a/lua_examples/telnet/simple_telnet.lua b/lua_examples/telnet/simple_telnet.lua deleted file mode 100644 index 3f9525bbac..0000000000 --- a/lua_examples/telnet/simple_telnet.lua +++ /dev/null @@ -1,35 +0,0 @@ --- a simple telnet server - -telnet_srv = net.createServer(net.TCP, 180) -telnet_srv:listen(2323, function(socket) - local fifo = {} - local fifo_drained = true - - local function sender(c) - if #fifo > 0 then - c:send(table.remove(fifo, 1)) - else - fifo_drained = true - end - end - - local function s_output(str) - table.insert(fifo, str) - if socket ~= nil and fifo_drained then - fifo_drained = false - sender(socket) - end - end - - node.output(s_output, 0) -- re-direct output to function s_ouput. - - socket:on("receive", function(c, l) - node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line - end) - socket:on("disconnection", function(c) - node.output(nil) -- un-regist the redirect output function, output goes to serial - end) - socket:on("sent", sender) - - print("Welcome to NodeMCU world.") -end) diff --git a/lua_examples/telnet/telnet.lua b/lua_examples/telnet/telnet_fifosock.lua similarity index 100% rename from lua_examples/telnet/telnet.lua rename to lua_examples/telnet/telnet_fifosock.lua diff --git a/lua_examples/telnet/telnet_pipe.lua b/lua_examples/telnet/telnet_pipe.lua new file mode 100644 index 0000000000..935f5837fe --- /dev/null +++ b/lua_examples/telnet/telnet_pipe.lua @@ -0,0 +1,68 @@ +--[[ A telnet server T. Ellison, June 2019 + +This version of the telnet server demonstrates the use of the new stdin and stout +pipes, which is a C implementation of the Lua fifosock concept moved into the +Lua core. These two pipes are referenced in the Lua registry. + +]] + +local M = {} +local modname = ... +local function telnet_session(socket) + local node = node + local stdout, sending + + local function output_CB(opipe) -- upval: socket + stdout = opipe + local rec = opipe:read(1400) + if rec and #rec > 0 then socket:send(rec) end + return false -- don't repost as the on:sent will do this + end + + local function onsent_CB(skt) -- upval: stdout + local rec = stdout:read(1400) + if rec and #rec > 0 then skt:send(rec) end + end + + local function disconnect_CB(skt) -- upval: socket, stdout + node.output() + socket, stdout = nil, nil -- set upvals to nl to allow GC + end + + node.output(output_CB, 0) + socket:on("receive", function(_,rec) node.input(rec) end) + socket:on("sent", onsent_CB) + socket:on("disconnection", disconnect_CB) + print(("Welcome to NodeMCU world (%d mem free, %s)"):format( + node.heap(), wifi.sta.getip())) +end + +function M.open(this, ssid, pwd, port) + local tmr, wifi, uwrite = tmr, wifi, uart.write + if ssid then + wifi.setmode(wifi.STATION, false) + wifi.sta.config { ssid = ssid, pwd = pwd, save = false } + end + local t = tmr.create() + t:alarm(500, tmr.ALARM_AUTO, function() + if (wifi.sta.status() == wifi.STA_GOTIP) then + t:unregister() + t=nil + print(("Telnet server started (%d mem free, %s)"):format( + node.heap(), wifi.sta.getip())) + M.svr = net.createServer(net.TCP, 180) + M.svr:listen(port or 23, telnet_session) + else + uwrite(0,".") + end + end) +end + +function M.close(this) + if this.svr then this.svr:close() end + package.loaded[modname] = nil +end + +return M + + From bc98174e82f0f5147ea5115fbaec656857c35b3f Mon Sep 17 00:00:00 2001 From: Terry Ellison Date: Sat, 20 Jul 2019 00:45:08 +0100 Subject: [PATCH 03/59] Updates following JM review --- app/driver/uart.c | 26 +------------------------ app/include/driver/input.h | 1 - app/lua/lflash.c | 5 +++-- app/lua/lnodemcu.c | 12 ++++-------- app/modules/node.c | 2 +- app/modules/uart.c | 2 +- lua_examples/telnet/telnet_fifosock.lua | 7 ++++--- lua_examples/telnet/telnet_pipe.lua | 13 +++++++------ 8 files changed, 21 insertions(+), 47 deletions(-) diff --git a/app/driver/uart.c b/app/driver/uart.c index 5b50d194b9..ff93f0283c 100644 --- a/app/driver/uart.c +++ b/app/driver/uart.c @@ -165,31 +165,7 @@ uart_tx_one_char(uint8 uart, uint8 TxChar) WRITE_PERI_REG(UART_FIFO(uart) , TxChar); return OK; } -#if 0 -/****************************************************************************** - * FunctionName : uart1_write_char - * Description : Internal used function - * Do some special deal while tx char is '\r' or '\n' - * Parameters : char c - character to tx - * Returns : NONE -*******************************************************************************/ -LOCAL void ICACHE_FLASH_ATTR -uart1_write_char(char c) -{ - if (c == '\n') - { - uart_tx_one_char(UART1, '\r'); - uart_tx_one_char(UART1, '\n'); - } - else if (c == '\r') - { - } - else - { - uart_tx_one_char(UART1, c); - } -} -#endif + /****************************************************************************** * FunctionName : uart0_tx_buffer * Description : use uart0 to transfer buffer diff --git a/app/include/driver/input.h b/app/include/driver/input.h index f18f48b6af..6b44591027 100644 --- a/app/include/driver/input.h +++ b/app/include/driver/input.h @@ -6,6 +6,5 @@ extern void input_setup(int bufsize, const char *prompt); extern void input_setup_receive(uart_cb_t uart_on_data_cb, int data_len, char end_char, bool run_input); extern void input_setecho (bool flag); extern void input_setprompt (const char *prompt); -extern void input_process_arm(void); #endif /* READLINE_APP_H */ diff --git a/app/lua/lflash.c b/app/lua/lflash.c index d2bf5cc2d5..340c106656 100644 --- a/app/lua/lflash.c +++ b/app/lua/lflash.c @@ -121,7 +121,7 @@ static char *flashSetPosition(uint32_t offset){ static char *flashBlock(const void* b, size_t size) { void *cur = flashPosition(); - NODE_DBG("flashBlock((%04x),%08x,%04x)\n", curOffset,b,size); + NODE_DBG("flashBlock((%04x),%p,%04x)\n", curOffset,b,size); lua_assert(ALIGN_BITS(b) == 0 && ALIGN_BITS(size) == 0); platform_flash_write(b, flashAddrPhys+curOffset, size); curOffset += size; @@ -451,7 +451,8 @@ void procSecondPass (void) { int i, len = (out->ndx > out->flashLen) ? (out->flashLen % WRITE_BLOCKSIZE) / WORDSIZE : WRITE_BLOCKSIZE / WORDSIZE; - uint32_t *buf = (uint32_t *) out->buffer.byte, flags = 0; + uint32_t *buf = (uint32_t *) out->buffer.byte; + uint32_t flags = 0; /* * Relocate all the addresses tagged in out->flags. This can't be done in * place because the out->blocks are still in use as dictionary content so diff --git a/app/lua/lnodemcu.c b/app/lua/lnodemcu.c index 6d8cf1a236..520ea02df9 100644 --- a/app/lua/lnodemcu.c +++ b/app/lua/lnodemcu.c @@ -22,12 +22,6 @@ #include "platform.h" extern int debug_errorfb (lua_State *L); -#if 0 -extern int pipe_create(lua_State *L); -extern int pipe_read(lua_State *L); -extern int pipe_unread(lua_State *L); -extern int pipe_write(lua_State *L); -#endif /* ** Error Reporting Task. We can't pass a string parameter to the error reporter ** directly through the task interface the call is wrapped in a C closure with @@ -62,13 +56,15 @@ int luaN_traceback (lua_State *L) { ** an error handler which will catch any error and then post this to the ** registered reporter function as a separate follow-on task. */ -int luaN_call (lua_State *L, int narg, int res, int doGC) { // [-narg, +0, v] +int luaN_call (lua_State *L, int narg, int nres, int doGC) { // [-narg, +0, v] int status; int base = lua_gettop(L) - narg; lua_pushcfunction(L, luaN_traceback); lua_insert(L, base); /* put under args */ - status = lua_pcall(L, narg, (res < 0 ? LUA_MULTRET : res), base); + status = lua_pcall(L, narg, (nres < 0 ? LUA_MULTRET : nres), base); lua_remove(L, base); /* remove traceback function */ + if (status && nres >=0) + lua_settop(L, base + nres); /* balance the stack on error */ /* force a complete garbage collection if requested */ if (doGC) lua_gc(L, LUA_GCCOLLECT, 0); diff --git a/app/modules/node.c b/app/modules/node.c index d3f59a4bcd..bce8ca28e8 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -215,7 +215,7 @@ static int node_output( lua_State* L ) lua_pushlightfunction(L, &pipe_create); lua_insert(L, 1); lua_pushinteger(L, LUA_TASK_MEDIUM); - lua_call(L, 2, 1); /* T[1] = pipe.create(dojob, low_priority) */ + lua_call(L, 2, 1); /* T[1] = pipe.create(CB, medium_priority) */ } else { // remove the stdout pipe lua_pop(L,1); lua_pushnil(L); /* T[1] = nil */ diff --git a/app/modules/uart.c b/app/modules/uart.c index a849095d7e..e67b1ea799 100644 --- a/app/modules/uart.c +++ b/app/modules/uart.c @@ -31,7 +31,7 @@ static int l_uart_on( lua_State* L ) if (lua_type( L, stack ) == LUA_TNUMBER) { data_len = luaL_checkinteger( L, stack ); - luaL_argcheck(L, data_len >= 0 && data_len <= LUA_MAXINPUT, stack, "wrong arg range"); + luaL_argcheck(L, data_len >= 0 && data_len < LUA_MAXINPUT, stack, "wrong arg range"); stack++; } else if (lua_isstring(L, stack)) diff --git a/lua_examples/telnet/telnet_fifosock.lua b/lua_examples/telnet/telnet_fifosock.lua index 328d5cbc75..318fe5daf9 100644 --- a/lua_examples/telnet/telnet_fifosock.lua +++ b/lua_examples/telnet/telnet_fifosock.lua @@ -27,10 +27,11 @@ concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st level FI cleared down to any residue. ]] -local node, table, tmr, wifi, uwrite, tostring = - node, table, tmr, wifi, uart.write, tostring +--luacheck: no unused args -local function telnet_listener(socket) +local node, tmr, wifi, uwrite = node, tmr, wifi, uart.write + +local function telnet_listener(socket) local queueLine = (require "fifosock").wrap(socket) local function receiveLine(s, line) diff --git a/lua_examples/telnet/telnet_pipe.lua b/lua_examples/telnet/telnet_pipe.lua index 935f5837fe..e33be27763 100644 --- a/lua_examples/telnet/telnet_pipe.lua +++ b/lua_examples/telnet/telnet_pipe.lua @@ -1,16 +1,17 @@ --[[ A telnet server T. Ellison, June 2019 -This version of the telnet server demonstrates the use of the new stdin and stout -pipes, which is a C implementation of the Lua fifosock concept moved into the +This version of the telnet server demonstrates the use of the new stdin and stout +pipes, which is a C implementation of the Lua fifosock concept moved into the Lua core. These two pipes are referenced in the Lua registry. ]] +--luacheck: no unused args local M = {} local modname = ... -local function telnet_session(socket) +local function telnet_session(socket) local node = node - local stdout, sending + local stdout local function output_CB(opipe) -- upval: socket stdout = opipe @@ -31,8 +32,8 @@ local function telnet_session(socket) node.output(output_CB, 0) socket:on("receive", function(_,rec) node.input(rec) end) - socket:on("sent", onsent_CB) - socket:on("disconnection", disconnect_CB) + socket:on("sent", onsent_CB) + socket:on("disconnection", disconnect_CB) print(("Welcome to NodeMCU world (%d mem free, %s)"):format( node.heap(), wifi.sta.getip())) end From 39bb60e75ae31ed02f611dc384cc5ad3a6bd9f6e Mon Sep 17 00:00:00 2001 From: Terry Ellison Date: Tue, 23 Jul 2019 20:46:49 +0100 Subject: [PATCH 04/59] Rebased against current dev --- app/driver/pwm2.c | 2 ++ app/include/pm/pmSleep.h | 2 +- app/lua/lflash.c | 1 + app/modules/bme280.c | 1 + app/modules/bme680.c | 1 + app/modules/bmp085.c | 1 + app/modules/file.c | 2 +- app/modules/hdc1080.c | 1 + app/modules/rc.c | 2 ++ app/modules/rotary.c | 1 + app/modules/tcs34725.c | 3 ++- app/modules/uart.c | 2 +- app/modules/wps.c | 1 + app/platform/platform.c | 4 ++-- app/platform/sdcard.c | 2 +- 15 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/driver/pwm2.c b/app/driver/pwm2.c index 38da5c21c7..a052ca3009 100644 --- a/app/driver/pwm2.c +++ b/app/driver/pwm2.c @@ -7,11 +7,13 @@ #include #include +#include #include "mem.h" #include "pin_map.h" #include "platform.h" #include "hw_timer.h" #include "driver/pwm2.h" +#include "user_interface.h" #define PWM2_TMR_MAGIC_80MHZ 16 #define PWM2_TMR_MAGIC_160MHZ 32 diff --git a/app/include/pm/pmSleep.h b/app/include/pm/pmSleep.h index 2fb8f46cf2..ea6c46d492 100644 --- a/app/include/pm/pmSleep.h +++ b/app/include/pm/pmSleep.h @@ -15,7 +15,7 @@ #if defined(PMSLEEP_DEBUG) #define PMSLEEP_DBG(fmt, ...) dbg_printf("\tPMSLEEP(%s):"fmt"\n", __FUNCTION__, ##__VA_ARGS__) #else - #define PMSLEEP_DBG(...) //c_printf(__VA_ARGS__) + #define PMSLEEP_DBG(...) //printf(__VA_ARGS__) #endif #if defined(NODE_ERROR) diff --git a/app/lua/lflash.c b/app/lua/lflash.c index 340c106656..221a667062 100644 --- a/app/lua/lflash.c +++ b/app/lua/lflash.c @@ -14,6 +14,7 @@ #include "lfunc.h" #include "lflash.h" #include "platform.h" +#include "user_interface.h" #include "vfs.h" #include "uzlib.h" diff --git a/app/modules/bme280.c b/app/modules/bme280.c index e8525921c8..9379445e97 100644 --- a/app/modules/bme280.c +++ b/app/modules/bme280.c @@ -11,6 +11,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "user_interface.h" #include /****************************************************/ diff --git a/app/modules/bme680.c b/app/modules/bme680.c index 85efbe2068..dcf6b80059 100644 --- a/app/modules/bme680.c +++ b/app/modules/bme680.c @@ -9,6 +9,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "user_interface.h" #include #include "bme680_defs.h" diff --git a/app/modules/bmp085.c b/app/modules/bmp085.c index 97eeadfb43..75caf2e070 100644 --- a/app/modules/bmp085.c +++ b/app/modules/bmp085.c @@ -1,6 +1,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "user_interface.h" #include #include diff --git a/app/modules/file.c b/app/modules/file.c index 34ff3ed4a3..db717076da 100644 --- a/app/modules/file.c +++ b/app/modules/file.c @@ -585,7 +585,7 @@ static int file_putfile( lua_State* L ) // Lua: fsinfo() static int file_fsinfo( lua_State* L ) { - u32_t total, used; + uint32_t total, used; if (vfs_fsinfo("", &total, &used)) { return luaL_error(L, "file system failed"); } diff --git a/app/modules/hdc1080.c b/app/modules/hdc1080.c index bc3f995f80..55d6eddb76 100644 --- a/app/modules/hdc1080.c +++ b/app/modules/hdc1080.c @@ -7,6 +7,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "user_interface.h" #include #include #include diff --git a/app/modules/rc.c b/app/modules/rc.c index 4f4c85e689..c65061a712 100644 --- a/app/modules/rc.c +++ b/app/modules/rc.c @@ -1,7 +1,9 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "user_interface.h" #include "rom.h" + //#include "driver/easygpio.h" //static Ping_Data pingA; #define defPulseLen 185 diff --git a/app/modules/rotary.c b/app/modules/rotary.c index 44397ef72d..7a414e9cf1 100644 --- a/app/modules/rotary.c +++ b/app/modules/rotary.c @@ -9,6 +9,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "task/task.h" #include #include #include "user_interface.h" diff --git a/app/modules/tcs34725.c b/app/modules/tcs34725.c index b5d59f28df..d989c02241 100644 --- a/app/modules/tcs34725.c +++ b/app/modules/tcs34725.c @@ -22,6 +22,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "user_interface.h" #include // #define TCS34725_ADDRESS (0x29<<1) @@ -352,4 +353,4 @@ LROT_BEGIN(tcs34725) LROT_END( tcs34725, NULL, 0 ) -NODEMCU_MODULE(TCS34725, "tcs34725", tcs34725, NULL); \ No newline at end of file +NODEMCU_MODULE(TCS34725, "tcs34725", tcs34725, NULL); diff --git a/app/modules/uart.c b/app/modules/uart.c index e67b1ea799..2b1f916488 100644 --- a/app/modules/uart.c +++ b/app/modules/uart.c @@ -45,7 +45,7 @@ static int l_uart_on( lua_State* L ) } } - if (lua_anyfunction(L, stack)) { + if (lua_isanyfunction(L, stack)) { if (lua_isnumber(L, stack+1) && lua_tointeger(L, stack+1) == 0) { run_input = false; } diff --git a/app/modules/wps.c b/app/modules/wps.c index e23f6be55c..43b52e2867 100644 --- a/app/modules/wps.c +++ b/app/modules/wps.c @@ -4,6 +4,7 @@ #include "module.h" #include "lauxlib.h" #include "platform.h" +#include "user_interface.h" static int wps_callback_ref; diff --git a/app/platform/platform.c b/app/platform/platform.c index ad7c2c26be..47644dbbc0 100644 --- a/app/platform/platform.c +++ b/app/platform/platform.c @@ -1124,7 +1124,7 @@ static void platform_task_dispatch (os_event_t *e) { static int task_init_handler (void) { int p, qlen = TASK_DEFAULT_QUEUE_LEN; for (p = 0; p < TASK_PRIORITY_COUNT; p++){ - TQB.task_Q[p] = (os_event_t *) c_malloc( sizeof(os_event_t)*qlen ); + TQB.task_Q[p] = (os_event_t *) malloc( sizeof(os_event_t)*qlen ); if (TQB.task_Q[p]) { os_memset(TQB.task_Q[p], 0, sizeof(os_event_t)*qlen); system_os_task(platform_task_dispatch, p, TQB.task_Q[p], TASK_DEFAULT_QUEUE_LEN); @@ -1146,7 +1146,7 @@ static int task_init_handler (void) { */ platform_task_handle_t platform_task_get_id (platform_task_callback_t t) { if ( (TQB.task_count & (TH_ALLOCATION_BRICK - 1)) == 0 ) { - TQB.task_func = (platform_task_callback_t *) os_realloc( + TQB.task_func = (platform_task_callback_t *) realloc( TQB.task_func, sizeof(platform_task_callback_t) * (TQB.task_count+TH_ALLOCATION_BRICK)); if (!TQB.task_func) { diff --git a/app/platform/sdcard.c b/app/platform/sdcard.c index 143d96c89b..d2858612b9 100644 --- a/app/platform/sdcard.c +++ b/app/platform/sdcard.c @@ -1,7 +1,7 @@ #include "platform.h" #include "driver/spi.h" #include - +#include "user_interface.h" #include "sdcard.h" From 522b1d00767561c7e30bbad714266f78a1072e88 Mon Sep 17 00:00:00 2001 From: Terry Ellison Date: Tue, 23 Jul 2019 21:22:59 +0100 Subject: [PATCH 05/59] Rebased against current dev, tweaks for clean compile --- app/coap/endpoints.c | 12 +++++------- app/lua/lua.h | 2 +- app/modules/http.c | 1 + app/platform/u8x8_nodemcu_hal.c | 1 + app/platform/ucg_nodemcu_hal.c | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/coap/endpoints.c b/app/coap/endpoints.c index 1ec882874b..ce62dda6b3 100644 --- a/app/coap/endpoints.c +++ b/app/coap/endpoints.c @@ -162,8 +162,6 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); } -extern int lua_put_line(const char *s, size_t l); - static const coap_endpoint_path_t path_command = {2, {"v1", "c"}}; static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo) { @@ -171,11 +169,11 @@ static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scra return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN); if (inpkt->payload.len > 0) { - char line[LUA_MAXINPUT]; - if (!coap_buffer_to_string(line, LUA_MAXINPUT, &inpkt->payload) && - lua_put_line(line, strlen(line))) { - NODE_DBG("\nResult(if any):\n"); - system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0); + char line[LUA_MAXINPUT+1]; + if (!coap_buffer_to_string(line, LUA_MAXINPUT, &inpkt->payload)) { + int l = strlen(line); + line[l] = '\n'; + lua_input_string(line, l+1); } return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); } diff --git a/app/lua/lua.h b/app/lua/lua.h index 874f0fc43c..46b5dc3517 100644 --- a/app/lua/lua.h +++ b/app/lua/lua.h @@ -277,7 +277,7 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) #define lua_isrotable(L,n) (lua_type(L, (n)) == LUA_TROTABLE) #define lua_isanytable(L,n) (lua_istable(L,n) || lua_isrotable(L,n)) -#define lua_islightuserdata(L,n) (lua_type(L, (n) == LUA_TLIGHTUSERDATA) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) #define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) #define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) diff --git a/app/modules/http.c b/app/modules/http.c index fddc902a83..7b2ff11590 100644 --- a/app/modules/http.c +++ b/app/modules/http.c @@ -3,6 +3,7 @@ * vowstar@gmail.com * 2015-12-29 *******************************************************************************/ +#include #include #include "module.h" #include "lauxlib.h" diff --git a/app/platform/u8x8_nodemcu_hal.c b/app/platform/u8x8_nodemcu_hal.c index 82a5a81b12..11000195db 100644 --- a/app/platform/u8x8_nodemcu_hal.c +++ b/app/platform/u8x8_nodemcu_hal.c @@ -9,6 +9,7 @@ #include #include "platform.h" +#include "user_interface.h" #define U8X8_USE_PINS #define U8X8_WITH_USER_PTR diff --git a/app/platform/ucg_nodemcu_hal.c b/app/platform/ucg_nodemcu_hal.c index a72990f6bd..b54a133e70 100644 --- a/app/platform/ucg_nodemcu_hal.c +++ b/app/platform/ucg_nodemcu_hal.c @@ -8,6 +8,7 @@ #include #include "platform.h" +#include "user_interface.h" #define USE_PIN_LIST #include "ucg_nodemcu_hal.h" From 32ad759409cbaaf53d3f51fc2f6573634eaadbc9 Mon Sep 17 00:00:00 2001 From: Philip Gladstone Date: Tue, 10 Sep 2019 06:47:35 -0400 Subject: [PATCH 06/59] Add streaming support for hx711 device (#2793) --- app/modules/hx711.c | 317 ++++++++++++++++++++++++++++++++++++++---- docs/modules/hx711.md | 60 +++++++- 2 files changed, 345 insertions(+), 32 deletions(-) diff --git a/app/modules/hx711.c b/app/modules/hx711.c index 61198e33a1..cd871504c4 100644 --- a/app/modules/hx711.c +++ b/app/modules/hx711.c @@ -3,65 +3,313 @@ #include "module.h" #include "lauxlib.h" +#include "lmem.h" #include "platform.h" #include #include #include "user_interface.h" static uint8_t data_pin; static uint8_t clk_pin; +// The fields below are after the pin_num conversion +static uint8_t pin_data_pin; +static uint8_t pin_clk_pin; + +#ifdef GPIO_INTERRUPT_ENABLE +static task_handle_t tasknumber; + +// HX711_STATUS can be defined to enable the hx711.status() function to get debug info +#undef HX711_STATUS +#define BUFFERS 2 + +typedef struct { + char *buf[BUFFERS]; + uint32_t dropped[BUFFERS]; + uint32_t timestamp[BUFFERS]; + uint32_t interrupts; + uint32_t hx711_interrupts; + uint16_t buflen; + uint16_t used; + uint32_t nobuffer; + uint8_t active; // slot of the active buffer + uint8_t freed; // slot of the most recently freed buffer + uint8_t mode; + uint8_t dropping; // is non zero when there is no space + int cb_ref; +} CONTROL; + +static CONTROL *control; +#endif /*Lua: hx711.init(clk_pin,data_pin)*/ static int hx711_init(lua_State* L) { - clk_pin = luaL_checkinteger(L,1); - data_pin = luaL_checkinteger(L,2); + clk_pin = luaL_checkint(L,1); + data_pin = luaL_checkint(L,2); MOD_CHECK_ID( gpio, clk_pin ); MOD_CHECK_ID( gpio, data_pin ); platform_gpio_mode(clk_pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT); platform_gpio_write(clk_pin,1);//put chip to sleep. + + pin_data_pin = pin_num[data_pin]; + pin_clk_pin = pin_num[clk_pin]; return 0; } +static int32_t ICACHE_RAM_ATTR read_sample(char mode) { + int i; + int32_t data = 0; + + for (i = 0; i < 24 ; i++){ //clock in the 24 bits + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin); + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin); + data = data << 1; + if (GPIO_REG_READ(GPIO_IN_ADDRESS) & (1 << pin_data_pin)) { + data = i == 0 ? -1 : data | 1; //signextend the first bit + } + } + //add 25th-27th clock pulse to prevent protocol error + for (i = 0; i <= mode; i++) { + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin); + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin); + } + + return data; +} + +#ifdef GPIO_INTERRUPT_ENABLE +static void ICACHE_RAM_ATTR hx711_data_available() { + if (!control) { + return; + } + uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS); + if (bits & (1 << pin_data_pin)) { + return; // not ready + } + + // Read a sample + int32_t data = read_sample(control->mode); + + if (control->dropping) { + if (control->active == control->freed) { + // still can't advance + control->nobuffer++; + return; + } + // Advance + control->active = (1 + control->active) % BUFFERS; + control->dropping = 0; + } + + // insert into the active buffer + char *dest = control->buf[control->active] + control->used; + *dest++ = data; + *dest++ = data >> 8; + *dest++ = data >> 16; + + control->used += 3; + if (control->used == control->buflen) { + control->used = 0; + control->timestamp[control->active] = system_get_time(); + control->dropped[control->active] = control->nobuffer; + control->nobuffer = 0; + // post task + task_post_medium(tasknumber, control->active); + + uint8_t next_active = (1 + control->active) % BUFFERS; + + if (control->active == control->freed) { + // We can't advance to the buffer + control->dropping = 1; + } else { + // flip to other buffer + control->active = next_active; + } + } +} + +static uint32_t ICACHE_RAM_ATTR hx711_interrupt(uint32_t ret_gpio_status) +{ + // This function really is running at interrupt level with everything + // else masked off. It should take as little time as necessary. + // + // + + // This gets the set of pins which have changed status + uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + + int pin_mask = 1 << pin_data_pin; + int i; + + control->interrupts++; + + if (gpio_status & pin_mask) { + uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS); + control->hx711_interrupts++; + if (!(bits & pin_mask)) { + // is now ready to read + hx711_data_available(); + } + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & pin_mask); + } + + return gpio_status & ~pin_mask; +} + +// Lua: hx711.start( mode, samples, callback ) +static int hx711_start( lua_State* L ) +{ + uint32_t mode = luaL_checkint( L, 1 ); + uint32_t samples = luaL_checkint( L, 2 ); + + if (mode > 2) { + return luaL_argerror( L, 1, "Mode value out of range" ); + } + + if (!samples || samples > 400) { + return luaL_argerror( L, 2, "Samples value out of range (1-400)" ); + } + + if (control) { + return luaL_error( L, "Already running" ); + } + + int buflen = 3 * samples; + + control = (CONTROL *) luaM_malloc(L, sizeof(CONTROL) + BUFFERS * buflen); + if (!control) { + return luaL_error( L, "Failed to allocate memory" ); + } + + int cb_ref; + + if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) { + lua_pushvalue(L, 3); // copy argument (func) to the top of stack + cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + luaM_free(L, control); + control = NULL; + return luaL_argerror( L, 3, "Not a callback function" ); + } + + memset(control, 0, sizeof(*control)); + control->buf[0] = (char *) (control + 1); + control->buflen = buflen; + int i; + + for (i = 1; i < BUFFERS; i++) { + control->buf[i] = control->buf[i - 1] + buflen; + } + control->mode = mode; + control->cb_ref = cb_ref; + control->freed = BUFFERS - 1; + + // configure data_pin as interrupt input + platform_gpio_register_intr_hook(1 << pin_data_pin, hx711_interrupt); + platform_gpio_mode(data_pin, PLATFORM_GPIO_INT, PLATFORM_GPIO_FLOAT); + platform_gpio_intr_init(data_pin, GPIO_PIN_INTR_NEGEDGE); + + + // Wake up chip + platform_gpio_write(clk_pin, 0); + + return 0; +} + +// Lua: hx711.stop( ) +static int hx711_stop( lua_State* L ) +{ + if (control) { + platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT); + CONTROL *to_free = control; + control = NULL; + luaL_unref(L, LUA_REGISTRYINDEX, to_free->cb_ref); + luaM_free(L, to_free); + } + + return 0; +} + +static int hx711_status( lua_State* L ) +{ + if (control) { + lua_pushlstring(L, (char *) control, sizeof(*control)); + return 1; + } + + return 0; +} + +static void hx711_task(os_param_t param, uint8_t prio) +{ + (void) prio; + if (!control) { + return; + } + + lua_State *L = lua_getstate(); + + if (control->cb_ref != LUA_NOREF) { + lua_rawgeti(L, LUA_REGISTRYINDEX, control->cb_ref); + + lua_pushlstring(L, control->buf[param], control->buflen); + lua_pushinteger(L, control->timestamp[param]); + lua_pushinteger(L, control->dropped[param]); + + control->freed = param; + + lua_call(L, 3, 0); + } +} +#endif + #define HX711_MAX_WAIT 1000000 /*will only read chA@128gain*/ /*Lua: result = hx711.read()*/ -static int ICACHE_FLASH_ATTR hx711_read(lua_State* L) { - uint32_t i; - int32_t data = 0; +static int hx711_read(lua_State* L) { + int j; //TODO: double check init has happened first. + // - //wakeup hx711 - platform_gpio_write(clk_pin,0); + uint32_t mode = luaL_optinteger(L, 1, 0); - //wait for data ready. or time out. - //TODO: set pin inturrupt and come back to it. This may take up to 1/10 sec - // or maybe just make an async version too and have both available. - system_soft_wdt_feed(); //clear WDT... this may take a while. - for (i = 0; i 2) { + return luaL_argerror( L, 1, "Mode value out of range" ); } - //Handle timeout error - if (i>=HX711_MAX_WAIT) { - return luaL_error( L, "ADC timeout!", ( unsigned )0 ); +#ifdef GPIO_INTERRUPT_ENABLE + if (control) { + hx711_stop(L); } +#endif + + //wakeup hx711 + platform_gpio_write(clk_pin, 0); + + int32_t data; - for (i = 0; i<24 ; i++){ //clock in the 24 bits - platform_gpio_write(clk_pin,1); - platform_gpio_write(clk_pin,0); - data = data<<1; - if (platform_gpio_read(data_pin)==1) { - data = i==0 ? -1 : data|1; //signextend the first bit + // read two samples if mode > 0. We discard the first read and return the + // second value. + for (j = (mode ? 1 : 0); j >= 0; j--) { + uint32_t i; + + //wait for data ready. or time out. + system_soft_wdt_feed(); //clear WDT... this may take a while. + for (i = 0; i= HX711_MAX_WAIT) { + return luaL_error( L, "ADC timeout!"); } + + data = read_sample(mode); } - //add 25th clock pulse to prevent protocol error (probably not needed - // since we'll go to sleep immediately after and reset on wakeup.) - platform_gpio_write(clk_pin,1); - platform_gpio_write(clk_pin,0); - //sleep - platform_gpio_write(clk_pin,1); - lua_pushinteger( L, data ); + + //sleep -- unfortunately, this resets the mode to 0 + platform_gpio_write(clk_pin, 1); + lua_pushinteger(L, data); return 1; } @@ -69,11 +317,20 @@ static int ICACHE_FLASH_ATTR hx711_read(lua_State* L) { LROT_BEGIN(hx711) LROT_FUNCENTRY( init, hx711_init ) LROT_FUNCENTRY( read, hx711_read ) +#ifdef GPIO_INTERRUPT_ENABLE + LROT_FUNCENTRY( start, hx711_start ) +#ifdef HX711_STATUS + LROT_FUNCENTRY( status, hx711_status ) +#endif + LROT_FUNCENTRY( stop, hx711_stop ) +#endif LROT_END( hx711, NULL, 0 ) int luaopen_hx711(lua_State *L) { - // TODO: Make sure that the GPIO system is initialized +#ifdef GPIO_INTERRUPT_ENABLE + tasknumber = task_get_id(hx711_task); +#endif return 0; } diff --git a/docs/modules/hx711.md b/docs/modules/hx711.md index 0eaa3cff19..1095ebae2d 100644 --- a/docs/modules/hx711.md +++ b/docs/modules/hx711.md @@ -2,8 +2,11 @@ | Since | Origin / Contributor | Maintainer | Source | | :----- | :-------------------- | :---------- | :------ | | 2015-10-09 | [Chris Takahashi](https://github.com/christakahashi) | [Chris Takahashi](https://github.com/christakahashi) | [hx711.c](../../app/modules/hx711.c)| +| 2019-04-20 | [Philip Gladstone](https://github.com/pjsg) | [Philip Gladstone](https://github.com/pjsg) -This module provides access to an [HX711 load cell amplifier/ADC](https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide). The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain. Currently only channel A at 128x gain is supported. +This module provides access to an [HX711 load cell amplifier/ADC](https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide). The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain. The standard Chinese sources have [cheap HX711 boards](https://www.aliexpress.com/wholesale?SearchText=hx711+module) for around $1. + +This can be used for single shot reads, or repetitive reads. Note: To save ROM image space, this module is not compiled into the firmware by default. @@ -35,11 +38,13 @@ Read digital loadcell ADC value. `hx711.read(mode)` #### Parameters -`mode` ADC mode. This parameter is currently ignored and reserved to ensure backward compatibility if support for additional modes is added. Currently only channel A @ 128 gain is supported. +- `mode` ADC mode. This parameter specifies which input and the gain to apply to that input. Reading in mode 1 or 2 takes longer than reading in mode 0. |mode | channel | gain | |-----|---------|------| | 0 | A | 128 | +| 1 | B | 32 | +| 2 | A | 64 | #### Returns a number (24 bit signed ADC value extended to the machine int size) @@ -49,3 +54,54 @@ a number (24 bit signed ADC value extended to the machine int size) -- Read ch A with 128 gain. raw_data = hx711.read(0) ``` + +## hx711.start() + +Starts to read multiple samples from the ADC. + +#### Syntax +`hx711.start(mode, samples, callback)` + +#### Parameters +- `mode` ADC mode. This parameter is currently ignored and reserved to ensure backward compatibility if support for additional modes is added. +- `samples` The number of samples before the callback is invoked. The length of time depends on the chip's sampling rate. +- `callback` The callback is invoked with three arguments (see below). + +|mode | channel | gain | +|-----|---------|------| +| 0 | A | 128 | +| 1 | B | 32 | +| 2 | A | 64 | + +#### Returns +nothing + +#### Callback +This is invoked every time `samples` samples are read from the HX711. The arguments are: + +- A string which contains `samples` packed 24 bit values. This can be unpacked with the `struct` module (using the "i3" format). +- The time in microseconds of the reception of the last sample in the buffer. +- The number of samples dropped before the start of this buffer (after the end of the previous buffer). + +#### Notes +This api only is built if GPIO_INTERRUPT_ENABLE and GPIO_INTERRUPT_HOOK_ENABLE are defined in the +`user_config.h`. This is the default. + +Also, do not try and mix calls to `start` and calls to `read`. Any calls to `read` will implicitly call `stop` first. + +#### Example +```lua +-- Read ch A with 128 gain. +hx711.start(0, 2, function(s, t, d) local r1, r2, _ = struct.unpack("i3 i3", s) print(r1, r2) end) +``` + +## hx711.stop() + +Stops a previously started set of reads. Any data in buffers is lost. No more callbacks will be invoked. + +#### Syntax +`hx711.stop()` + +#### Returns +nothing + From 4c3d45e41252dafea23b2475c2fc0114248b5c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Fri, 13 Sep 2019 13:47:34 +0200 Subject: [PATCH 07/59] Revert "Add streaming support for hx711 device (#2793)" (#2914) This reverts commit 32ad759409cbaaf53d3f51fc2f6573634eaadbc9. --- app/modules/hx711.c | 317 ++++-------------------------------------- docs/modules/hx711.md | 60 +------- 2 files changed, 32 insertions(+), 345 deletions(-) diff --git a/app/modules/hx711.c b/app/modules/hx711.c index cd871504c4..61198e33a1 100644 --- a/app/modules/hx711.c +++ b/app/modules/hx711.c @@ -3,313 +3,65 @@ #include "module.h" #include "lauxlib.h" -#include "lmem.h" #include "platform.h" #include #include #include "user_interface.h" static uint8_t data_pin; static uint8_t clk_pin; -// The fields below are after the pin_num conversion -static uint8_t pin_data_pin; -static uint8_t pin_clk_pin; - -#ifdef GPIO_INTERRUPT_ENABLE -static task_handle_t tasknumber; - -// HX711_STATUS can be defined to enable the hx711.status() function to get debug info -#undef HX711_STATUS -#define BUFFERS 2 - -typedef struct { - char *buf[BUFFERS]; - uint32_t dropped[BUFFERS]; - uint32_t timestamp[BUFFERS]; - uint32_t interrupts; - uint32_t hx711_interrupts; - uint16_t buflen; - uint16_t used; - uint32_t nobuffer; - uint8_t active; // slot of the active buffer - uint8_t freed; // slot of the most recently freed buffer - uint8_t mode; - uint8_t dropping; // is non zero when there is no space - int cb_ref; -} CONTROL; - -static CONTROL *control; -#endif /*Lua: hx711.init(clk_pin,data_pin)*/ static int hx711_init(lua_State* L) { - clk_pin = luaL_checkint(L,1); - data_pin = luaL_checkint(L,2); + clk_pin = luaL_checkinteger(L,1); + data_pin = luaL_checkinteger(L,2); MOD_CHECK_ID( gpio, clk_pin ); MOD_CHECK_ID( gpio, data_pin ); platform_gpio_mode(clk_pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT); platform_gpio_write(clk_pin,1);//put chip to sleep. - - pin_data_pin = pin_num[data_pin]; - pin_clk_pin = pin_num[clk_pin]; return 0; } -static int32_t ICACHE_RAM_ATTR read_sample(char mode) { - int i; - int32_t data = 0; - - for (i = 0; i < 24 ; i++){ //clock in the 24 bits - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin); - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin); - data = data << 1; - if (GPIO_REG_READ(GPIO_IN_ADDRESS) & (1 << pin_data_pin)) { - data = i == 0 ? -1 : data | 1; //signextend the first bit - } - } - //add 25th-27th clock pulse to prevent protocol error - for (i = 0; i <= mode; i++) { - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin); - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin); - } - - return data; -} - -#ifdef GPIO_INTERRUPT_ENABLE -static void ICACHE_RAM_ATTR hx711_data_available() { - if (!control) { - return; - } - uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS); - if (bits & (1 << pin_data_pin)) { - return; // not ready - } - - // Read a sample - int32_t data = read_sample(control->mode); - - if (control->dropping) { - if (control->active == control->freed) { - // still can't advance - control->nobuffer++; - return; - } - // Advance - control->active = (1 + control->active) % BUFFERS; - control->dropping = 0; - } - - // insert into the active buffer - char *dest = control->buf[control->active] + control->used; - *dest++ = data; - *dest++ = data >> 8; - *dest++ = data >> 16; - - control->used += 3; - if (control->used == control->buflen) { - control->used = 0; - control->timestamp[control->active] = system_get_time(); - control->dropped[control->active] = control->nobuffer; - control->nobuffer = 0; - // post task - task_post_medium(tasknumber, control->active); - - uint8_t next_active = (1 + control->active) % BUFFERS; - - if (control->active == control->freed) { - // We can't advance to the buffer - control->dropping = 1; - } else { - // flip to other buffer - control->active = next_active; - } - } -} - -static uint32_t ICACHE_RAM_ATTR hx711_interrupt(uint32_t ret_gpio_status) -{ - // This function really is running at interrupt level with everything - // else masked off. It should take as little time as necessary. - // - // - - // This gets the set of pins which have changed status - uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); - - int pin_mask = 1 << pin_data_pin; - int i; - - control->interrupts++; - - if (gpio_status & pin_mask) { - uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS); - control->hx711_interrupts++; - if (!(bits & pin_mask)) { - // is now ready to read - hx711_data_available(); - } - GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & pin_mask); - } - - return gpio_status & ~pin_mask; -} - -// Lua: hx711.start( mode, samples, callback ) -static int hx711_start( lua_State* L ) -{ - uint32_t mode = luaL_checkint( L, 1 ); - uint32_t samples = luaL_checkint( L, 2 ); - - if (mode > 2) { - return luaL_argerror( L, 1, "Mode value out of range" ); - } - - if (!samples || samples > 400) { - return luaL_argerror( L, 2, "Samples value out of range (1-400)" ); - } - - if (control) { - return luaL_error( L, "Already running" ); - } - - int buflen = 3 * samples; - - control = (CONTROL *) luaM_malloc(L, sizeof(CONTROL) + BUFFERS * buflen); - if (!control) { - return luaL_error( L, "Failed to allocate memory" ); - } - - int cb_ref; - - if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) { - lua_pushvalue(L, 3); // copy argument (func) to the top of stack - cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); - } else { - luaM_free(L, control); - control = NULL; - return luaL_argerror( L, 3, "Not a callback function" ); - } - - memset(control, 0, sizeof(*control)); - control->buf[0] = (char *) (control + 1); - control->buflen = buflen; - int i; - - for (i = 1; i < BUFFERS; i++) { - control->buf[i] = control->buf[i - 1] + buflen; - } - control->mode = mode; - control->cb_ref = cb_ref; - control->freed = BUFFERS - 1; - - // configure data_pin as interrupt input - platform_gpio_register_intr_hook(1 << pin_data_pin, hx711_interrupt); - platform_gpio_mode(data_pin, PLATFORM_GPIO_INT, PLATFORM_GPIO_FLOAT); - platform_gpio_intr_init(data_pin, GPIO_PIN_INTR_NEGEDGE); - - - // Wake up chip - platform_gpio_write(clk_pin, 0); - - return 0; -} - -// Lua: hx711.stop( ) -static int hx711_stop( lua_State* L ) -{ - if (control) { - platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT); - CONTROL *to_free = control; - control = NULL; - luaL_unref(L, LUA_REGISTRYINDEX, to_free->cb_ref); - luaM_free(L, to_free); - } - - return 0; -} - -static int hx711_status( lua_State* L ) -{ - if (control) { - lua_pushlstring(L, (char *) control, sizeof(*control)); - return 1; - } - - return 0; -} - -static void hx711_task(os_param_t param, uint8_t prio) -{ - (void) prio; - if (!control) { - return; - } - - lua_State *L = lua_getstate(); - - if (control->cb_ref != LUA_NOREF) { - lua_rawgeti(L, LUA_REGISTRYINDEX, control->cb_ref); - - lua_pushlstring(L, control->buf[param], control->buflen); - lua_pushinteger(L, control->timestamp[param]); - lua_pushinteger(L, control->dropped[param]); - - control->freed = param; - - lua_call(L, 3, 0); - } -} -#endif - #define HX711_MAX_WAIT 1000000 /*will only read chA@128gain*/ /*Lua: result = hx711.read()*/ -static int hx711_read(lua_State* L) { - int j; +static int ICACHE_FLASH_ATTR hx711_read(lua_State* L) { + uint32_t i; + int32_t data = 0; //TODO: double check init has happened first. - // - uint32_t mode = luaL_optinteger(L, 1, 0); + //wakeup hx711 + platform_gpio_write(clk_pin,0); - if (mode > 2) { - return luaL_argerror( L, 1, "Mode value out of range" ); + //wait for data ready. or time out. + //TODO: set pin inturrupt and come back to it. This may take up to 1/10 sec + // or maybe just make an async version too and have both available. + system_soft_wdt_feed(); //clear WDT... this may take a while. + for (i = 0; i=HX711_MAX_WAIT) { + return luaL_error( L, "ADC timeout!", ( unsigned )0 ); } -#endif - - //wakeup hx711 - platform_gpio_write(clk_pin, 0); - - int32_t data; - // read two samples if mode > 0. We discard the first read and return the - // second value. - for (j = (mode ? 1 : 0); j >= 0; j--) { - uint32_t i; - - //wait for data ready. or time out. - system_soft_wdt_feed(); //clear WDT... this may take a while. - for (i = 0; i= HX711_MAX_WAIT) { - return luaL_error( L, "ADC timeout!"); + for (i = 0; i<24 ; i++){ //clock in the 24 bits + platform_gpio_write(clk_pin,1); + platform_gpio_write(clk_pin,0); + data = data<<1; + if (platform_gpio_read(data_pin)==1) { + data = i==0 ? -1 : data|1; //signextend the first bit } - - data = read_sample(mode); } - - //sleep -- unfortunately, this resets the mode to 0 - platform_gpio_write(clk_pin, 1); - lua_pushinteger(L, data); + //add 25th clock pulse to prevent protocol error (probably not needed + // since we'll go to sleep immediately after and reset on wakeup.) + platform_gpio_write(clk_pin,1); + platform_gpio_write(clk_pin,0); + //sleep + platform_gpio_write(clk_pin,1); + lua_pushinteger( L, data ); return 1; } @@ -317,20 +69,11 @@ static int hx711_read(lua_State* L) { LROT_BEGIN(hx711) LROT_FUNCENTRY( init, hx711_init ) LROT_FUNCENTRY( read, hx711_read ) -#ifdef GPIO_INTERRUPT_ENABLE - LROT_FUNCENTRY( start, hx711_start ) -#ifdef HX711_STATUS - LROT_FUNCENTRY( status, hx711_status ) -#endif - LROT_FUNCENTRY( stop, hx711_stop ) -#endif LROT_END( hx711, NULL, 0 ) int luaopen_hx711(lua_State *L) { -#ifdef GPIO_INTERRUPT_ENABLE - tasknumber = task_get_id(hx711_task); -#endif + // TODO: Make sure that the GPIO system is initialized return 0; } diff --git a/docs/modules/hx711.md b/docs/modules/hx711.md index 1095ebae2d..0eaa3cff19 100644 --- a/docs/modules/hx711.md +++ b/docs/modules/hx711.md @@ -2,11 +2,8 @@ | Since | Origin / Contributor | Maintainer | Source | | :----- | :-------------------- | :---------- | :------ | | 2015-10-09 | [Chris Takahashi](https://github.com/christakahashi) | [Chris Takahashi](https://github.com/christakahashi) | [hx711.c](../../app/modules/hx711.c)| -| 2019-04-20 | [Philip Gladstone](https://github.com/pjsg) | [Philip Gladstone](https://github.com/pjsg) -This module provides access to an [HX711 load cell amplifier/ADC](https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide). The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain. The standard Chinese sources have [cheap HX711 boards](https://www.aliexpress.com/wholesale?SearchText=hx711+module) for around $1. - -This can be used for single shot reads, or repetitive reads. +This module provides access to an [HX711 load cell amplifier/ADC](https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide). The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain. Currently only channel A at 128x gain is supported. Note: To save ROM image space, this module is not compiled into the firmware by default. @@ -38,13 +35,11 @@ Read digital loadcell ADC value. `hx711.read(mode)` #### Parameters -- `mode` ADC mode. This parameter specifies which input and the gain to apply to that input. Reading in mode 1 or 2 takes longer than reading in mode 0. +`mode` ADC mode. This parameter is currently ignored and reserved to ensure backward compatibility if support for additional modes is added. Currently only channel A @ 128 gain is supported. |mode | channel | gain | |-----|---------|------| | 0 | A | 128 | -| 1 | B | 32 | -| 2 | A | 64 | #### Returns a number (24 bit signed ADC value extended to the machine int size) @@ -54,54 +49,3 @@ a number (24 bit signed ADC value extended to the machine int size) -- Read ch A with 128 gain. raw_data = hx711.read(0) ``` - -## hx711.start() - -Starts to read multiple samples from the ADC. - -#### Syntax -`hx711.start(mode, samples, callback)` - -#### Parameters -- `mode` ADC mode. This parameter is currently ignored and reserved to ensure backward compatibility if support for additional modes is added. -- `samples` The number of samples before the callback is invoked. The length of time depends on the chip's sampling rate. -- `callback` The callback is invoked with three arguments (see below). - -|mode | channel | gain | -|-----|---------|------| -| 0 | A | 128 | -| 1 | B | 32 | -| 2 | A | 64 | - -#### Returns -nothing - -#### Callback -This is invoked every time `samples` samples are read from the HX711. The arguments are: - -- A string which contains `samples` packed 24 bit values. This can be unpacked with the `struct` module (using the "i3" format). -- The time in microseconds of the reception of the last sample in the buffer. -- The number of samples dropped before the start of this buffer (after the end of the previous buffer). - -#### Notes -This api only is built if GPIO_INTERRUPT_ENABLE and GPIO_INTERRUPT_HOOK_ENABLE are defined in the -`user_config.h`. This is the default. - -Also, do not try and mix calls to `start` and calls to `read`. Any calls to `read` will implicitly call `stop` first. - -#### Example -```lua --- Read ch A with 128 gain. -hx711.start(0, 2, function(s, t, d) local r1, r2, _ = struct.unpack("i3 i3", s) print(r1, r2) end) -``` - -## hx711.stop() - -Stops a previously started set of reads. Any data in buffers is lost. No more callbacks will be invoked. - -#### Syntax -`hx711.stop()` - -#### Returns -nothing - From 81e213ace0144d40a103ed6aeed71b61f251e24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Sat, 21 Sep 2019 17:24:48 +0200 Subject: [PATCH 08/59] Remove superfluous module def Fixes #2920 --- app/include/user_config.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/include/user_config.h b/app/include/user_config.h index d0b923b51c..5734f3be29 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -134,10 +134,6 @@ // Enable creation on the wifi.eventmon.reason table #define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE -// Enable use of the WiFi.monitor sub-module -//#define LUA_USE_MODULES_WIFI_MONITOR - - // Whilst the DNS client details can be configured through the WiFi API, // the defaults can be exposed temporarily during start-up. The following // WIFI_STA options allow you to configure this in the firmware. If the From 04287acbd4f13a07189ce6b971654ca7c284ec79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Sun, 29 Sep 2019 20:40:56 +0200 Subject: [PATCH 09/59] Fix invalid smartconfig include Fixes #2928, #2923 --- app/modules/wifi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/modules/wifi.c b/app/modules/wifi.c index 7d5766a575..27ec988e16 100644 --- a/app/modules/wifi.c +++ b/app/modules/wifi.c @@ -17,7 +17,7 @@ #ifdef WIFI_SMART_ENABLE #include "smart/smart.h" -#include "smart/smartconfig.h" +#include "smartconfig.h" static int wifi_smart_succeed = LUA_NOREF; #endif From 043046d2ab06fdefdae2a097c7c0f01cdb8da2fb Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Mon, 30 Sep 2019 13:41:51 +0100 Subject: [PATCH 10/59] Deprecate crypto.to{Hex,Base64} (#2929) The internal implementation already preferentially forwards to the encoder module, so we should just remove these functions as they confuse people into thinking that we don't have their inverses (see the feature request https://github.com/nodemcu/nodemcu-firmware/issues/2907). Update the docs to refer to the encoder version and add deprecation warnings to the runtime implementations. --- app/modules/crypto.c | 6 ++++++ docs/modules/crypto.md | 32 ++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/modules/crypto.c b/app/modules/crypto.c index 3deabdaa1d..81443181ab 100644 --- a/app/modules/crypto.c +++ b/app/modules/crypto.c @@ -61,9 +61,11 @@ static int call_encoder( lua_State* L, const char *function ) { } static int crypto_base64_encode (lua_State* L) { + platform_print_deprecation_note("crypto.toBase64", "in the next version"); return call_encoder(L, "toBase64"); } static int crypto_hex_encode (lua_State* L) { + platform_print_deprecation_note("crypto.toHex", "in the next version"); return call_encoder(L, "toHex"); } #else @@ -79,6 +81,8 @@ static int crypto_base64_encode( lua_State* L ) const char* msg = luaL_checklstring(L, 1, &len); luaL_Buffer out; + platform_print_deprecation_note("crypto.toBase64", "in the next version"); + luaL_buffinit(L, &out); for (i = 0; i < len; i += 3) { int a = msg[i]; @@ -104,6 +108,8 @@ static int crypto_hex_encode( lua_State* L) const char* msg = luaL_checklstring(L, 1, &len); luaL_Buffer out; + platform_print_deprecation_note("crypto.toHex", "in the next version"); + luaL_buffinit(L, &out); for (i = 0; i < len; i++) { luaL_addchar(&out, crypto_hexbytes[msg[i] >> 4]); diff --git a/docs/modules/crypto.md b/docs/modules/crypto.md index 97f9dec296..75bec7e357 100644 --- a/docs/modules/crypto.md +++ b/docs/modules/crypto.md @@ -33,7 +33,7 @@ The encrypted data as a binary string. For AES this is always a multiple of 16 b #### Example ```lua -print(crypto.toHex(crypto.encrypt("AES-ECB", "1234567890abcdef", "Hi, I'm secret!"))) +print(encoder.toHex(crypto.encrypt("AES-ECB", "1234567890abcdef", "Hi, I'm secret!"))) ``` #### See also @@ -62,7 +62,7 @@ Note that the decrypted string may contain extra zero-bytes of padding at the en ```lua key = "1234567890abcdef" cipher = crypto.encrypt("AES-ECB", key, "Hi, I'm secret!") -print(crypto.toHex(cipher)) +print(encoder.toHex(cipher)) print(crypto.decrypt("AES-ECB", key, cipher)) ``` @@ -82,11 +82,11 @@ Compute a cryptographic hash of a a file. - `filename` the path to the file to hash #### Returns -A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use [`crypto.toHex()`](#cryptotohex ). +A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use [`encoder.toHex()`](encoder.md#encodertohex ). #### Example ```lua -print(crypto.toHex(crypto.fhash("sha1","myfile.lua"))) +print(encoder.toHex(crypto.fhash("sha1","myfile.lua"))) ``` ## crypto.hash() @@ -101,11 +101,11 @@ Compute a cryptographic hash of a Lua string. `str` string to hash contents of #### Returns -A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use [`crypto.toHex()`](#cryptotohex ). +A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use [`encoder.toHex()`](encoder.md#encodertohex). #### Example ```lua -print(crypto.toHex(crypto.hash("sha1","abc"))) +print(encoder.toHex(crypto.hash("sha1","abc"))) ``` ## crypto.new_hash() @@ -127,7 +127,7 @@ hashobj = crypto.new_hash("SHA1") hashobj:update("FirstString") hashobj:update("SecondString") digest = hashobj:finalize() -print(crypto.toHex(digest)) +print(encoder.toHex(digest)) ``` ## crypto.hmac() @@ -143,11 +143,11 @@ Compute a [HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication - `key` key to use for signing, may be a binary string #### Returns -A binary string containing the HMAC signature. Use [`crypto.toHex()`](#cryptotohex) to obtain the textual version. +A binary string containing the HMAC signature. Use [`encoder.toHex()`](encoder.md#encodertohex) to obtain the textual version. #### Example ```lua -print(crypto.toHex(crypto.hmac("sha1","abc","mysecret"))) +print(encoder.toHex(crypto.hmac("sha1","abc","mysecret"))) ``` ## crypto.new_hmac() @@ -170,7 +170,7 @@ hmacobj = crypto.new_hmac("SHA1", "s3kr3t") hmacobj:update("FirstString") hmacobj:update("SecondString") digest = hmacobj:finalize() -print(crypto.toHex(digest)) +print(encoder.toHex(digest)) ``` @@ -186,17 +186,21 @@ Applies an XOR mask to a Lua string. Note that this is not a proper cryptographi - `mask` the mask to apply, repeated if shorter than the message #### Returns -The masked message, as a binary string. Use [`crypto.toHex()`](#cryptotohex) to get a textual representation of it. +The masked message, as a binary string. Use [`encoder.toHex()`](encoder.md#encodertohex) to get a textual representation of it. #### Example ```lua -print(crypto.toHex(crypto.mask("some message to obscure","X0Y7"))) +print(encoder.toHex(crypto.mask("some message to obscure","X0Y7"))) ``` ## crypto.toBase64() Provides a Base64 representation of a (binary) Lua string. +!!! warning + + This function is deprecated; please use instead [`encoder.toBase64()`](encoder.md#encodertobase64) + #### Syntax `b64 = crypto.toBase64(binary)` @@ -215,6 +219,10 @@ print(crypto.toBase64(crypto.hash("sha1","abc"))) Provides an ASCII hex representation of a (binary) Lua string. Each byte in the input string is represented as two hex characters in the output. +!!! warning + + This function is deprecated; please use instead [`encoder.toHex()`](encoder.md#encodertohex) + #### Syntax `hexstr = crypto.toHex(binary)` From f3044e1aff432ca48f6511554b317e0c80207d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Wed, 30 Oct 2019 22:36:06 +0100 Subject: [PATCH 11/59] Fix typos --- docs/modules/node.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/modules/node.md b/docs/modules/node.md index 3c4a98337b..d082c05c1a 100644 --- a/docs/modules/node.md +++ b/docs/modules/node.md @@ -299,9 +299,9 @@ If a `group` is given the return value will be a table containing the following - `git_commit_id` (string) - `git_release` (string) release name +additional commits e.g. "2.0.0-master_20170202 +403" - `git_commit_dts` (string) commit timestamp in an ordering format. e.g. "201908111200" - - `node_verion_major` (number) - - `node_verion_minor` (number) - - `node_verion_revision` (number) + - `node_version_major` (number) + - `node_version_minor` (number) + - `node_version_revision` (number) - for `group` = `"build_config"` - `ssl` (boolean) - `lfs_size` (number) as defined at build time From 0e34f7d3090fa262c90184a9e204b58fc9798583 Mon Sep 17 00:00:00 2001 From: "Matsievskiy S.V" Date: Wed, 13 Nov 2019 23:48:20 +0300 Subject: [PATCH 12/59] fix lfs upload issue --- app/lua/lflash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lua/lflash.c b/app/lua/lflash.c index 221a667062..a3afcf9b46 100644 --- a/app/lua/lflash.c +++ b/app/lua/lflash.c @@ -539,7 +539,7 @@ static int loadLFS (lua_State *L) { flashSetPosition(0); if ((res = uzlib_inflate(get_byte, put_byte, recall_byte, - in->len, &crc, &in->inflate_state)) != UZLIB_OK) { + in->len, &crc, &in->inflate_state)) != UZLIB_DONE) { const char *err[] = {"Data_error during decompression", "Chksum_error during decompression", "Dictionary error during decompression", From e3935debd3a435700aa209bbc6212ef549e839f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Str=C3=B6m?= Date: Thu, 21 Nov 2019 12:38:07 +0100 Subject: [PATCH 13/59] Improve MQTT documentation (#2967) --- docs/modules/mqtt.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/mqtt.md b/docs/modules/mqtt.md index 0a01d1bab9..0b9261df80 100644 --- a/docs/modules/mqtt.md +++ b/docs/modules/mqtt.md @@ -157,8 +157,8 @@ end In reality, the connected function should do something useful! -The two callbacks to `:connect()` alias with the "connect" and "offline" -callbacks available through `:on()`. +The first callback to `:connect()` aliases with the "connect" callback available through `:on()` (the last passed callback to either of those are used). +The second (failure) callback is however not the same as the "offline" `:on()` callback. The "offline" callback is only called after an already established connection becomes closed. If the `connect()` call fails to establish a connection, the callback passed to `:connect()` is called and nothing else. Previously, we instructed an application to pass either the *integer* 0 or *integer* 1 for `secure`. Now, this will trigger a deprecation warning; please From 9a2579d97160e981cd084ff483f0eeac8210da37 Mon Sep 17 00:00:00 2001 From: Gregor Hartmann Date: Tue, 26 Nov 2019 12:12:45 +0100 Subject: [PATCH 14/59] Improve httpserver documentation (#2971) --- docs/lua-modules/httpserver.md | 29 ++++++++++++++++++++++------- lua_modules/http/httpserver.lua | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/lua-modules/httpserver.md b/docs/lua-modules/httpserver.md index 0d3139ff1c..64634e78b5 100644 --- a/docs/lua-modules/httpserver.md +++ b/docs/lua-modules/httpserver.md @@ -36,20 +36,35 @@ Callback function has 2 arguments: `req` (request) and `res` (response). The fir object. - `method`: Request method that was used (e.g.`POST` or `GET`) - `url`: Requested URL -- `onheader`: value to setup handler function for HTTP headers like `content-type`. Handler function has 3 parameters: +- `onheader`: assign a function to this value which will be called as soon as HTTP headers like `content-type` are available. + This handler function has 3 parameters: - `self`: `req` object - - `name`: Header name + - `name`: Header name. Will allways be lowercase. - `value`: Header value -- `ondata`: value to setup handler function HTTP data. Handler function has 2 parameters: +- `ondata`: assign a function to this value which will be called as soon as body data is available. + This handler function has 2 parameters: - `self`: `req` object - - `chunk`: Request data + - `chunk`: Request data. If all data is received there will be one last call with data = nil The second object holds functions: -- `send(self, data, [response_code])`: Function to send data to client. `self` is `req` object, `data` is data to send and `response_code` is HTTP response code like `200` or `404` (for example) -- `send_header(self, header_name, header_data)`: Function to send HTTP headers to client. `self` is `req` object, `header_name` is HTTP header name and `header_data` is HTTP header data for client. -- `finish([data])`: Function to finalize connection, optionally sending data. `data` is optional data to send on connection finalizing. +- `send(self, data, [response_code])`: Function to send data to client. + + - `self`: `res` object + - `data`: data to send (may be nil) + - `response_code`: the HTTP response code like `200`(default) or `404` (for example) *NOTE* if there are several calls with response_code given only the first one will be used. Any further codes given will be ignored. + +- `send_header(self, header_name, header_data)`: Function to send HTTP headers to client. This function will not be available after data has been sent. (It will be nil.) + + - `self`: `res` object + - `header_name`: the HTTP header name + - `header_data`: the HTTP header data + +- `finish([data[, response_code]])`: Function to finalize connection, optionally sending data and return code. + + - `data`: optional data to send on connection finalizing + - `response_code`: the HTTP response code like `200`(default) or `404` (for example) *NOTE* if there are several calls with response_code given only the first one will be used. Any further codes given will be ignored. Full example can be found in [http-example.lua](../../lua_modules/http/http-example.lua) diff --git a/lua_modules/http/httpserver.lua b/lua_modules/http/httpserver.lua index ba2696036e..50717e1e96 100644 --- a/lua_modules/http/httpserver.lua +++ b/lua_modules/http/httpserver.lua @@ -116,7 +116,7 @@ do if not req or not req.ondata then return end req:ondata(chunk) -- NB: once length of seen chunks equals Content-Length: - -- onend(conn) is called + -- ondata(conn) is called body_len = body_len + #chunk -- print("-B", #chunk, body_len, cnt_len, node.heap()) if body_len >= cnt_len then From c7d0f836257060dbd1f6655cb066e6ae0d8e4443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Voborsk=C3=BD?= Date: Mon, 9 Dec 2019 13:29:23 +0100 Subject: [PATCH 15/59] Update sensor driver for BME680 to 3.5.9 (#2969) --- app/modules/bme680.c | 131 ++++++++++++---------- app/modules/bme680_defs.h | 227 ++++++++++++++++++++------------------ 2 files changed, 193 insertions(+), 165 deletions(-) diff --git a/app/modules/bme680.c b/app/modules/bme680.c index dcf6b80059..c4a08f6273 100644 --- a/app/modules/bme680.c +++ b/app/modules/bme680.c @@ -68,7 +68,10 @@ static uint8_t r8u(uint8_t reg) { return ret[0]; } -/* This part of code is coming from the original bme680.c driver by Bosch. +// replace 'dev->calib.' with 'bme680_data.' +// replace 'dev->amb_temp' with 'amb_temp' + +/**\mainpage * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH * * Redistribution and use in source and binary forms, with or without @@ -108,20 +111,13 @@ static uint8_t r8u(uint8_t reg) { * other rights of third parties which may result from its use. * No license is granted by implication or otherwise under any patent or * patent rights of the copyright holder. + * + * File bme680.c + * @date 19 Jun 2018 + * @version 3.5.9 + * */ -/**static variables */ -/**Look up table for the possible gas range values */ -uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), - UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777), UINT32_C(2147483647), - UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228), UINT32_C(2147483647), UINT32_C(2126008810), - UINT32_C(2147483647), UINT32_C(2147483647) }; -/**Look up table for the possible gas range values */ -uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000), - UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016), UINT32_C( - 8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000), UINT32_C(250000), - UINT32_C(125000) }; - static uint8_t calc_heater_res(uint16_t temp) { uint8_t heatr_res; @@ -132,9 +128,7 @@ static uint8_t calc_heater_res(uint16_t temp) int32_t var5; int32_t heatr_res_x100; - if (temp < 200) /* Cap temperature */ - temp = 200; - else if (temp > 400) + if (temp > 400) /* Cap temperature */ temp = 400; var1 = (((int32_t) amb_temp * bme680_data.par_gh3) / 1000) * 256; @@ -173,12 +167,12 @@ static int16_t calc_temperature(uint32_t temp_adc) int64_t var3; int16_t calc_temp; - var1 = ((int32_t) temp_adc / 8) - ((int32_t) bme680_data.par_t1 * 2); - var2 = (var1 * (int32_t) bme680_data.par_t2) / 2048; - var3 = ((var1 / 2) * (var1 / 2)) / 4096; - var3 = ((var3) * ((int32_t) bme680_data.par_t3 * 16)) / 16384; + var1 = ((int32_t) temp_adc >> 3) - ((int32_t) bme680_data.par_t1 << 1); + var2 = (var1 * (int32_t) bme680_data.par_t2) >> 11; + var3 = ((var1 >> 1) * (var1 >> 1)) >> 12; + var3 = ((var3) * ((int32_t) bme680_data.par_t3 << 4)) >> 14; bme680_data.t_fine = (int32_t) (var2 + var3); - calc_temp = (int16_t) (((bme680_data.t_fine * 5) + 128) / 256); + calc_temp = (int16_t) (((bme680_data.t_fine * 5) + 128) >> 8); return calc_temp; } @@ -188,27 +182,37 @@ static uint32_t calc_pressure(uint32_t pres_adc) int32_t var1; int32_t var2; int32_t var3; - int32_t calc_pres; - - var1 = (((int32_t) bme680_data.t_fine) / 2) - 64000; - var2 = ((var1 / 4) * (var1 / 4)) / 2048; - var2 = ((var2) * (int32_t) bme680_data.par_p6) / 4; - var2 = var2 + ((var1 * (int32_t) bme680_data.par_p5) * 2); - var2 = (var2 / 4) + ((int32_t) bme680_data.par_p4 * 65536); - var1 = ((var1 / 4) * (var1 / 4)) / 8192; - var1 = (((var1) * ((int32_t) bme680_data.par_p3 * 32)) / 8) + (((int32_t) bme680_data.par_p2 * var1) / 2); - var1 = var1 / 262144; - var1 = ((32768 + var1) * (int32_t) bme680_data.par_p1) / 32768; - calc_pres = (int32_t) (1048576 - pres_adc); - calc_pres = (int32_t) ((calc_pres - (var2 / 4096)) * (3125)); - calc_pres = ((calc_pres / var1) * 2); - var1 = ((int32_t) bme680_data.par_p9 * (int32_t) (((calc_pres / 8) * (calc_pres / 8)) / 8192)) / 4096; - var2 = ((int32_t) (calc_pres / 4) * (int32_t) bme680_data.par_p8) / 8192; - var3 = ((int32_t) (calc_pres / 256) * (int32_t) (calc_pres / 256) * (int32_t) (calc_pres / 256) - * (int32_t) bme680_data.par_p10) / 131072; - calc_pres = (int32_t) (calc_pres) + ((var1 + var2 + var3 + ((int32_t) bme680_data.par_p7 * 128)) / 16); - - return (uint32_t) calc_pres; + int32_t pressure_comp; + + var1 = (((int32_t)bme680_data.t_fine) >> 1) - 64000; + var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * + (int32_t)bme680_data.par_p6) >> 2; + var2 = var2 + ((var1 * (int32_t)bme680_data.par_p5) << 1); + var2 = (var2 >> 2) + ((int32_t)bme680_data.par_p4 << 16); + var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * + ((int32_t)bme680_data.par_p3 << 5)) >> 3) + + (((int32_t)bme680_data.par_p2 * var1) >> 1); + var1 = var1 >> 18; + var1 = ((32768 + var1) * (int32_t)bme680_data.par_p1) >> 15; + pressure_comp = 1048576 - pres_adc; + pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125)); + if (pressure_comp >= BME680_MAX_OVERFLOW_VAL) + pressure_comp = ((pressure_comp / var1) << 1); + else + pressure_comp = ((pressure_comp << 1) / var1); + var1 = ((int32_t)bme680_data.par_p9 * (int32_t)(((pressure_comp >> 3) * + (pressure_comp >> 3)) >> 13)) >> 12; + var2 = ((int32_t)(pressure_comp >> 2) * + (int32_t)bme680_data.par_p8) >> 13; + var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) * + (int32_t)(pressure_comp >> 8) * + (int32_t)bme680_data.par_p10) >> 17; + + pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 + + ((int32_t)bme680_data.par_p7 << 7)) >> 4); + + return (uint32_t)pressure_comp; + } static uint32_t calc_humidity(uint16_t hum_adc) @@ -222,19 +226,19 @@ static uint32_t calc_humidity(uint16_t hum_adc) int32_t temp_scaled; int32_t calc_hum; - temp_scaled = (((int32_t) bme680_data.t_fine * 5) + 128) / 256; + temp_scaled = (((int32_t) bme680_data.t_fine * 5) + 128) >> 8; var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) bme680_data.par_h1 * 16))) - - (((temp_scaled * (int32_t) bme680_data.par_h3) / ((int32_t) 100)) / 2); + - (((temp_scaled * (int32_t) bme680_data.par_h3) / ((int32_t) 100)) >> 1); var2 = ((int32_t) bme680_data.par_h2 - * (((temp_scaled * (int32_t) bme680_data.par_h4) / ((int32_t) 100)) - + (((temp_scaled * ((temp_scaled * (int32_t) bme680_data.par_h5) / ((int32_t) 100))) / 64) - / ((int32_t) 100)) + (int32_t) (1 * 16384))) / 1024; + * (((temp_scaled * (int32_t) bme680_data.par_h4) / ((int32_t) 100)) + + (((temp_scaled * ((temp_scaled * (int32_t) bme680_data.par_h5) / ((int32_t) 100))) >> 6) + / ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10; var3 = var1 * var2; - var4 = (int32_t) bme680_data.par_h6 * 128; - var4 = ((var4) + ((temp_scaled * (int32_t) bme680_data.par_h7) / ((int32_t) 100))) / 16; - var5 = ((var3 / 16384) * (var3 / 16384)) / 1024; - var6 = (var4 * var5) / 2; - calc_hum = (((var3 + var6) / 1024) * ((int32_t) 1000)) / 4096; + var4 = (int32_t) bme680_data.par_h6 << 7; + var4 = ((var4) + ((temp_scaled * (int32_t) bme680_data.par_h7) / ((int32_t) 100))) >> 4; + var5 = ((var3 >> 14) * (var3 >> 14)) >> 10; + var6 = (var4 * var5) >> 1; + calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12; if (calc_hum > 100000) /* Cap at 100%rH */ calc_hum = 100000; @@ -244,6 +248,19 @@ static uint32_t calc_humidity(uint16_t hum_adc) return (uint32_t) calc_hum; } + +/**static variables */ + /**Look up table 1 for the possible gas range values */ + uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), + UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777), + UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228), + UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647) }; + /**Look up table 2 for the possible gas range values */ + uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000), + UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016), + UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000), + UINT32_C(250000), UINT32_C(125000) }; + static uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range) { int64_t var1; @@ -251,14 +268,16 @@ static uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range) int64_t var3; uint32_t calc_gas_res; - var1 = (int64_t) ((1340 + (5 * (int64_t) bme680_data.range_sw_err)) * ((int64_t) lookupTable1[gas_range])) / 65536; - var2 = (((int64_t) ((int64_t) gas_res_adc * 32768) - (int64_t) (16777216)) + var1); - var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) / 512); - calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 / 2)) / (int64_t) var2); + var1 = (int64_t) ((1340 + (5 * (int64_t) bme680_data.range_sw_err)) * + ((int64_t) lookupTable1[gas_range])) >> 16; + var2 = (((int64_t) ((int64_t) gas_res_adc << 15) - (int64_t) (16777216)) + var1); + var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) >> 9); + calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 >> 1)) / (int64_t) var2); return calc_gas_res; } + uint16_t calc_dur() { uint32_t tph_dur; /* Calculate in us */ diff --git a/app/modules/bme680_defs.h b/app/modules/bme680_defs.h index 4ef701f6ea..4dfccbebc2 100644 --- a/app/modules/bme680_defs.h +++ b/app/modules/bme680_defs.h @@ -39,78 +39,47 @@ * No license is granted by implication or otherwise under any patent or * patent rights of the copyright holder. * - * @file bme680_defs.h - * @date 5 Jul 2017 - * @version 3.5.1 - * @brief - * + * @file bme680_defs.h + * @date 19 Jun 2018 + * @version 3.5.9 + * @brief Sensor driver for BME680 sensor */ -/*! @file bme680_defs.h - @brief Sensor driver for BME680 sensor */ -/*! - * @defgroup BME680 SENSOR API - * @brief - * @{*/ #ifndef BME680_DEFS_H_ #define BME680_DEFS_H_ -/********************************************************/ -/* header includes */ +/** header includes **/ #ifdef __KERNEL__ #include +#include #else #include +#include #endif -#ifdef __KERNEL__ -#if (LONG_MAX) > 0x7fffffff -#define __have_long64 1 -#elif (LONG_MAX) == 0x7fffffff -#define __have_long32 1 -#endif +/** Common macros **/ -#if !defined(UINT8_C) -#define INT8_C(x) x -#if (INT_MAX) > 0x7f -#define UINT8_C(x) x -#else -#define UINT8_C(x) x##U -#endif +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) S8_C(x) +#define UINT8_C(x) U8_C(x) #endif -#if !defined(UINT16_C) -#define INT16_C(x) x -#if (INT_MAX) > 0x7fff -#define UINT16_C(x) x -#else -#define UINT16_C(x) x##U -#endif +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) S16_C(x) +#define UINT16_C(x) U16_C(x) #endif #if !defined(INT32_C) && !defined(UINT32_C) -#if __have_long32 -#define INT32_C(x) x##L -#define UINT32_C(x) x##UL -#else -#define INT32_C(x) x -#define UINT32_C(x) x##U -#endif +#define INT32_C(x) S32_C(x) +#define UINT32_C(x) U32_C(x) #endif #if !defined(INT64_C) && !defined(UINT64_C) -#if __have_long64 -#define INT64_C(x) x##L -#define UINT64_C(x) x##UL -#else -#define INT64_C(x) x##LL -#define UINT64_C(x) x##ULL -#endif -#endif +#define INT64_C(x) S64_C(x) +#define UINT64_C(x) U64_C(x) #endif -/**@}*/ -/**\name C standard macros */ +/** C standard macros **/ #ifndef NULL #ifdef __cplusplus #define NULL 0 @@ -119,29 +88,35 @@ #endif #endif -/** BME680 General config */ +/** BME680 configuration macros */ +/** Enable or un-comment the macro to provide floating point data output **/ +#ifndef BME680_FLOAT_POINT_COMPENSATION +/* #define BME680_FLOAT_POINT_COMPENSATION **/ +#endif + +/** BME680 General config **/ #define BME680_POLL_PERIOD_MS UINT8_C(10) -/** BME680 I2C addresses */ +/** BME680 I2C addresses **/ #define BME680_I2C_ADDR_PRIMARY UINT8_C(0x76) #define BME680_I2C_ADDR_SECONDARY UINT8_C(0x77) -/** BME680 unique chip identifier */ +/** BME680 unique chip identifier **/ #define BME680_CHIP_ID UINT8_C(0x61) -/** BME680 coefficients related defines */ -#define BME680_COEFF_SIZE UINT8_C(0x41) +/** BME680 coefficients related defines **/ +#define BME680_COEFF_SIZE UINT8_C(41) #define BME680_COEFF_ADDR1_LEN UINT8_C(25) #define BME680_COEFF_ADDR2_LEN UINT8_C(16) -/** BME680 field_x related defines */ +/** BME680 field_x related defines **/ #define BME680_FIELD_LENGTH UINT8_C(15) #define BME680_FIELD_ADDR_OFFSET UINT8_C(17) -/** Soft reset command */ +/** Soft reset command **/ #define BME680_SOFT_RESET_CMD UINT8_C(0xb6) -/** Error code definitions */ +/** Error code definitions **/ #define BME680_OK INT8_C(0) /* Errors */ #define BME680_E_NULL_PTR INT8_C(-1) @@ -157,22 +132,22 @@ #define BME680_I_MIN_CORRECTION UINT8_C(1) #define BME680_I_MAX_CORRECTION UINT8_C(2) -/** Register map */ -/** Other coefficient's address */ +/** Register map **/ +/** Other coefficient's address **/ #define BME680_ADDR_RES_HEAT_VAL_ADDR UINT8_C(0x00) #define BME680_ADDR_RES_HEAT_RANGE_ADDR UINT8_C(0x02) #define BME680_ADDR_RANGE_SW_ERR_ADDR UINT8_C(0x04) #define BME680_ADDR_SENS_CONF_START UINT8_C(0x5A) #define BME680_ADDR_GAS_CONF_START UINT8_C(0x64) -/** Field settings */ +/** Field settings **/ #define BME680_FIELD0_ADDR UINT8_C(0x1d) -/** Heater settings */ +/** Heater settings **/ #define BME680_RES_HEAT0_ADDR UINT8_C(0x5a) #define BME680_GAS_WAIT0_ADDR UINT8_C(0x64) -/** Sensor configuration registers */ +/** Sensor configuration registers **/ #define BME680_CONF_HEAT_CTRL_ADDR UINT8_C(0x70) #define BME680_CONF_ODR_RUN_GAS_NBC_ADDR UINT8_C(0x71) #define BME680_CONF_OS_H_ADDR UINT8_C(0x72) @@ -180,25 +155,25 @@ #define BME680_CONF_T_P_MODE_ADDR UINT8_C(0x74) #define BME680_CONF_ODR_FILT_ADDR UINT8_C(0x75) -/** Coefficient's address */ +/** Coefficient's address **/ #define BME680_COEFF_ADDR1 UINT8_C(0x89) #define BME680_COEFF_ADDR2 UINT8_C(0xe1) -/** Chip identifier */ +/** Chip identifier **/ #define BME680_CHIP_ID_ADDR UINT8_C(0xd0) -/** Soft reset register */ +/** Soft reset register **/ #define BME680_SOFT_RESET_ADDR UINT8_C(0xe0) -/** Heater control settings */ +/** Heater control settings **/ #define BME680_ENABLE_HEATER UINT8_C(0x00) #define BME680_DISABLE_HEATER UINT8_C(0x08) -/** Gas measurement settings */ +/** Gas measurement settings **/ #define BME680_DISABLE_GAS_MEAS UINT8_C(0x00) #define BME680_ENABLE_GAS_MEAS UINT8_C(0x01) -/** Over-sampling settings */ +/** Over-sampling settings **/ #define BME680_OS_NONE UINT8_C(0) #define BME680_OS_1X UINT8_C(1) #define BME680_OS_2X UINT8_C(2) @@ -206,7 +181,7 @@ #define BME680_OS_8X UINT8_C(4) #define BME680_OS_16X UINT8_C(5) -/** IIR filter settings */ +/** IIR filter settings **/ #define BME680_FILTER_SIZE_0 UINT8_C(0) #define BME680_FILTER_SIZE_1 UINT8_C(1) #define BME680_FILTER_SIZE_3 UINT8_C(2) @@ -220,28 +195,27 @@ #define BME680_SLEEP_MODE UINT8_C(0) #define BME680_FORCED_MODE UINT8_C(1) -/** Delay related macro declaration */ -#define BME680_RESET_PERIOD UINT32_C(10) +/** Delay related macro declaration **/ +#define BME680_RESET_PERIOD UINT32_C(10) -/** SPI memory page settings */ +/** SPI memory page settings **/ #define BME680_MEM_PAGE0 UINT8_C(0x10) #define BME680_MEM_PAGE1 UINT8_C(0x00) -/** Ambient humidity shift value for compensation */ +/** Ambient humidity shift value for compensation **/ #define BME680_HUM_REG_SHIFT_VAL UINT8_C(4) -/** Run gas enable and disable settings */ +/** Run gas enable and disable settings **/ #define BME680_RUN_GAS_DISABLE UINT8_C(0) #define BME680_RUN_GAS_ENABLE UINT8_C(1) -/** Buffer length macro declaration */ +/** Buffer length macro declaration **/ #define BME680_TMP_BUFFER_LENGTH UINT8_C(40) #define BME680_REG_BUFFER_LENGTH UINT8_C(6) #define BME680_FIELD_DATA_LENGTH UINT8_C(3) #define BME680_GAS_REG_BUF_LENGTH UINT8_C(20) -#define BME680_GAS_HEATER_PROF_LEN_MAX UINT8_C(10) -/** Settings selector */ +/** Settings selector **/ #define BME680_OST_SEL UINT16_C(1) #define BME680_OSP_SEL UINT16_C(2) #define BME680_OSH_SEL UINT16_C(4) @@ -250,13 +224,13 @@ #define BME680_HCNTRL_SEL UINT16_C(32) #define BME680_RUN_GAS_SEL UINT16_C(64) #define BME680_NBCONV_SEL UINT16_C(128) -#define BME680_GAS_SENSOR_SEL UINT16_C(BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL) +#define BME680_GAS_SENSOR_SEL (BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL) -/** Number of conversion settings*/ +/** Number of conversion settings **/ #define BME680_NBCONV_MIN UINT8_C(0) #define BME680_NBCONV_MAX UINT8_C(10) -/** Mask definitions */ +/** Mask definitions **/ #define BME680_GAS_MEAS_MSK UINT8_C(0x30) #define BME680_NBCONV_MSK UINT8_C(0X0F) #define BME680_FILTER_MSK UINT8_C(0X1C) @@ -278,14 +252,14 @@ #define BME680_SPI_WR_MSK UINT8_C(0x7f) #define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F) -/** Bit position definitions for sensor settings */ +/** Bit position definitions for sensor settings **/ #define BME680_GAS_MEAS_POS UINT8_C(4) #define BME680_FILTER_POS UINT8_C(2) #define BME680_OST_POS UINT8_C(5) #define BME680_OSP_POS UINT8_C(2) #define BME680_RUN_GAS_POS UINT8_C(4) -/** Array Index to Field data mapping for Calibration Data*/ +/** Array Index to Field data mapping for Calibration Data **/ #define BME680_T2_LSB_REG (1) #define BME680_T2_MSB_REG (2) #define BME680_T3_REG (3) @@ -321,7 +295,7 @@ #define BME680_GH1_REG (37) #define BME680_GH3_REG (38) -/** BME680 register buffer index settings*/ +/** BME680 register buffer index settings **/ #define BME680_REG_FILTER_INDEX UINT8_C(5) #define BME680_REG_TEMP_INDEX UINT8_C(4) #define BME680_REG_PRES_INDEX UINT8_C(4) @@ -330,38 +304,51 @@ #define BME680_REG_RUN_GAS_INDEX UINT8_C(1) #define BME680_REG_HCTRL_INDEX UINT8_C(0) -/** Macro to combine two 8 bit data's to form a 16 bit data */ +/** BME680 pressure calculation macros **/ +/*! This max value is used to provide precedence to multiplication or division + * in pressure compensation equation to achieve least loss of precision and + * avoiding overflows. + * i.e Comparing value, BME680_MAX_OVERFLOW_VAL = INT32_C(1 << 30) + */ +#define BME680_MAX_OVERFLOW_VAL INT32_C(0x40000000) + +/** Macro to combine two 8 bit data's to form a 16 bit data **/ #define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) -/** Macro to SET and GET BITS of a register */ +/** Macro to SET and GET BITS of a register **/ #define BME680_SET_BITS(reg_data, bitname, data) \ ((reg_data & ~(bitname##_MSK)) | \ ((data << bitname##_POS) & bitname##_MSK)) #define BME680_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \ (bitname##_POS)) -/** Macro variant to handle the bitname position if it is zero */ +/** Macro variant to handle the bitname position if it is zero **/ #define BME680_SET_BITS_POS_0(reg_data, bitname, data) \ ((reg_data & ~(bitname##_MSK)) | \ (data & bitname##_MSK)) #define BME680_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) -/** Type definitions */ -/* - * Generic communication function pointer - * @param[in] dev_id: Place holder to store the id of the device structure - * Can be used to store the index of the Chip select or - * I2C address of the device. - * @param[in] reg_addr: Used to select the register the where data needs to - * be read from or written to. - * @param[in/out] reg_data: Data array to read/write - * @param[in] len: Length of the data array +/** Type definitions **/ +/*! + * @brief Generic communication function pointer + * @param[in] dev_id + * Place holder to store the id of the device structure + * Can be used to store the index of the Chip select or + * I2C address of the device. + * @param[in] reg_addr + * Used to select the register the where data needs to + * be read from or written to. + * @param[in/out] reg_data + * Data array to read/write + * @param[in] len + * Length of the data array */ typedef int8_t (*bme680_com_fptr_t)(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len); -/* - * Delay function pointer - * @param[in] period: Time period in milliseconds +/*! + * @brief Delay function pointer + * @param[in] period + * Time period in milliseconds */ typedef void (*bme680_delay_fptr_t)(uint32_t period); @@ -375,7 +362,7 @@ enum bme680_intf { BME680_I2C_INTF }; -/* structure definitions */ +/** structure definitions **/ /*! * @brief Sensor field data structure */ @@ -386,6 +373,8 @@ struct bme680_field_data { uint8_t gas_index; /*! Measurement index to track order */ uint8_t meas_index; + +#ifndef BME680_FLOAT_POINT_COMPENSATION /*! Temperature in degree celsius x100 */ int16_t temperature; /*! Pressure in Pascal */ @@ -394,6 +383,18 @@ struct bme680_field_data { uint32_t humidity; /*! Gas resistance in Ohms */ uint32_t gas_resistance; +#else + /*! Temperature in degree celsius */ + float temperature; + /*! Pressure in Pascal */ + float pressure; + /*! Humidity in % relative humidity x1000 */ + float humidity; + /*! Gas resistance in Ohms */ + float gas_resistance; + +#endif + }; /*! @@ -446,8 +447,14 @@ struct bme680_calib_data { int16_t par_p9; /*! Variable to store calibrated pressure data */ uint8_t par_p10; + +#ifndef BME680_FLOAT_POINT_COMPENSATION /*! Variable to store t_fine size */ int32_t t_fine; +#else + /*! Variable to store t_fine size */ + float t_fine; +#endif /*! Variable to store heater resistance range */ uint8_t res_heat_range; /*! Variable to store heater resistance value */ @@ -458,7 +465,7 @@ struct bme680_calib_data { /*! * @brief BME680 sensor settings structure which comprises of ODR, - * over-sampling and filter settings. + * over-sampling and filter settings. */ struct bme680_tph_sett { /*! Humidity oversampling */ @@ -473,7 +480,7 @@ struct bme680_tph_sett { /*! * @brief BME680 gas sensor which comprises of gas settings - * and status parameters + * and status parameters */ struct bme680_gas_sett { /*! Variable to store nb conversion */ @@ -482,9 +489,9 @@ struct bme680_gas_sett { uint8_t heatr_ctrl; /*! Run gas enable value */ uint8_t run_gas; - /*! Pointer to store heater temperature */ + /*! Heater temperature value */ uint16_t heatr_temp; - /*! Pointer to store duration profile */ + /*! Duration profile value */ uint16_t heatr_dur; }; @@ -500,7 +507,7 @@ struct bme680_dev { enum bme680_intf intf; /*! Memory page used */ uint8_t mem_page; - /*! Ambient temperature in Degree C*/ + /*! Ambient temperature in Degree C */ int8_t amb_temp; /*! Sensor calibration data */ struct bme680_calib_data calib; @@ -514,16 +521,18 @@ struct bme680_dev { uint8_t new_fields; /*! Store the info messages */ uint8_t info_msg; - /*! Burst read structure */ + /*! Bus read function pointer */ bme680_com_fptr_t read; - /*! Burst write structure */ + /*! Bus write function pointer */ bme680_com_fptr_t write; - /*! Delay in ms */ + /*! delay function pointer */ bme680_delay_fptr_t delay_ms; /*! Communication function result */ int8_t com_rslt; }; + + #endif /* BME680_DEFS_H_ */ /** @}*/ /** @}*/ From b179f30ef676a557837b5620ab2664198e03cca5 Mon Sep 17 00:00:00 2001 From: Gregor Hartmann Date: Mon, 9 Dec 2019 13:30:09 +0100 Subject: [PATCH 16/59] Fixes for `ws2812` and `ws2812_effects` (#2953) * clean effects library * Fix several issues in ws2812 and effects * Implement working way of calling shift from callback --- .gitignore | 1 + app/modules/ws2812.c | 121 ++++++------ app/modules/ws2812.h | 25 ++- app/modules/ws2812_effects.c | 279 ++++++++++++++-------------- lua_tests/mispec.lua | 159 ++++++++++++++++ lua_tests/mispec_ws2812.lua | 153 +++++++++++++++ lua_tests/mispec_ws2812_2.lua | 149 +++++++++++++++ lua_tests/mispec_ws2812_effects.lua | 31 ++++ 8 files changed, 721 insertions(+), 197 deletions(-) create mode 100644 lua_tests/mispec.lua create mode 100644 lua_tests/mispec_ws2812.lua create mode 100644 lua_tests/mispec_ws2812_2.lua create mode 100644 lua_tests/mispec_ws2812_effects.lua diff --git a/.gitignore b/.gitignore index 736ae691be..62f8d18182 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ tools/toolchains/ .project .settings/ .vscode +.vs #ignore temp file for build infos buildinfo.h diff --git a/app/modules/ws2812.c b/app/modules/ws2812.c index fa892079c0..8f9e6c4195 100644 --- a/app/modules/ws2812.c +++ b/app/modules/ws2812.c @@ -16,10 +16,6 @@ #define MODE_DUAL 1 - - - - // Init UART1 to be able to stream WS2812 data to GPIO2 pin // If DUAL mode is selected, init UART0 to stream to TXD0 as well // You HAVE to redirect LUA's output somewhere else @@ -168,15 +164,15 @@ static int ws2812_write(lua_State* L) { return 0; } -static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { +static ptrdiff_t posrelat(ptrdiff_t pos, size_t len) { /* relative string position: negative means back from end */ if (pos < 0) pos += (ptrdiff_t)len + 1; - return (pos >= 0) ? pos : 0; + return MIN(MAX(pos, 1), len); } static ws2812_buffer *allocate_buffer(lua_State *L, int leds, int colorsPerLed) { // Allocate memory - size_t size = sizeof(ws2812_buffer) + colorsPerLed*leds*sizeof(uint8_t); + size_t size = sizeof(ws2812_buffer) + colorsPerLed*leds; ws2812_buffer * buffer = (ws2812_buffer*)lua_newuserdata(L, size); // Associate its metatable @@ -245,17 +241,11 @@ static int ws2812_buffer_fill_lua(lua_State* L) { return 0; } -static int ws2812_buffer_fade(lua_State* L) { - ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer"); - const int fade = luaL_checkinteger(L, 2); - unsigned direction = luaL_optinteger( L, 3, FADE_OUT ); - - luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number"); - +void ws2812_buffer_fade(ws2812_buffer * buffer, int fade, unsigned direction) { uint8_t * p = &buffer->values[0]; int val = 0; int i; - for(i = 0; i < buffer->size * buffer->colorsPerLed; i++) + for (i = 0; i < buffer->size * buffer->colorsPerLed; i++) { if (direction == FADE_OUT) { @@ -269,78 +259,101 @@ static int ws2812_buffer_fade(lua_State* L) { *p++ = val; } } +} - return 0; +static int ws2812_buffer_fade_lua(lua_State* L) { + ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer"); + const int fade = luaL_checkinteger(L, 2); + unsigned direction = luaL_optinteger( L, 3, FADE_OUT ); + + luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number"); + + ws2812_buffer_fade(buffer, fade, direction); + + return 0; } +int ws2812_buffer_shift(lua_State* L, ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end){ + + ws2812_buffer_shift_prepare* prepare = ws2812_buffer_get_shift_prepare(L, buffer, shiftValue, shift_type, pos_start, pos_end); + ws2812_buffer_shift_prepared(prepare); + // Free memory + luaM_free(L, prepare); + return 0; +} -int ws2812_buffer_shift(ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end) { +ws2812_buffer_shift_prepare* ws2812_buffer_get_shift_prepare(lua_State* L, ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end){ ptrdiff_t start = posrelat(pos_start, buffer->size); ptrdiff_t end = posrelat(pos_end, buffer->size); - if (start < 1) start = 1; - if (end > (ptrdiff_t)buffer->size) end = (ptrdiff_t)buffer->size; start--; int size = end - start; size_t offset = start * buffer->colorsPerLed; - //luaL_argcheck(L, shiftValue > 0-size && shiftValue < size, 2, "shifting more elements than buffer size"); + luaL_argcheck(L, shiftValue >= 0-size && shiftValue <= size, 2, "shifting more elements than buffer size"); int shift = shiftValue >= 0 ? shiftValue : -shiftValue; - // check if we want to shift at all - if (shift == 0 || size <= 0) - { - return 0; - } - - uint8_t * tmp_pixels = malloc(buffer->colorsPerLed * sizeof(uint8_t) * shift); - int i,j; size_t shift_len, remaining_len; // calculate length of shift section and remaining section shift_len = shift*buffer->colorsPerLed; remaining_len = (size-shift)*buffer->colorsPerLed; - if (shiftValue > 0) + ws2812_buffer_shift_prepare* prepare = luaM_malloc(L, sizeof(ws2812_buffer_shift_prepare) + shift_len); + prepare->offset = offset; + prepare->tmp_pixels = (uint8_t*)(prepare+1); + prepare->shiftValue = shiftValue; + prepare->shift_len = shift_len; + prepare->remaining_len = remaining_len; + prepare->shift_type = shift_type; + prepare->buffer = buffer; + + return prepare; +} + +void ws2812_buffer_shift_prepared(ws2812_buffer_shift_prepare* prepare) { + + // check if we want to shift at all + if (prepare->shift_len == 0 || (prepare->shift_len + prepare->remaining_len) <= 0) + { + return; + } + + if (prepare->shiftValue > 0) { // Store the values which are moved out of the array (last n pixels) - memcpy(tmp_pixels, &buffer->values[offset + (size-shift)*buffer->colorsPerLed], shift_len); + memcpy(prepare->tmp_pixels, &prepare->buffer->values[prepare->offset + prepare->remaining_len], prepare->shift_len); // Move pixels to end - os_memmove(&buffer->values[offset + shift*buffer->colorsPerLed], &buffer->values[offset], remaining_len); + os_memmove(&prepare->buffer->values[prepare->offset + prepare->shift_len], &prepare->buffer->values[prepare->offset], prepare->remaining_len); // Fill beginning with temp data - if (shift_type == SHIFT_LOGICAL) + if (prepare->shift_type == SHIFT_LOGICAL) { - memset(&buffer->values[offset], 0, shift_len); + memset(&prepare->buffer->values[prepare->offset], 0, prepare->shift_len); } else { - memcpy(&buffer->values[offset], tmp_pixels, shift_len); + memcpy(&prepare->buffer->values[prepare->offset], prepare->tmp_pixels, prepare->shift_len); } } else { // Store the values which are moved out of the array (last n pixels) - memcpy(tmp_pixels, &buffer->values[offset], shift_len); + memcpy(prepare->tmp_pixels, &prepare->buffer->values[prepare->offset], prepare->shift_len); // Move pixels to end - os_memmove(&buffer->values[offset], &buffer->values[offset + shift*buffer->colorsPerLed], remaining_len); + os_memmove(&prepare->buffer->values[prepare->offset], &prepare->buffer->values[prepare->offset + prepare->shift_len], prepare->remaining_len); // Fill beginning with temp data - if (shift_type == SHIFT_LOGICAL) + if (prepare->shift_type == SHIFT_LOGICAL) { - memset(&buffer->values[offset + (size-shift)*buffer->colorsPerLed], 0, shift_len); + memset(&prepare->buffer->values[prepare->offset + prepare->remaining_len], 0, prepare->shift_len); } else { - memcpy(&buffer->values[offset + (size-shift)*buffer->colorsPerLed], tmp_pixels, shift_len); + memcpy(&prepare->buffer->values[prepare->offset + prepare->remaining_len], prepare->tmp_pixels, prepare->shift_len); } } - // Free memory - free(tmp_pixels); - - return 0; } - static int ws2812_buffer_shift_lua(lua_State* L) { ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer"); @@ -351,11 +364,10 @@ static int ws2812_buffer_shift_lua(lua_State* L) { const int pos_end = luaL_optinteger(L, 5, -1); - ws2812_buffer_shift(buffer, shiftValue, shift_type, pos_start, pos_end); + ws2812_buffer_shift(L, buffer, shiftValue, shift_type, pos_start, pos_end); return 0; } - static int ws2812_buffer_dump(lua_State* L) { ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer"); @@ -366,8 +378,7 @@ static int ws2812_buffer_dump(lua_State* L) { static int ws2812_buffer_replace(lua_State* L) { ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer"); - size_t l = buffer->size; - ptrdiff_t start = posrelat(luaL_optinteger(L, 3, 1), l); + ptrdiff_t start = posrelat(luaL_optinteger(L, 3, 1), buffer->size); uint8_t *src; size_t srcLen; @@ -425,8 +436,8 @@ static int ws2812_buffer_mix(lua_State* L) { val += (int32_t)(source[src].values[i] * source[src].factor); } - val += 128; // rounding istead of floor - val >>= 8; + val += 128; // rounding istead of floor + val /= 256; // do not use implemetation dependant right shift if (val < 0) { val = 0; @@ -501,7 +512,7 @@ static int ws2812_buffer_set(lua_State* L) { // Overflow check if( buffer->colorsPerLed*led + len > buffer->colorsPerLed*buffer->size ) { - return luaL_error(L, "string size will exceed strip length"); + return luaL_error(L, "string size will exceed strip length"); } memcpy(&buffer->values[buffer->colorsPerLed*led], buf, len); @@ -531,8 +542,6 @@ static int ws2812_buffer_sub(lua_State* L) { size_t l = lhs->size; ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; if (start <= end) { ws2812_buffer *result = allocate_buffer(L, end - start + 1, lhs->colorsPerLed); memcpy(result->values, lhs->values + lhs->colorsPerLed * (start - 1), lhs->colorsPerLed * (end - start + 1)); @@ -591,10 +600,9 @@ static int ws2812_buffer_tostring(lua_State* L) { return 1; } - LROT_BEGIN(ws2812_buffer) LROT_FUNCENTRY( dump, ws2812_buffer_dump ) - LROT_FUNCENTRY( fade, ws2812_buffer_fade ) + LROT_FUNCENTRY( fade, ws2812_buffer_fade_lua) LROT_FUNCENTRY( fill, ws2812_buffer_fill_lua ) LROT_FUNCENTRY( get, ws2812_buffer_get ) LROT_FUNCENTRY( replace, ws2812_buffer_replace ) @@ -609,8 +617,6 @@ LROT_BEGIN(ws2812_buffer) LROT_FUNCENTRY( __tostring, ws2812_buffer_tostring ) LROT_END( ws2812_buffer, ws2812_buffer, LROT_MASK_INDEX ) - - LROT_BEGIN(ws2812) LROT_FUNCENTRY( init, ws2812_init ) LROT_FUNCENTRY( newBuffer, ws2812_new_buffer ) @@ -623,7 +629,6 @@ LROT_BEGIN(ws2812) LROT_NUMENTRY( SHIFT_CIRCULAR, SHIFT_CIRCULAR ) LROT_END( ws2812, NULL, 0 ) - int luaopen_ws2812(lua_State *L) { // TODO: Make sure that the GPIO system is initialized luaL_rometatable(L, "ws2812.buffer", LROT_TABLEREF(ws2812_buffer)); diff --git a/app/modules/ws2812.h b/app/modules/ws2812.h index 9b31910f62..95fd3f0292 100644 --- a/app/modules/ws2812.h +++ b/app/modules/ws2812.h @@ -17,6 +17,12 @@ #define SHIFT_LOGICAL 0 #define SHIFT_CIRCULAR 1 +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif typedef struct { int size; @@ -24,9 +30,26 @@ typedef struct { uint8_t values[0]; } ws2812_buffer; +typedef struct { + size_t offset; + uint8_t* tmp_pixels; + int shiftValue; + size_t shift_len; + size_t remaining_len; + unsigned shift_type; + ws2812_buffer* buffer; +} ws2812_buffer_shift_prepare; + void ICACHE_RAM_ATTR ws2812_write_data(const uint8_t *pixels, uint32_t length, const uint8_t *pixels2, uint32_t length2); -int ws2812_buffer_shift(ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end); +// To shift the lua_State is needed for error message and memory allocation. +// We also need the shift operation inside a timer callback, where we cannot access the lua_State, +// so This is split up in prepare and the actual call, which can be called multiple times with the same prepare object. +// After being done just luaM_free on the prepare object. +void ws2812_buffer_shift_prepared(ws2812_buffer_shift_prepare* prepare); +ws2812_buffer_shift_prepare* ws2812_buffer_get_shift_prepare(lua_State* L, ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end); + int ws2812_buffer_fill(ws2812_buffer * buffer, int * colors); +void ws2812_buffer_fade(ws2812_buffer * buffer, int fade, unsigned direction); #endif /* APP_MODULES_WS2812_H_ */ diff --git a/app/modules/ws2812_effects.c b/app/modules/ws2812_effects.c index e53676becf..7e30dabca7 100644 --- a/app/modules/ws2812_effects.c +++ b/app/modules/ws2812_effects.c @@ -38,6 +38,10 @@ #define min3(a,b, c) min((a), min((b), (c))) #define max3(a,b, c) max((a), max((b), (c))) +#define IDX_R 1 +#define IDX_G 0 +#define IDX_B 2 +#define IDX_W 3 typedef struct { @@ -54,6 +58,7 @@ typedef struct { uint8_t effect_type; uint8_t color[4]; int effect_int_param1; + ws2812_buffer_shift_prepare* prepare; } ws2812_effects; @@ -91,9 +96,6 @@ static int ws2812_write(ws2812_buffer* buffer) { size_t length1, length2; const char *buffer1, *buffer2; - buffer1 = 0; - length1 = 0; - buffer1 = buffer->values; length1 = buffer->colorsPerLed*buffer->size; @@ -115,11 +117,11 @@ static int ws2812_set_pixel(int pixel, uint32_t color) { uint8_t w = buffer->colorsPerLed == 4 ? ((color & 0xFF000000) >> 24) : 0; int offset = pixel * buffer->colorsPerLed; - buffer->values[offset] = g; - buffer->values[offset+1] = r; - buffer->values[offset+2] = b; + buffer->values[offset+IDX_R] = r; + buffer->values[offset+IDX_G] = g; + buffer->values[offset+IDX_B] = b; if (buffer->colorsPerLed == 4) { - buffer->values[offset+3] = w; + buffer->values[offset+IDX_W] = w; } return 0; @@ -158,12 +160,14 @@ static int ws2812_effects_init(lua_State *L) { luaL_argcheck(L, buffer != NULL, 1, "no valid buffer provided"); // get rid of old state if (state != NULL) { + if (state->prepare) { + luaM_free(L, state->prepare); + } luaL_unref(L, LUA_REGISTRYINDEX, state->buffer_ref); free((void *) state); } // Allocate memory and set all to zero - size_t size = sizeof(ws2812_effects) + buffer->colorsPerLed*sizeof(uint8_t); - state = (ws2812_effects *) calloc(1,size); + state = (ws2812_effects *) calloc(1,sizeof(ws2812_effects)); // initialize state->speed = SPEED_DEFAULT; state->mode_delay = DELAY_DEFAULT; @@ -203,10 +207,10 @@ static int ws2812_effects_get_speed(lua_State* L) { } static int ws2812_effects_set_speed(lua_State* L) { - uint8_t speed = luaL_checkinteger(L, 1); + int speed = luaL_checkinteger(L, 1); luaL_argcheck(L, state != NULL, 1, LIBRARY_NOT_INITIALIZED_ERROR_MSG); - luaL_argcheck(L, speed >= 0 && speed <= 255, 1, "should be a 0-255"); - state->speed = speed; + luaL_argcheck(L, speed >= SPEED_MIN && speed <= SPEED_MAX, 1, "should be 0-255"); + state->speed = (uint8_t)speed; state->mode_delay = 10; return 0; } @@ -230,37 +234,35 @@ static int ws2812_effects_set_delay(lua_State* L) { static int ws2812_effects_set_brightness(lua_State* L) { - uint8_t brightness = luaL_checkint(L, 1); + int brightness = luaL_checkint(L, 1); luaL_argcheck(L, state != NULL, 1, LIBRARY_NOT_INITIALIZED_ERROR_MSG); - luaL_argcheck(L, brightness >= 0 && brightness < 256, 1, "should be a 0-255"); - state->brightness = brightness; + luaL_argcheck(L, brightness >= BRIGHTNESS_MIN && brightness <= BRIGHTNESS_MAX, 1, "should be 0-255"); + state->brightness = (uint8_t) brightness; return 0; } -static int ws2812_effects_fill_buffer(uint32_t color) { +static void ws2812_effects_fill_buffer(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { ws2812_buffer * buffer = state->buffer; - uint8_t g = ((color & 0x00FF0000) >> 16); - uint8_t r = ((color & 0x0000FF00) >> 8); - uint8_t b = (color & 0x000000FF); - uint8_t w = buffer->colorsPerLed == 4 ? ((color & 0xFF000000) >> 24) : 0; + uint8_t bright_g = g * state->brightness / BRIGHTNESS_MAX; + uint8_t bright_r = r * state->brightness / BRIGHTNESS_MAX; + uint8_t bright_b = b * state->brightness / BRIGHTNESS_MAX; + uint8_t bright_w = w * state->brightness / BRIGHTNESS_MAX; // Fill buffer int i; uint8_t * p = &buffer->values[0]; for(i = 0; i < buffer->size; i++) { - *p++ = g * state->brightness / 255; - *p++ = r * state->brightness / 255; - *p++ = b * state->brightness / 255; + *p++ = bright_g; + *p++ = bright_r; + *p++ = bright_b; if (buffer->colorsPerLed == 4) { - *p++ = w * state->brightness / 255; + *p++ = bright_w; } } - - return 0; } @@ -279,9 +281,7 @@ static int ws2812_effects_fill_color() { uint8_t b = state->color[2]; uint8_t w = state->color[3]; - uint32_t color = (w << 24) | (g << 16) | (r << 8) | b; - - ws2812_effects_fill_buffer(color); + ws2812_effects_fill_buffer(r, g, b, w); return 0; } @@ -302,7 +302,7 @@ static int ws2812_effects_mode_blink() { // on ws2812_effects_fill_color(); } - else { + else { // off ws2812_buffer * buffer = state->buffer; memset(&buffer->values[0], 0, buffer->size * buffer->colorsPerLed); @@ -383,9 +383,9 @@ static int ws2812_effects_gradient(const char *gradient_spec, size_t length1) { // convert to RGB uint32_t grb = hsv2grb(h, s, v); - *p++ = ((grb & 0x00FF0000) >> 16) * state->brightness / 255; - *p++ = ((grb & 0x0000FF00) >> 8) * state->brightness / 255; - *p++ = (grb & 0x000000FF) * state->brightness / 255; + *p++ = ((grb & 0x00FF0000) >> 16) * state->brightness / BRIGHTNESS_MAX; + *p++ = ((grb & 0x0000FF00) >> 8) * state->brightness / BRIGHTNESS_MAX; + *p++ = (grb & 0x000000FF) * state->brightness / BRIGHTNESS_MAX; for (j = 3; j < buffer->colorsPerLed; j++) { *p++ = 0; @@ -442,9 +442,9 @@ static int ws2812_effects_gradient_rgb(const char *buffer1, size_t length1) { int steps = numPixels - 1; for(i = 0; i < numPixels; i++) { - *p++ = (g1 + ((g2-g1) * i / steps)) * state->brightness / 255; - *p++ = (r1 + ((r2-r1) * i / steps)) * state->brightness / 255; - *p++ = (b1 + ((b2-b1) * i / steps)) * state->brightness / 255; + *p++ = (g1 + ((g2-g1) * i / steps)) * state->brightness / BRIGHTNESS_MAX; + *p++ = (r1 + ((r2-r1) * i / steps)) * state->brightness / BRIGHTNESS_MAX; + *p++ = (b1 + ((b2-b1) * i / steps)) * state->brightness / BRIGHTNESS_MAX; for (j = 3; j < buffer->colorsPerLed; j++) { *p++ = 0; @@ -465,9 +465,9 @@ static int ws2812_effects_mode_random_color() { ws2812_buffer * buffer = state->buffer; uint32_t color = color_wheel(state->mode_color_index); - uint8_t r = ((color & 0x00FF0000) >> 16) * state->brightness / 255; - uint8_t g = ((color & 0x0000FF00) >> 8) * state->brightness / 255; - uint8_t b = ((color & 0x000000FF) >> 0) * state->brightness / 255; + uint8_t r = ((color & 0x00FF0000) >> 16) * state->brightness / BRIGHTNESS_MAX; + uint8_t g = ((color & 0x0000FF00) >> 8) * state->brightness / BRIGHTNESS_MAX; + uint8_t b = ((color & 0x000000FF) >> 0) * state->brightness / BRIGHTNESS_MAX; // Fill buffer int i,j; @@ -500,9 +500,9 @@ static int ws2812_effects_mode_rainbow() { int i,j; uint8_t * p = &buffer->values[0]; for(i = 0; i < buffer->size; i++) { - *p++ = g * state->brightness / 255; - *p++ = r * state->brightness / 255; - *p++ = b * state->brightness / 255; + *p++ = g * state->brightness / BRIGHTNESS_MAX; + *p++ = r * state->brightness / BRIGHTNESS_MAX; + *p++ = b * state->brightness / BRIGHTNESS_MAX; for (j = 3; j < buffer->colorsPerLed; j++) { *p++ = 0; @@ -526,9 +526,9 @@ static int ws2812_effects_mode_rainbow_cycle(int repeat_count) { for(i = 0; i < buffer->size; i++) { uint16_t wheel_index = (i * 360 / buffer->size * repeat_count) % 360; uint32_t color = color_wheel(wheel_index); - uint8_t r = ((color & 0x00FF0000) >> 16) * state->brightness / 255; - uint8_t g = ((color & 0x0000FF00) >> 8) * state->brightness / 255; - uint8_t b = ((color & 0x000000FF) >> 0) * state->brightness / 255; + uint8_t r = ((color & 0x00FF0000) >> 16) * state->brightness / BRIGHTNESS_MAX; + uint8_t g = ((color & 0x0000FF00) >> 8) * state->brightness / BRIGHTNESS_MAX; + uint8_t b = ((color & 0x000000FF) >> 0) * state->brightness / BRIGHTNESS_MAX; *p++ = g; *p++ = r; *p++ = b; @@ -565,9 +565,9 @@ static int ws2812_effects_mode_flicker_int(uint8_t max_flicker) { if(g1<0) g1=0; if(r1<0) r1=0; if(b1<0) b1=0; - *p++ = g1 * state->brightness / 255; - *p++ = r1 * state->brightness / 255; - *p++ = b1 * state->brightness / 255; + *p++ = g1 * state->brightness / BRIGHTNESS_MAX; + *p++ = r1 * state->brightness / BRIGHTNESS_MAX; + *p++ = b1 * state->brightness / BRIGHTNESS_MAX; for (j = 3; j < buffer->colorsPerLed; j++) { *p++ = 0; } @@ -582,13 +582,13 @@ static int ws2812_effects_mode_flicker_int(uint8_t max_flicker) { static int ws2812_effects_mode_halloween() { ws2812_buffer * buffer = state->buffer; - int g1 = 50 * state->brightness / 255; - int r1 = 255 * state->brightness / 255; - int b1 = 0 * state->brightness / 255; + int g1 = 50 * state->brightness / BRIGHTNESS_MAX; + int r1 = 255 * state->brightness / BRIGHTNESS_MAX; + int b1 = 0 * state->brightness / BRIGHTNESS_MAX; - int g2 = 0 * state->brightness / 255; - int r2 = 255 * state->brightness / 255; - int b2 = 130 * state->brightness / 255; + int g2 = 0 * state->brightness / BRIGHTNESS_MAX; + int r2 = 255 * state->brightness / BRIGHTNESS_MAX; + int b2 = 130 * state->brightness / BRIGHTNESS_MAX; // Fill buffer @@ -612,13 +612,13 @@ static int ws2812_effects_mode_halloween() { static int ws2812_effects_mode_circus_combustus() { ws2812_buffer * buffer = state->buffer; - int g1 = 0 * state->brightness / 255; - int r1 = 255 * state->brightness / 255; - int b1 = 0 * state->brightness / 255; + int g1 = 0 * state->brightness / BRIGHTNESS_MAX; + int r1 = 255 * state->brightness / BRIGHTNESS_MAX; + int b1 = 0 * state->brightness / BRIGHTNESS_MAX; - int g2 = 255 * state->brightness / 255; - int r2 = 255 * state->brightness / 255; - int b2 = 255 * state->brightness / 255; + int g2 = 255 * state->brightness / BRIGHTNESS_MAX; + int r2 = 255 * state->brightness / BRIGHTNESS_MAX; + int b2 = 255 * state->brightness / BRIGHTNESS_MAX; // Fill buffer int i,j; @@ -659,9 +659,7 @@ static int ws2812_effects_mode_larson_scanner() { ws2812_buffer * buffer = state->buffer; int led_index = 0; - for(int i=0; i < buffer->size * buffer->colorsPerLed; i++) { - buffer->values[i] = buffer->values[i] >> 1; - } + ws2812_buffer_fade(buffer, 2, FADE_OUT); uint16_t pos = 0; @@ -694,9 +692,9 @@ static int ws2812_effects_mode_color_wipe() { } else { - uint8_t px_r = state->color[1] * state->brightness / 255; - uint8_t px_g = state->color[0] * state->brightness / 255; - uint8_t px_b = state->color[2] * state->brightness / 255; + uint8_t px_r = state->color[1] * state->brightness / BRIGHTNESS_MAX; + uint8_t px_g = state->color[0] * state->brightness / BRIGHTNESS_MAX; + uint8_t px_b = state->color[2] * state->brightness / BRIGHTNESS_MAX; buffer->values[led_index] = px_g; buffer->values[led_index + 1] = px_r; buffer->values[led_index + 2] = px_b; @@ -769,9 +767,8 @@ static uint32_t ws2812_effects_mode_delay() /** * run loop for the effects. */ -static void ws2812_effects_loop(void *p) +static void ws2812_effects_loop(void* p) { - if (state->effect_type == WS2812_EFFECT_BLINK) { ws2812_effects_mode_blink(); @@ -783,7 +780,7 @@ static void ws2812_effects_loop(void *p) else if (state->effect_type == WS2812_EFFECT_RAINBOW_CYCLE) { // the rainbow cycle effect can be achieved by shifting the buffer - ws2812_buffer_shift(state->buffer, 1, SHIFT_CIRCULAR, 1, -1); + ws2812_buffer_shift_prepared(state->prepare); } else if (state->effect_type == WS2812_EFFECT_FLICKER) { @@ -815,11 +812,11 @@ static void ws2812_effects_loop(void *p) } else if (state->effect_type == WS2812_EFFECT_HALLOWEEN) { - ws2812_buffer_shift(state->buffer, 1, SHIFT_CIRCULAR, 1, -1); + ws2812_buffer_shift_prepared(state->prepare); } else if (state->effect_type == WS2812_EFFECT_CIRCUS_COMBUSTUS) { - ws2812_buffer_shift(state->buffer, 1, SHIFT_CIRCULAR, 1, -1); + ws2812_buffer_shift_prepared(state->prepare); } else if (state->effect_type == WS2812_EFFECT_LARSON_SCANNER) { @@ -827,7 +824,7 @@ static void ws2812_effects_loop(void *p) } else if (state->effect_type == WS2812_EFFECT_CYCLE) { - ws2812_buffer_shift(state->buffer, state->effect_int_param1, SHIFT_CIRCULAR, 1, -1); + ws2812_buffer_shift_prepared(state->prepare); } else if (state->effect_type == WS2812_EFFECT_COLOR_WIPE) { @@ -847,12 +844,21 @@ static void ws2812_effects_loop(void *p) ws2812_write(state->buffer); // set the timer if (state->running == 1 && state->mode_delay >= 10) + if (state->running == 1 && state->mode_delay >= 10) { os_timer_disarm(&(state->os_t)); os_timer_arm(&(state->os_t), state->mode_delay, FALSE); } } +void prepare_shift(lua_State* L, ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end){ + // deinit old effect + if (state->prepare) { + luaM_free(L, state->prepare); + } + + state->prepare = ws2812_buffer_get_shift_prepare(L, buffer, shiftValue, shift_type, pos_start, pos_end); +} /** * Set the active effect mode @@ -887,105 +893,102 @@ static int ws2812_effects_set_mode(lua_State* L) { switch (state->effect_type) { case WS2812_EFFECT_STATIC: - // fill with currently set color - ws2812_effects_fill_color(); - state->mode_delay = 250; - break; + // fill with currently set color + ws2812_effects_fill_color(); + state->mode_delay = 250; + break; case WS2812_EFFECT_BLINK: - ws2812_effects_mode_blink(); - break; + ws2812_effects_mode_blink(); + break; case WS2812_EFFECT_GRADIENT: - if(arg_type == LUA_TSTRING) - { - size_t length1; - const char *buffer1 = lua_tolstring(L, 2, &length1); + if(arg_type == LUA_TSTRING) + { + size_t length1; + const char *buffer1 = lua_tolstring(L, 2, &length1); + + if ((length1 / state->buffer->colorsPerLed < 2) || (length1 % state->buffer->colorsPerLed != 0)) + { + luaL_argerror(L, 2, "must be at least two colors and same size as buffer colors"); + } - if ((length1 / state->buffer->colorsPerLed < 2) || (length1 % state->buffer->colorsPerLed != 0)) + ws2812_effects_gradient(buffer1, length1); + ws2812_write(state->buffer); + } + else { - luaL_argerror(L, 2, "must be at least two colors and same size as buffer colors"); + luaL_argerror(L, 2, "string expected"); } - ws2812_effects_gradient(buffer1, length1); - ws2812_write(state->buffer); - } - else - { - luaL_argerror(L, 2, "string expected"); - } - - break; + break; case WS2812_EFFECT_GRADIENT_RGB: - if(arg_type == LUA_TSTRING) - { - size_t length1; - const char *buffer1 = lua_tolstring(L, 2, &length1); + if(arg_type == LUA_TSTRING) + { + size_t length1; + const char *buffer1 = lua_tolstring(L, 2, &length1); - if ((length1 / state->buffer->colorsPerLed < 2) || (length1 % state->buffer->colorsPerLed != 0)) + if ((length1 / state->buffer->colorsPerLed < 2) || (length1 % state->buffer->colorsPerLed != 0)) + { + luaL_argerror(L, 2, "must be at least two colors and same size as buffer colors"); + } + + ws2812_effects_gradient_rgb(buffer1, length1); + ws2812_write(state->buffer); + } + else { - luaL_argerror(L, 2, "must be at least two colors and same size as buffer colors"); + luaL_argerror(L, 2, "string expected"); } - ws2812_effects_gradient_rgb(buffer1, length1); - ws2812_write(state->buffer); - } - else - { - luaL_argerror(L, 2, "string expected"); - } - - break; + break; case WS2812_EFFECT_RANDOM_COLOR: - ws2812_effects_mode_random_color(); - break; + ws2812_effects_mode_random_color(); + break; case WS2812_EFFECT_RAINBOW: - ws2812_effects_mode_rainbow(); - break; + ws2812_effects_mode_rainbow(); + break; case WS2812_EFFECT_RAINBOW_CYCLE: - ws2812_effects_mode_rainbow_cycle(effect_param != EFFECT_PARAM_INVALID ? effect_param : 1); - break; - // flicker + ws2812_effects_mode_rainbow_cycle(effect_param != EFFECT_PARAM_INVALID ? effect_param : 1); + prepare_shift(L, state->buffer, 1, SHIFT_CIRCULAR, 1, -1); + break; case WS2812_EFFECT_FLICKER: - state->effect_int_param1 = effect_param; - break; + state->effect_int_param1 = effect_param; + break; case WS2812_EFFECT_FIRE_FLICKER: case WS2812_EFFECT_FIRE_FLICKER_SOFT: case WS2812_EFFECT_FIRE_FLICKER_INTENSE: - { state->color[0] = 255-40; state->color[1] = 255; state->color[2] = 40; state->color[3] = 0; - } - break; + break; case WS2812_EFFECT_HALLOWEEN: - ws2812_effects_mode_halloween(); - break; + ws2812_effects_mode_halloween(); + prepare_shift(L, state->buffer, 1, SHIFT_CIRCULAR, 1, -1); + break; case WS2812_EFFECT_CIRCUS_COMBUSTUS: - ws2812_effects_mode_circus_combustus(); - break; + ws2812_effects_mode_circus_combustus(); + prepare_shift(L, state->buffer, 1, SHIFT_CIRCULAR, 1, -1); + break; case WS2812_EFFECT_LARSON_SCANNER: - ws2812_effects_mode_larson_scanner(); - break; + ws2812_effects_mode_larson_scanner(); + break; case WS2812_EFFECT_CYCLE: - if (effect_param != EFFECT_PARAM_INVALID) { - state->effect_int_param1 = effect_param; - } - break; + if (effect_param != EFFECT_PARAM_INVALID) { + state->effect_int_param1 = effect_param; + } + prepare_shift(L, state->buffer, state->effect_int_param1, SHIFT_CIRCULAR, 1, -1); + break; case WS2812_EFFECT_COLOR_WIPE: - { - uint32_t black = 0; - ws2812_effects_fill_buffer(black); + // fill buffer with black. r,g,b,w = 0 + ws2812_effects_fill_buffer(0, 0, 0, 0); ws2812_effects_mode_color_wipe(); break; - } case WS2812_EFFECT_RANDOM_DOT: - { // check if more than 1 dot shall be set state->effect_int_param1 = effect_param; - uint32_t black = 0; - ws2812_effects_fill_buffer(black); + // fill buffer with black. r,g,b,w = 0 + ws2812_effects_fill_buffer(0, 0, 0, 0); break; - } } } diff --git a/lua_tests/mispec.lua b/lua_tests/mispec.lua new file mode 100644 index 0000000000..9025f5bdf9 --- /dev/null +++ b/lua_tests/mispec.lua @@ -0,0 +1,159 @@ +local moduleName = ... or 'mispec' +local M = {} +_G[moduleName] = M + +-- Helpers: +function ok(expression, desc) + if expression == nil then expression = false end + desc = desc or 'expression is not ok' + if not expression then + error(desc .. '\n' .. debug.traceback()) + end +end + +function ko(expression, desc) + if expression == nil then expression = false end + desc = desc or 'expression is not ko' + if expression then + error(desc .. '\n' .. debug.traceback()) + end +end + +function eq(a, b) + if type(a) ~= type(b) then + error('type ' .. type(a) .. ' is not equal to ' .. type(b) .. '\n' .. debug.traceback()) + end + if type(a) == 'function' then + return string.dump(a) == string.dump(b) + end + if a == b then return true end + if type(a) ~= 'table' then + error(string.format("%q",tostring(a)) .. ' is not equal to ' .. string.format("%q",tostring(b)) .. '\n' .. debug.traceback()) + end + for k,v in pairs(a) do + if b[k] == nil or not eq(v, b[k]) then return false end + end + for k,v in pairs(b) do + if a[k] == nil or not eq(v, a[k]) then return false end + end + return true +end + +function failwith(message, func, ...) + local status, err = pcall(func, ...) + if status then + local messagePart = "" + if message then + messagePart = " containing \"" .. message .. "\"" + end + error("Error expected" .. messagePart .. '\n' .. debug.traceback()) + end + if (message and not string.find(err, message)) then + error("expected errormessage \"" .. err .. "\" to contain \"" .. message .. "\"" .. '\n' .. debug.traceback() ) + end + return true +end + +function fail(func, ...) + return failwith(nil, func, ...) +end + +local function eventuallyImpl(func, retries, delayMs) + local prevEventually = _G.eventually + _G.eventually = function() error("Cannot nest eventually/andThen.") end + local status, err = pcall(func) + _G.eventually = prevEventually + if status then + M.queuedEventuallyCount = M.queuedEventuallyCount - 1 + M.runNextPending() + else + if retries > 0 then + local t = tmr.create() + t:register(delayMs, tmr.ALARM_SINGLE, M.runNextPending) + t:start() + + table.insert(M.pending, 1, function() eventuallyImpl(func, retries - 1, delayMs) end) + else + M.failed = M.failed + 1 + print("\n ! it failed:", err) + + -- remove all pending eventuallies as spec has failed at this point + for i = 1, M.queuedEventuallyCount - 1 do + table.remove(M.pending, 1) + end + M.queuedEventuallyCount = 0 + M.runNextPending() + end + end +end + +function eventually(func, retries, delayMs) + retries = retries or 10 + delayMs = delayMs or 300 + + M.queuedEventuallyCount = M.queuedEventuallyCount + 1 + + table.insert(M.pending, M.queuedEventuallyCount, function() + eventuallyImpl(func, retries, delayMs) + end) +end + +function andThen(func) + eventually(func, 0, 0) +end + +function describe(name, itshoulds) + M.name = name + M.itshoulds = itshoulds +end + +-- Module: +M.runNextPending = function() + local next = table.remove(M.pending, 1) + if next then + node.task.post(next) + next = nil + else + M.succeeded = M.total - M.failed + local elapsedSeconds = (tmr.now() - M.startTime) / 1000 / 1000 + print(string.format( + '\n\nCompleted in %.2f seconds.\nSuccess rate is %.1f%% (%d failed out of %d).', + elapsedSeconds, 100 * M.succeeded / M.total, M.failed, M.total)) + M.pending = nil + M.queuedEventuallyCount = nil + end +end + +M.run = function() + M.pending = {} + M.queuedEventuallyCount = 0 + M.startTime = tmr.now() + M.total = 0 + M.failed = 0 + local it = {} + it.should = function(_, desc, func) + table.insert(M.pending, function() + uart.write(0, '\n * ' .. desc) + M.total = M.total + 1 + if M.pre then M.pre() end + local status, err = pcall(func) + if not status then + print("\n ! it failed:", err) + M.failed = M.failed + 1 + end + if M.post then M.post() end + M.runNextPending() + end) + end + it.initialize = function(_, pre) M.pre = pre end; + it.cleanup = function(_, post) M.post = post end; + M.itshoulds(it) + + print('' .. M.name .. ', it should:') + M.runNextPending() + + M.itshoulds = nil + M.name = nil +end + +print ("loaded mispec") diff --git a/lua_tests/mispec_ws2812.lua b/lua_tests/mispec_ws2812.lua new file mode 100644 index 0000000000..9538ca0c0b --- /dev/null +++ b/lua_tests/mispec_ws2812.lua @@ -0,0 +1,153 @@ +require 'mispec' + +local buffer, buffer1, buffer2 + +local function initBuffer(buffer, ...) + local i,v + for i,v in ipairs({...}) do + buffer:set(i, v, v*2, v*3, v*4) + end + return buffer +end + +local function equalsBuffer(buffer1, buffer2) + return eq(buffer1:dump(), buffer2:dump()) +end + + +describe('WS2812 buffers', function(it) + + it:should('initialize a buffer', function() + buffer = ws2812.newBuffer(9, 3) + ko(buffer == nil) + ok(eq(buffer:size(), 9), "check size") + ok(eq(buffer:dump(), string.char(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)), "initialize with 0") + + failwith("should be a positive integer", ws2812.newBuffer, 9, 0) + failwith("should be a positive integer", ws2812.newBuffer, 9, -1) + failwith("should be a positive integer", ws2812.newBuffer, 0, 3) + failwith("should be a positive integer", ws2812.newBuffer, -1, 3) + end) + + it:should('have correct size', function() + buffer = ws2812.newBuffer(9, 3) + ok(eq(buffer:size(), 9), "check size") + buffer = ws2812.newBuffer(9, 22) + ok(eq(buffer:size(), 9), "check size") + buffer = ws2812.newBuffer(13, 1) + ok(eq(buffer:size(), 13), "check size") + end) + + it:should('fill a buffer with one color', function() + buffer = ws2812.newBuffer(3, 3) + buffer:fill(1,222,55) + ok(eq(buffer:dump(), string.char(1,222,55,1,222,55,1,222,55)), "RGB") + buffer = ws2812.newBuffer(3, 4) + buffer:fill(1,222,55, 77) + ok(eq(buffer:dump(), string.char(1,222,55,77,1,222,55,77,1,222,55,77)), "RGBW") + end) + + it:should('replace correctly', function() + buffer = ws2812.newBuffer(5, 3) + buffer:replace(string.char(3,255,165,33,0,244,12,87,255)) + ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW") + + buffer = ws2812.newBuffer(5, 3) + buffer:replace(string.char(3,255,165,33,0,244,12,87,255), 2) + ok(eq(buffer:dump(), string.char(0,0,0,3,255,165,33,0,244,12,87,255,0,0,0)), "RGBW") + + buffer = ws2812.newBuffer(5, 3) + buffer:replace(string.char(3,255,165,33,0,244,12,87,255), -5) + ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW") + + failwith("Does not fit into destination", function() buffer:replace(string.char(3,255,165,33,0,244,12,87,255), 4) end) + end) + + it:should('replace correctly issue #2921', function() + local buffer = ws2812.newBuffer(5, 3) + buffer:replace(string.char(3,255,165,33,0,244,12,87,255), -7) + ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW") + end) + + it:should('get/set correctly', function() + buffer = ws2812.newBuffer(3, 4) + buffer:fill(1,222,55,13) + ok(eq({buffer:get(2)},{1,222,55,13})) + buffer:set(2, 4,53,99,0) + ok(eq({buffer:get(1)},{1,222,55,13})) + ok(eq({buffer:get(2)},{4,53,99,0})) + ok(eq(buffer:dump(), string.char(1,222,55,13,4,53,99,0,1,222,55,13)), "RGBW") + + failwith("index out of range", function() buffer:get(0) end) + failwith("index out of range", function() buffer:get(4) end) + failwith("index out of range", function() buffer:set(0,1,2,3,4) end) + failwith("index out of range", function() buffer:set(4,1,2,3,4) end) + failwith("number expected, got no value", function() buffer:set(2,1,2,3) end) +-- failwith("extra values given", function() buffer:set(2,1,2,3,4,5) end) + end) + + it:should('fade correctly', function() + buffer = ws2812.newBuffer(1, 3) + buffer:fill(1,222,55) + buffer:fade(2) + ok(buffer:dump() == string.char(0,111,27), "RGB") + buffer:fill(1,222,55) + buffer:fade(3, ws2812.FADE_OUT) + ok(buffer:dump() == string.char(0,222/3,55/3), "RGB") + buffer:fill(1,222,55) + buffer:fade(3, ws2812.FADE_IN) + ok(buffer:dump() == string.char(3,255,165), "RGB") + buffer = ws2812.newBuffer(1, 4) + buffer:fill(1,222,55, 77) + buffer:fade(2, ws2812.FADE_OUT) + ok(eq(buffer:dump(), string.char(0,111,27,38)), "RGBW") + end) + + it:should('mix correctly issue #1736', function() + buffer1 = ws2812.newBuffer(1, 3) + buffer2 = ws2812.newBuffer(1, 3) + buffer1:fill(10,22,54) + buffer2:fill(10,27,55) + buffer1:mix(256/8*7,buffer1,256/8,buffer2) + ok(eq({buffer1:get(1)}, {10,23,54})) + end) + + it:should('mix saturation correctly ', function() + buffer1 = ws2812.newBuffer(1, 3) + buffer2 = ws2812.newBuffer(1, 3) + + buffer1:fill(10,22,54) + buffer2:fill(10,27,55) + buffer1:mix(256/2,buffer1,-256,buffer2) + ok(eq({buffer1:get(1)}, {0,0,0})) + + buffer1:fill(10,22,54) + buffer2:fill(10,27,55) + buffer1:mix(25600,buffer1,256/8,buffer2) + ok(eq({buffer1:get(1)}, {255,255,255})) + + buffer1:fill(10,22,54) + buffer2:fill(10,27,55) + buffer1:mix(-257,buffer1,255,buffer2) + ok(eq({buffer1:get(1)}, {0,5,1})) + end) + + it:should('mix with strings correctly ', function() + buffer1 = ws2812.newBuffer(1, 3) + buffer2 = ws2812.newBuffer(1, 3) + + buffer1:fill(10,22,54) + buffer2:fill(10,27,55) + buffer1:mix(-257,buffer1:dump(),255,buffer2:dump()) + ok(eq({buffer1:get(1)}, {0,5,1})) + end) + + it:should('power', function() + buffer = ws2812.newBuffer(2, 4) + buffer:fill(10,22,54,234) + ok(eq(buffer:power(), 2*(10+22+54+234))) + end) + +end) + +mispec.run() diff --git a/lua_tests/mispec_ws2812_2.lua b/lua_tests/mispec_ws2812_2.lua new file mode 100644 index 0000000000..a9b4056bbc --- /dev/null +++ b/lua_tests/mispec_ws2812_2.lua @@ -0,0 +1,149 @@ +require 'mispec' + +local buffer, buffer1, buffer2 + +local function initBuffer(buffer, ...) + local i,v + for i,v in ipairs({...}) do + buffer:set(i, v, v*2, v*3, v*4) + end + return buffer +end + +local function equalsBuffer(buffer1, buffer2) + return eq(buffer1:dump(), buffer2:dump()) +end + + +describe('WS2812 buffers', function(it) + + it:should('shift LOGICAL', function() + + buffer1 = ws2812.newBuffer(4, 4) + buffer2 = ws2812.newBuffer(4, 4) + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,0,0,7,8) + buffer1:shift(2) + ok(equalsBuffer(buffer1, buffer2), "shift right") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,9,12,0,0) + buffer1:shift(-2) + ok(equalsBuffer(buffer1, buffer2), "shift left") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,7,0,8,12) + buffer1:shift(1, nil, 2,3) + ok(equalsBuffer(buffer1, buffer2), "shift middle right") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,7,9,0,12) + buffer1:shift(-1, nil, 2,3) + ok(equalsBuffer(buffer1, buffer2), "shift middle left") + + -- bounds checks, handle gracefully as string:sub does + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,8,9,12,0) + buffer1:shift(-1, ws2812.SHIFT_LOGICAL, 0,5) + ok(equalsBuffer(buffer1, buffer2), "shift left out of bound") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,0,7,8,9) + buffer1:shift(1, ws2812.SHIFT_LOGICAL, 0,5) + ok(equalsBuffer(buffer1, buffer2), "shift right out of bound") + + end) + + it:should('shift LOGICAL issue #2946', function() + buffer1 = ws2812.newBuffer(4, 4) + buffer2 = ws2812.newBuffer(4, 4) + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,0,0,0,0) + buffer1:shift(4) + ok(equalsBuffer(buffer1, buffer2), "shift all right") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,0,0,0,0) + buffer1:shift(-4) + ok(equalsBuffer(buffer1, buffer2), "shift all left") + + failwith("shifting more elements than buffer size", function() buffer1:shift(10) end) + failwith("shifting more elements than buffer size", function() buffer1:shift(-6) end) + end) + + it:should('shift CIRCULAR', function() + buffer1 = ws2812.newBuffer(4, 4) + buffer2 = ws2812.newBuffer(4, 4) + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,9,12,7,8) + buffer1:shift(2, ws2812.SHIFT_CIRCULAR) + ok(equalsBuffer(buffer1, buffer2), "shift right") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,9,12,7,8) + buffer1:shift(-2, ws2812.SHIFT_CIRCULAR) + ok(equalsBuffer(buffer1, buffer2), "shift left") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,7,9,8,12) + buffer1:shift(1, ws2812.SHIFT_CIRCULAR, 2,3) + ok(equalsBuffer(buffer1, buffer2), "shift middle right") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,7,9,8,12) + buffer1:shift(-1, ws2812.SHIFT_CIRCULAR, 2,3) + ok(equalsBuffer(buffer1, buffer2), "shift middle left") + + -- bounds checks, handle gracefully as string:sub does + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,8,9,12,7) + buffer1:shift(-1, ws2812.SHIFT_CIRCULAR, 0,5) + ok(equalsBuffer(buffer1, buffer2), "shift left out of bound") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,12,7,8,9) + buffer1:shift(1, ws2812.SHIFT_CIRCULAR, 0,5) + ok(equalsBuffer(buffer1, buffer2), "shift right out of bound") + + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,12,7,8,9) + buffer1:shift(1, ws2812.SHIFT_CIRCULAR, -12,12) + ok(equalsBuffer(buffer1, buffer2), "shift right way out of bound") + + end) + + it:should('sub', function() + buffer1 = ws2812.newBuffer(4, 4) + buffer2 = ws2812.newBuffer(4, 4) + initBuffer(buffer1,7,8,9,12) + buffer1 = buffer1:sub(4,3) + ok(eq(buffer1:size(), 0), "sub empty") + + buffer1 = ws2812.newBuffer(4, 4) + buffer2 = ws2812.newBuffer(2, 4) + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,9,12) + buffer1 = buffer1:sub(3,4) + ok(equalsBuffer(buffer1, buffer2), "sub") + + buffer1 = ws2812.newBuffer(4, 4) + buffer2 = ws2812.newBuffer(4, 4) + initBuffer(buffer1,7,8,9,12) + initBuffer(buffer2,7,8,9,12) + buffer1 = buffer1:sub(-12,33) + ok(equalsBuffer(buffer1, buffer2), "out of bounds") + end) + + + + +--[[ +ws2812.buffer:__concat() +--]] + +end) + +mispec.run() diff --git a/lua_tests/mispec_ws2812_effects.lua b/lua_tests/mispec_ws2812_effects.lua new file mode 100644 index 0000000000..3fc8d95b8d --- /dev/null +++ b/lua_tests/mispec_ws2812_effects.lua @@ -0,0 +1,31 @@ +require 'mispec' + +local buffer, buffer1, buffer2 + +describe('WS2812_effects', function(it) + + it:should('set_speed', function() + buffer = ws2812.newBuffer(9, 3) + ws2812_effects.init(buffer) + + ws2812_effects.set_speed(0) + ws2812_effects.set_speed(255) + + failwith("should be", ws2812_effects.set_speed, -1) + failwith("should be", ws2812_effects.set_speed, 256) + end) + + it:should('set_brightness', function() + buffer = ws2812.newBuffer(9, 3) + ws2812_effects.init(buffer) + + ws2812_effects.set_brightness(0) + ws2812_effects.set_brightness(255) + + failwith("should be", ws2812_effects.set_brightness, -1) + failwith("should be", ws2812_effects.set_brightness, 256) + end) + +end) + +mispec.run() From 4fc2b85fde197e92ffa7337fa26c7b30f616d0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Mon, 9 Dec 2019 13:31:55 +0100 Subject: [PATCH 17/59] Streaming support for hx711 (#2915) --- app/modules/hx711.c | 318 ++++++++++++++++++++++++++++++++++++++---- docs/modules/hx711.md | 60 +++++++- 2 files changed, 346 insertions(+), 32 deletions(-) diff --git a/app/modules/hx711.c b/app/modules/hx711.c index 61198e33a1..5277b439fa 100644 --- a/app/modules/hx711.c +++ b/app/modules/hx711.c @@ -3,65 +3,314 @@ #include "module.h" #include "lauxlib.h" +#include "lmem.h" #include "platform.h" #include #include +#include "task/task.h" #include "user_interface.h" static uint8_t data_pin; static uint8_t clk_pin; +// The fields below are after the pin_num conversion +static uint8_t pin_data_pin; +static uint8_t pin_clk_pin; + +#ifdef GPIO_INTERRUPT_ENABLE +static task_handle_t tasknumber; + +// HX711_STATUS can be defined to enable the hx711.status() function to get debug info +#undef HX711_STATUS +#define BUFFERS 2 + +typedef struct { + char *buf[BUFFERS]; + uint32_t dropped[BUFFERS]; + uint32_t timestamp[BUFFERS]; + uint32_t interrupts; + uint32_t hx711_interrupts; + uint16_t buflen; + uint16_t used; + uint32_t nobuffer; + uint8_t active; // slot of the active buffer + uint8_t freed; // slot of the most recently freed buffer + uint8_t mode; + uint8_t dropping; // is non zero when there is no space + int cb_ref; +} CONTROL; + +static CONTROL *control; +#endif /*Lua: hx711.init(clk_pin,data_pin)*/ static int hx711_init(lua_State* L) { - clk_pin = luaL_checkinteger(L,1); - data_pin = luaL_checkinteger(L,2); + clk_pin = luaL_checkint(L,1); + data_pin = luaL_checkint(L,2); MOD_CHECK_ID( gpio, clk_pin ); MOD_CHECK_ID( gpio, data_pin ); platform_gpio_mode(clk_pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT); platform_gpio_write(clk_pin,1);//put chip to sleep. + + pin_data_pin = pin_num[data_pin]; + pin_clk_pin = pin_num[clk_pin]; return 0; } +static int32_t ICACHE_RAM_ATTR read_sample(char mode) { + int i; + int32_t data = 0; + + for (i = 0; i < 24 ; i++){ //clock in the 24 bits + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin); + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin); + data = data << 1; + if (GPIO_REG_READ(GPIO_IN_ADDRESS) & (1 << pin_data_pin)) { + data = i == 0 ? -1 : data | 1; //signextend the first bit + } + } + //add 25th-27th clock pulse to prevent protocol error + for (i = 0; i <= mode; i++) { + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin); + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin); + } + + return data; +} + +#ifdef GPIO_INTERRUPT_ENABLE +static void ICACHE_RAM_ATTR hx711_data_available() { + if (!control) { + return; + } + uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS); + if (bits & (1 << pin_data_pin)) { + return; // not ready + } + + // Read a sample + int32_t data = read_sample(control->mode); + + if (control->dropping) { + if (control->active == control->freed) { + // still can't advance + control->nobuffer++; + return; + } + // Advance + control->active = (1 + control->active) % BUFFERS; + control->dropping = 0; + } + + // insert into the active buffer + char *dest = control->buf[control->active] + control->used; + *dest++ = data; + *dest++ = data >> 8; + *dest++ = data >> 16; + + control->used += 3; + if (control->used == control->buflen) { + control->used = 0; + control->timestamp[control->active] = system_get_time(); + control->dropped[control->active] = control->nobuffer; + control->nobuffer = 0; + // post task + task_post_medium(tasknumber, control->active); + + uint8_t next_active = (1 + control->active) % BUFFERS; + + if (control->active == control->freed) { + // We can't advance to the buffer + control->dropping = 1; + } else { + // flip to other buffer + control->active = next_active; + } + } +} + +static uint32_t ICACHE_RAM_ATTR hx711_interrupt(uint32_t ret_gpio_status) +{ + // This function really is running at interrupt level with everything + // else masked off. It should take as little time as necessary. + // + // + + // This gets the set of pins which have changed status + uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + + int pin_mask = 1 << pin_data_pin; + int i; + + control->interrupts++; + + if (gpio_status & pin_mask) { + uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS); + control->hx711_interrupts++; + if (!(bits & pin_mask)) { + // is now ready to read + hx711_data_available(); + } + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & pin_mask); + } + + return gpio_status & ~pin_mask; +} + +// Lua: hx711.start( mode, samples, callback ) +static int hx711_start( lua_State* L ) +{ + uint32_t mode = luaL_checkint( L, 1 ); + uint32_t samples = luaL_checkint( L, 2 ); + + if (mode > 2) { + return luaL_argerror( L, 1, "Mode value out of range" ); + } + + if (!samples || samples > 400) { + return luaL_argerror( L, 2, "Samples value out of range (1-400)" ); + } + + if (control) { + return luaL_error( L, "Already running" ); + } + + int buflen = 3 * samples; + + control = (CONTROL *) luaM_malloc(L, sizeof(CONTROL) + BUFFERS * buflen); + if (!control) { + return luaL_error( L, "Failed to allocate memory" ); + } + + int cb_ref; + + if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) { + lua_pushvalue(L, 3); // copy argument (func) to the top of stack + cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + luaM_free(L, control); + control = NULL; + return luaL_argerror( L, 3, "Not a callback function" ); + } + + memset(control, 0, sizeof(*control)); + control->buf[0] = (char *) (control + 1); + control->buflen = buflen; + int i; + + for (i = 1; i < BUFFERS; i++) { + control->buf[i] = control->buf[i - 1] + buflen; + } + control->mode = mode; + control->cb_ref = cb_ref; + control->freed = BUFFERS - 1; + + // configure data_pin as interrupt input + platform_gpio_register_intr_hook(1 << pin_data_pin, hx711_interrupt); + platform_gpio_mode(data_pin, PLATFORM_GPIO_INT, PLATFORM_GPIO_FLOAT); + platform_gpio_intr_init(data_pin, GPIO_PIN_INTR_NEGEDGE); + + + // Wake up chip + platform_gpio_write(clk_pin, 0); + + return 0; +} + +// Lua: hx711.stop( ) +static int hx711_stop( lua_State* L ) +{ + if (control) { + platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT); + CONTROL *to_free = control; + control = NULL; + luaL_unref(L, LUA_REGISTRYINDEX, to_free->cb_ref); + luaM_free(L, to_free); + } + + return 0; +} + +static int hx711_status( lua_State* L ) +{ + if (control) { + lua_pushlstring(L, (char *) control, sizeof(*control)); + return 1; + } + + return 0; +} + +static void hx711_task(os_param_t param, uint8_t prio) +{ + (void) prio; + if (!control) { + return; + } + + lua_State *L = lua_getstate(); + + if (control->cb_ref != LUA_NOREF) { + lua_rawgeti(L, LUA_REGISTRYINDEX, control->cb_ref); + + lua_pushlstring(L, control->buf[param], control->buflen); + lua_pushinteger(L, control->timestamp[param]); + lua_pushinteger(L, control->dropped[param]); + + control->freed = param; + + lua_call(L, 3, 0); + } +} +#endif + #define HX711_MAX_WAIT 1000000 /*will only read chA@128gain*/ /*Lua: result = hx711.read()*/ -static int ICACHE_FLASH_ATTR hx711_read(lua_State* L) { - uint32_t i; - int32_t data = 0; +static int hx711_read(lua_State* L) { + int j; //TODO: double check init has happened first. + // - //wakeup hx711 - platform_gpio_write(clk_pin,0); + uint32_t mode = luaL_optinteger(L, 1, 0); - //wait for data ready. or time out. - //TODO: set pin inturrupt and come back to it. This may take up to 1/10 sec - // or maybe just make an async version too and have both available. - system_soft_wdt_feed(); //clear WDT... this may take a while. - for (i = 0; i 2) { + return luaL_argerror( L, 1, "Mode value out of range" ); } - //Handle timeout error - if (i>=HX711_MAX_WAIT) { - return luaL_error( L, "ADC timeout!", ( unsigned )0 ); +#ifdef GPIO_INTERRUPT_ENABLE + if (control) { + hx711_stop(L); } +#endif + + //wakeup hx711 + platform_gpio_write(clk_pin, 0); + + int32_t data; - for (i = 0; i<24 ; i++){ //clock in the 24 bits - platform_gpio_write(clk_pin,1); - platform_gpio_write(clk_pin,0); - data = data<<1; - if (platform_gpio_read(data_pin)==1) { - data = i==0 ? -1 : data|1; //signextend the first bit + // read two samples if mode > 0. We discard the first read and return the + // second value. + for (j = (mode ? 1 : 0); j >= 0; j--) { + uint32_t i; + + //wait for data ready. or time out. + system_soft_wdt_feed(); //clear WDT... this may take a while. + for (i = 0; i= HX711_MAX_WAIT) { + return luaL_error( L, "ADC timeout!"); } + + data = read_sample(mode); } - //add 25th clock pulse to prevent protocol error (probably not needed - // since we'll go to sleep immediately after and reset on wakeup.) - platform_gpio_write(clk_pin,1); - platform_gpio_write(clk_pin,0); - //sleep - platform_gpio_write(clk_pin,1); - lua_pushinteger( L, data ); + + //sleep -- unfortunately, this resets the mode to 0 + platform_gpio_write(clk_pin, 1); + lua_pushinteger(L, data); return 1; } @@ -69,11 +318,20 @@ static int ICACHE_FLASH_ATTR hx711_read(lua_State* L) { LROT_BEGIN(hx711) LROT_FUNCENTRY( init, hx711_init ) LROT_FUNCENTRY( read, hx711_read ) +#ifdef GPIO_INTERRUPT_ENABLE + LROT_FUNCENTRY( start, hx711_start ) +#ifdef HX711_STATUS + LROT_FUNCENTRY( status, hx711_status ) +#endif + LROT_FUNCENTRY( stop, hx711_stop ) +#endif LROT_END( hx711, NULL, 0 ) int luaopen_hx711(lua_State *L) { - // TODO: Make sure that the GPIO system is initialized +#ifdef GPIO_INTERRUPT_ENABLE + tasknumber = task_get_id(hx711_task); +#endif return 0; } diff --git a/docs/modules/hx711.md b/docs/modules/hx711.md index 0eaa3cff19..1095ebae2d 100644 --- a/docs/modules/hx711.md +++ b/docs/modules/hx711.md @@ -2,8 +2,11 @@ | Since | Origin / Contributor | Maintainer | Source | | :----- | :-------------------- | :---------- | :------ | | 2015-10-09 | [Chris Takahashi](https://github.com/christakahashi) | [Chris Takahashi](https://github.com/christakahashi) | [hx711.c](../../app/modules/hx711.c)| +| 2019-04-20 | [Philip Gladstone](https://github.com/pjsg) | [Philip Gladstone](https://github.com/pjsg) -This module provides access to an [HX711 load cell amplifier/ADC](https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide). The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain. Currently only channel A at 128x gain is supported. +This module provides access to an [HX711 load cell amplifier/ADC](https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide). The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain. The standard Chinese sources have [cheap HX711 boards](https://www.aliexpress.com/wholesale?SearchText=hx711+module) for around $1. + +This can be used for single shot reads, or repetitive reads. Note: To save ROM image space, this module is not compiled into the firmware by default. @@ -35,11 +38,13 @@ Read digital loadcell ADC value. `hx711.read(mode)` #### Parameters -`mode` ADC mode. This parameter is currently ignored and reserved to ensure backward compatibility if support for additional modes is added. Currently only channel A @ 128 gain is supported. +- `mode` ADC mode. This parameter specifies which input and the gain to apply to that input. Reading in mode 1 or 2 takes longer than reading in mode 0. |mode | channel | gain | |-----|---------|------| | 0 | A | 128 | +| 1 | B | 32 | +| 2 | A | 64 | #### Returns a number (24 bit signed ADC value extended to the machine int size) @@ -49,3 +54,54 @@ a number (24 bit signed ADC value extended to the machine int size) -- Read ch A with 128 gain. raw_data = hx711.read(0) ``` + +## hx711.start() + +Starts to read multiple samples from the ADC. + +#### Syntax +`hx711.start(mode, samples, callback)` + +#### Parameters +- `mode` ADC mode. This parameter is currently ignored and reserved to ensure backward compatibility if support for additional modes is added. +- `samples` The number of samples before the callback is invoked. The length of time depends on the chip's sampling rate. +- `callback` The callback is invoked with three arguments (see below). + +|mode | channel | gain | +|-----|---------|------| +| 0 | A | 128 | +| 1 | B | 32 | +| 2 | A | 64 | + +#### Returns +nothing + +#### Callback +This is invoked every time `samples` samples are read from the HX711. The arguments are: + +- A string which contains `samples` packed 24 bit values. This can be unpacked with the `struct` module (using the "i3" format). +- The time in microseconds of the reception of the last sample in the buffer. +- The number of samples dropped before the start of this buffer (after the end of the previous buffer). + +#### Notes +This api only is built if GPIO_INTERRUPT_ENABLE and GPIO_INTERRUPT_HOOK_ENABLE are defined in the +`user_config.h`. This is the default. + +Also, do not try and mix calls to `start` and calls to `read`. Any calls to `read` will implicitly call `stop` first. + +#### Example +```lua +-- Read ch A with 128 gain. +hx711.start(0, 2, function(s, t, d) local r1, r2, _ = struct.unpack("i3 i3", s) print(r1, r2) end) +``` + +## hx711.stop() + +Stops a previously started set of reads. Any data in buffers is lost. No more callbacks will be invoked. + +#### Syntax +`hx711.stop()` + +#### Returns +nothing + From f85c2780ad035a5e0b2e38cbd30293aaba2649e1 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Mon, 9 Dec 2019 13:33:30 +0100 Subject: [PATCH 18/59] New `net.if.info` call to show LwIP information (#2862) * Remove app/include/netif/wlan_lwip_if.h This file appears to be unused in our tree. * New `net.if.info` call to show LwIP information This is a generalization of `wifi.sta`'s and `wifi.ap`'s `getip` and `getmac` calls. I don't propose to deprecate those, but perhaps we should, in the documentation, point users at this function instead. The direct motivation is to permit continued use of DHCP-provided NTP servers in a future where https://github.com/nodemcu/nodemcu-firmware/pull/2819 has landed, now that https://github.com/nodemcu/nodemcu-firmware/pull/2709 is in the tree. But rather than exposing just that information, a more general interface seems useful. --- app/include/netif/wlan_lwip_if.h | 25 ------------- app/modules/net.c | 61 ++++++++++++++++++++++++++++++++ docs/modules/net.md | 37 +++++++++++++++++++ 3 files changed, 98 insertions(+), 25 deletions(-) delete mode 100644 app/include/netif/wlan_lwip_if.h diff --git a/app/include/netif/wlan_lwip_if.h b/app/include/netif/wlan_lwip_if.h deleted file mode 100644 index 13eff5e454..0000000000 --- a/app/include/netif/wlan_lwip_if.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2010-2011 Espressif System - * -*/ - -#ifndef _WLAN_LWIP_IF_H_ -#define _WLAN_LWIP_IF_H_ - -#define LWIP_IF0_PRIO 28 -#define LWIP_IF1_PRIO 29 - -enum { - SIG_LWIP_RX = 0, -}; - -struct netif * eagle_lwip_if_alloc(struct ieee80211_conn *conn, const uint8 *macaddr, struct ip_info *info); -struct netif * eagle_lwip_getif(uint8 index); - -#ifndef IOT_SIP_MODE -sint8 ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb); -#else -sint8 ieee80211_output_pbuf(struct ieee80211_conn *conn, esf_buf *eb); -#endif - -#endif /* _WLAN_LWIP_IF_H_ */ diff --git a/app/modules/net.c b/app/modules/net.c index 51efae715b..d8678ec9c8 100644 --- a/app/modules/net.c +++ b/app/modules/net.c @@ -18,6 +18,7 @@ #include "lwip/igmp.h" #include "lwip/tcp.h" #include "lwip/udp.h" +#include "lwip/dhcp.h" #if defined(CLIENT_SSL_ENABLE) && defined(LUA_USE_MODULES_NET) && defined(LUA_USE_MODULES_TLS) #define TLS_MODULE_PRESENT @@ -980,6 +981,62 @@ static int net_getdnsserver( lua_State* L ) { return 1; } +#pragma mark - netif info + +/* + * XXX This is internal to Espressif's SDK, but it's called from several places + * in the NodeMCU tree. It would be nicer if there were a LwIP export for this + * rather than this not-so-secret symbol. + */ +extern struct netif *eagle_lwip_getif(uint8); + +static void +push_ipaddr(lua_State *L, ip_addr_t *addr) { + char temp[20]; + ssize_t ipl = ets_snprintf(temp, sizeof temp, IPSTR, IP2STR(&addr->addr)); + lua_assert (ipl >= 0 && ipl < 20); + lua_pushlstring( L, temp, ipl ); +} + +static void +field_from_ipaddr(lua_State *L, const char * field_name, ip_addr_t* addr) { + if ( ip_addr_isany(addr) ) { + lua_pushnil(L); + } else { + push_ipaddr(L, addr); + } + lua_setfield(L, -2, field_name); +} + +static int net_if_info( lua_State* L ) { + int ifidx = luaL_optint(L, 1, 0); + + struct netif * nif = eagle_lwip_getif(ifidx); + if (nif == NULL) { + return luaL_error( L, "unknown network interface index %d", ifidx); + } + + lua_createtable(L, 0, + 4 + (nif->dhcp == NULL ? 0 : 1)); + + lua_pushlstring(L, nif->hwaddr, nif->hwaddr_len); + lua_setfield(L, -2, "hwaddr"); + + field_from_ipaddr(L, "ip" , &nif->ip_addr); + field_from_ipaddr(L, "netmask", &nif->netmask); + field_from_ipaddr(L, "gateway", &nif->gw); + + if (nif->dhcp != NULL) { + lua_createtable(L, 0, 3); + field_from_ipaddr(L, "server_ip" , &nif->dhcp->server_ip_addr ); + field_from_ipaddr(L, "client_ip" , &nif->dhcp->offered_ip_addr ); + field_from_ipaddr(L, "ntp_server", &nif->dhcp->offered_ntp_addr); + } + lua_setfield(L, -2, "dhcp"); + + return 1; +} + #pragma mark - Tables #ifdef TLS_MODULE_PRESENT @@ -1031,6 +1088,9 @@ LROT_BEGIN(net_dns) LROT_FUNCENTRY( resolve, net_dns_static ) LROT_END( net_dns, net_dns, 0 ) +LROT_BEGIN(net_if) + LROT_FUNCENTRY( info, net_if_info ) +LROT_END(net_if, net_if, 0) LROT_BEGIN(net) LROT_FUNCENTRY( createServer, net_createServer ) @@ -1039,6 +1099,7 @@ LROT_BEGIN(net) LROT_FUNCENTRY( multicastJoin, net_multicastJoin ) LROT_FUNCENTRY( multicastLeave, net_multicastLeave ) LROT_TABENTRY( dns, net_dns ) + LROT_TABENTRY( if, net_if ) #ifdef TLS_MODULE_PRESENT LROT_TABENTRY( cert, tls_cert ) #endif diff --git a/docs/modules/net.md b/docs/modules/net.md index dd1c0ee495..7f6b70e4ff 100644 --- a/docs/modules/net.md +++ b/docs/modules/net.md @@ -618,6 +618,43 @@ Sets the IP of the DNS server used to resolve hostnames. Default: resolver1.open #### See also [`net.dns:getdnsserver()`](#netdnsgetdnsserver) +# net.if Module + +## net.if.info() + +Return information about a network interface, specified by index. + +#### Syntax +`net.if.info(if_index)` + +#### Parameters +- `if_index` the interface index; on ESP8266, `0` is the wifi client (STA) and `1` + is the wifi AP. + +#### Returns +`nil` if the given `if_index` does not correspond to an interface. Otherwise, +a table containing ... + +* `ip`, `netmask`, and `gateway` configured for this interface, as dotted quad strings + or `nil` if none is set. + +* if DHCP was used to configure the interface, then `dhcp` will be a table containing... + + * `server_ip` -- the DHCP server itself, as a dotted quad + + * `client_ip` -- the IP address suggested for the client; likely, this equals `ip` + above, unless the configuration has been overridden. + + * `ntp_server` -- the NTP server suggested by the DHCP server. + +DNS servers are not tracked per-interface in LwIP and, as such, are not +reported here; use [`net.dns:getdnsserver()`](#netdnsgetdnsserver). + +#### Example + +`print(net.if.info(0).dhcp.ntp_server)` will show the NTP server suggested by +the DHCP server. + # net.cert Module This part gone to the [TLS](tls.md) module, link kept for backward compatibility. From d84da3649411a1906bb4839a6719f1eea5acf676 Mon Sep 17 00:00:00 2001 From: Andreas Date: Fri, 13 Dec 2019 11:53:39 +0100 Subject: [PATCH 19/59] fixed missing forward declaration (#2975) --- lua_modules/ds18b20/ds18b20.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua_modules/ds18b20/ds18b20.lua b/lua_modules/ds18b20/ds18b20.lua index b672c87a35..50d9a34152 100644 --- a/lua_modules/ds18b20/ds18b20.lua +++ b/lua_modules/ds18b20/ds18b20.lua @@ -50,6 +50,8 @@ local function to_string(addr, esc) end end +local conversion + local function readout(self) local next = false local sens = self.sens @@ -114,7 +116,7 @@ local function readout(self) end end -local function conversion(self) +conversion = function (self) local sens = self.sens local powered_only = true for _, s in ipairs(sens) do powered_only = powered_only and s:byte(9) ~= 1 end From bf8f14b6117f4452857537ea98fbc07f0551b807 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Fri, 27 Dec 2019 13:17:44 +0000 Subject: [PATCH 20/59] SSL rampage (#2938) * Remove stale putative MD2 support This hasn't worked in a while, presumably since one of our upstream merges. Don't bother making it work, since MD2 is generally considered insecure. * Land mbedtls 2.16.3-77-gf02988e57 * TLS: remove some dead code from espconn_mbedtls There was some... frankly kind of scary buffer and data shuffling if ESP8266_PLATFORM was defined. Since we don't, in fact, define that preprocessor symbol, just drop the code lest anyone (possibly future-me) be scared. * TLS: espconn_mbedtls: run through astyle No functional changes * TLS: espconn_mbedtls: put the file_params on the stack There's no need to malloc a structure that's used only locally. * TLS: Further minor tidying of mbedtls glue What an absolute shitshow this is. mbedtls should absolutely not be mentioned inside sys/socket.h and app/mbedtls/app/lwIPSocket.c is not so much glue as it as a complete copy of a random subset of lwIP; it should go, but we aren't there yet. Get rid of the mysterious "mbedlts_record" struct, which housed merely a length of bytes sent solely for gating the "record sent" callback. Remove spurious __attribute__((weak)) from symbols not otherwise defined and rename them to emphasize that they are not actually part of mbedtls proper. * TLS: Rampage esp mbedtls glue and delete unused code This at least makes the shitshow smaller * TLS: lwip: fix some memp definitions I presume these also need the new arguments * TLS: Remove more non-NodeMCU code from our mbedtls * TLS: drop support for 1.1 Depending on who you ask it's either EOL already or EOL soon, so we may as well get rid of it now. --- app/crypto/digests.c | 7 - app/include/lwip/memp_std.h | 14 +- app/include/mbedtls/aes.h | 325 ++- app/include/mbedtls/aesni.h | 52 +- app/include/mbedtls/arc4.h | 29 +- app/include/mbedtls/aria.h | 370 +++ app/include/mbedtls/asn1write.h | 317 ++- app/include/mbedtls/base64.h | 9 + app/include/mbedtls/bignum.h | 822 ++++--- app/include/mbedtls/blowfish.h | 200 +- app/include/mbedtls/bn_mul.h | 23 +- app/include/mbedtls/camellia.h | 253 +- app/include/mbedtls/ccm.h | 228 +- app/include/mbedtls/certs.h | 240 +- app/include/mbedtls/chacha20.h | 226 ++ app/include/mbedtls/chachapoly.h | 358 +++ app/include/mbedtls/check_config.h | 38 +- app/include/mbedtls/cipher.h | 594 +++-- app/include/mbedtls/cipher_internal.h | 15 + app/include/mbedtls/cmac.h | 61 +- app/include/mbedtls/compat-1.3.h | 9 +- app/include/mbedtls/config.h | 570 ++++- app/include/mbedtls/ctr_drbg.h | 335 ++- app/include/mbedtls/debug.h | 36 + app/include/mbedtls/des.h | 31 +- app/include/mbedtls/dhm.h | 247 +- app/include/mbedtls/ecdh.h | 369 ++- app/include/mbedtls/ecdsa.h | 500 +++- app/include/mbedtls/ecjpake.h | 170 +- app/include/mbedtls/ecp.h | 1194 ++++++--- app/include/mbedtls/ecp_internal.h | 6 + app/include/mbedtls/entropy.h | 6 +- app/include/mbedtls/error.h | 30 +- app/include/mbedtls/gcm.h | 171 +- app/include/mbedtls/havege.h | 8 +- app/include/mbedtls/hkdf.h | 141 ++ app/include/mbedtls/hmac_drbg.h | 341 ++- app/include/mbedtls/md.h | 111 +- app/include/mbedtls/md2.h | 31 +- app/include/mbedtls/md4.h | 31 +- app/include/mbedtls/md5.h | 31 +- app/include/mbedtls/net.h | 5 + app/include/mbedtls/net_sockets.h | 48 +- app/include/mbedtls/nist_kw.h | 184 ++ app/include/mbedtls/oid.h | 26 +- app/include/mbedtls/padlock.h | 42 +- app/include/mbedtls/pem.h | 8 +- app/include/mbedtls/pk.h | 229 +- app/include/mbedtls/pk_internal.h | 23 + app/include/mbedtls/pkcs11.h | 3 +- app/include/mbedtls/pkcs5.h | 4 + app/include/mbedtls/platform.h | 79 +- app/include/mbedtls/platform_util.h | 196 ++ app/include/mbedtls/poly1305.h | 192 ++ app/include/mbedtls/ripemd160.h | 32 +- app/include/mbedtls/rsa.h | 1004 ++++---- app/include/mbedtls/sha1.h | 196 +- app/include/mbedtls/sha256.h | 137 +- app/include/mbedtls/sha512.h | 142 +- app/include/mbedtls/ssl.h | 793 +++++- app/include/mbedtls/ssl_cache.h | 6 + app/include/mbedtls/ssl_ciphersuites.h | 54 + app/include/mbedtls/ssl_cookie.h | 8 +- app/include/mbedtls/ssl_internal.h | 165 +- app/include/mbedtls/ssl_ticket.h | 14 +- app/include/mbedtls/threading.h | 17 +- app/include/mbedtls/timing.h | 26 +- app/include/mbedtls/version.h | 10 +- app/include/mbedtls/x509.h | 10 +- app/include/mbedtls/x509_crl.h | 4 +- app/include/mbedtls/x509_crt.h | 104 +- app/include/mbedtls/x509_csr.h | 8 + app/include/mbedtls/xtea.h | 30 +- app/include/sys/Espconn_mem.h | 33 - app/include/sys/espconn_mbedtls.h | 15 +- app/include/sys/socket.h | 14 +- app/include/user_config.h | 1 - app/include/user_mbedtls.h | 4 +- app/mbedtls/app/Espconn_mem.c | 73 - app/mbedtls/app/espconn_mbedtls.c | 574 ++--- app/mbedtls/app/lwIPSocket.c | 240 +- app/mbedtls/library/aes.c | 837 ++++++- app/mbedtls/library/aesni.c | 6 + app/mbedtls/library/arc4.c | 8 +- app/mbedtls/library/aria.c | 1079 ++++++++ app/mbedtls/library/asn1parse.c | 10 +- app/mbedtls/library/asn1write.c | 62 +- app/mbedtls/library/bignum.c | 489 +++- app/mbedtls/library/blowfish.c | 64 +- app/mbedtls/library/camellia.c | 76 +- app/mbedtls/library/ccm.c | 94 +- app/mbedtls/library/certs.c | 2022 ++++++++++++--- app/mbedtls/library/chacha20.c | 570 +++++ app/mbedtls/library/chachapoly.c | 540 ++++ app/mbedtls/library/cipher.c | 343 ++- app/mbedtls/library/cipher_wrap.c | 821 +++++++ app/mbedtls/library/cmac.c | 36 +- app/mbedtls/library/ctr_drbg.c | 238 +- app/mbedtls/library/debug.c | 94 +- app/mbedtls/library/des.c | 97 +- app/mbedtls/library/dhm.c | 87 +- app/mbedtls/library/ecdh.c | 558 ++++- app/mbedtls/library/ecdsa.c | 669 ++++- app/mbedtls/library/ecjpake.c | 42 +- app/mbedtls/library/ecp.c | 1259 ++++++++-- app/mbedtls/library/ecp_curves.c | 203 +- app/mbedtls/library/entropy.c | 18 +- app/mbedtls/library/entropy_poll.c | 11 +- app/mbedtls/library/error.c | 116 +- app/mbedtls/library/gcm.c | 60 +- app/mbedtls/library/havege.c | 36 +- app/mbedtls/library/hkdf.c | 192 ++ app/mbedtls/library/hmac_drbg.c | 152 +- app/mbedtls/library/md.c | 15 +- app/mbedtls/library/md2.c | 8 +- app/mbedtls/library/md4.c | 38 +- app/mbedtls/library/md5.c | 29 +- app/mbedtls/library/memory_buffer_alloc.c | 20 +- app/mbedtls/library/nist_kw.c | 755 ++++++ app/mbedtls/library/oid.c | 53 +- app/mbedtls/library/pem.c | 34 +- app/mbedtls/library/pk.c | 216 +- app/mbedtls/library/pk_wrap.c | 213 +- app/mbedtls/library/pkcs12.c | 20 +- app/mbedtls/library/pkparse.c | 132 +- app/mbedtls/library/pkwrite.c | 59 +- app/mbedtls/library/platform.c | 29 +- app/mbedtls/library/platform_util.c | 139 ++ app/mbedtls/library/poly1305.c | 559 +++++ app/mbedtls/library/ripemd160.c | 47 +- app/mbedtls/library/rsa.c | 319 ++- app/mbedtls/library/rsa_internal.c | 9 +- app/mbedtls/library/sha1.c | 64 +- app/mbedtls/library/sha256.c | 64 +- app/mbedtls/library/sha512.c | 54 +- app/mbedtls/library/ssl_ciphersuites.c | 536 +++- app/mbedtls/library/ssl_cli.c | 222 +- app/mbedtls/library/ssl_cookie.c | 10 +- app/mbedtls/library/ssl_srv.c | 614 +++-- app/mbedtls/library/ssl_ticket.c | 10 +- app/mbedtls/library/ssl_tls.c | 2716 +++++++++++++++------ app/mbedtls/library/threading.c | 44 +- app/mbedtls/library/timing.c | 4 +- app/mbedtls/library/version.c | 2 +- app/mbedtls/library/version_features.c | 66 + app/mbedtls/library/x509.c | 103 +- app/mbedtls/library/x509_create.c | 171 +- app/mbedtls/library/x509_crl.c | 27 +- app/mbedtls/library/x509_crt.c | 1356 +++++----- app/mbedtls/library/x509_csr.c | 29 +- app/mbedtls/library/x509write_crt.c | 65 +- app/mbedtls/library/x509write_csr.c | 54 +- app/mbedtls/library/xtea.c | 8 +- app/mbedtls/platform/mbedtls_mem.c | 4 - app/mbedtls/platform/mbedtls_net.c | 126 - docs/modules/crypto.md | 1 - docs/modules/tls.md | 2 +- 157 files changed, 25839 insertions(+), 7398 deletions(-) create mode 100644 app/include/mbedtls/aria.h create mode 100644 app/include/mbedtls/chacha20.h create mode 100644 app/include/mbedtls/chachapoly.h create mode 100644 app/include/mbedtls/hkdf.h create mode 100644 app/include/mbedtls/nist_kw.h create mode 100644 app/include/mbedtls/platform_util.h create mode 100644 app/include/mbedtls/poly1305.h delete mode 100644 app/include/sys/Espconn_mem.h delete mode 100644 app/mbedtls/app/Espconn_mem.c create mode 100644 app/mbedtls/library/aria.c create mode 100644 app/mbedtls/library/chacha20.c create mode 100644 app/mbedtls/library/chachapoly.c create mode 100644 app/mbedtls/library/hkdf.c create mode 100644 app/mbedtls/library/nist_kw.c create mode 100644 app/mbedtls/library/platform_util.c create mode 100644 app/mbedtls/library/poly1305.c delete mode 100644 app/mbedtls/platform/mbedtls_mem.c diff --git a/app/crypto/digests.c b/app/crypto/digests.c index 0553658129..ddc00580e5 100644 --- a/app/crypto/digests.c +++ b/app/crypto/digests.c @@ -37,10 +37,6 @@ #include #include -#ifdef MD2_ENABLE -#include "ssl/ssl_crypto.h" -#endif - #ifdef SHA2_ENABLE #include "sha2.h" #endif @@ -60,9 +56,6 @@ typedef char ensure_int_and_size_t_same[(sizeof(int)==sizeof(size_t)) ? 0 : -1]; static const digest_mech_info_t hash_mechs[] ICACHE_RODATA_ATTR = { -#ifdef MD2_ENABLE - MECH(MD2, _ , MD2_SIZE, 16), -#endif MECH(MD5, , MD5_DIGEST_LENGTH, 64) ,MECH(SHA1, , SHA1_DIGEST_LENGTH, 64) #ifdef SHA2_ENABLE diff --git a/app/include/lwip/memp_std.h b/app/include/lwip/memp_std.h index e300c8bbc7..e561abe070 100644 --- a/app/include/lwip/memp_std.h +++ b/app/include/lwip/memp_std.h @@ -52,14 +52,14 @@ LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom #endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ #if LWIP_NETCONN -LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") -LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") +LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF", DMEM_ATTR) +LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN", DMEM_ATTR) #endif /* LWIP_NETCONN */ #if NO_SYS==0 -LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API", DMEM_ATTR) #if !LWIP_TCPIP_CORE_LOCKING_INPUT -LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT", DMEM_ATTR) #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ #endif /* NO_SYS==0 */ @@ -82,13 +82,13 @@ LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbin LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE") #endif /* LWIP_SNMP */ #if LWIP_DNS && LWIP_SOCKET -LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB", DMEM_ATTR) #endif /* LWIP_DNS && LWIP_SOCKET */ #if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC -LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST", DMEM_ATTR) #endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #if PPP_SUPPORT && PPPOE_SUPPORT -LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") +LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF", DMEM_ATTR) #endif /* PPP_SUPPORT && PPPOE_SUPPORT */ /* diff --git a/app/include/mbedtls/aes.h b/app/include/mbedtls/aes.h index 46016dcb7f..94e7282d36 100644 --- a/app/include/mbedtls/aes.h +++ b/app/include/mbedtls/aes.h @@ -1,7 +1,9 @@ /** * \file aes.h * - * \brief The Advanced Encryption Standard (AES) specifies a FIPS-approved + * \brief This file contains AES definitions and functions. + * + * The Advanced Encryption Standard (AES) specifies a FIPS-approved * cryptographic algorithm that can be used to protect electronic * data. * @@ -11,7 +13,13 @@ * ISO/IEC 18033-2:2006: Information technology -- Security * techniques -- Encryption algorithms -- Part 2: Asymmetric * ciphers. + * + * The AES-XTS block mode is standardized by NIST SP 800-38E + * + * and described in detail by IEEE P1619 + * . */ + /* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 * @@ -50,8 +58,13 @@ #define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ #define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ -/* Error codes in range 0x0023-0x0025 */ +/* Error codes in range 0x0021-0x0025 */ +#define MBEDTLS_ERR_AES_BAD_INPUT_DATA -0x0021 /**< Invalid input data. */ + +/* MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE is deprecated and should not be used. */ #define MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE -0x0023 /**< Feature not available. For example, an unsupported AES key size. */ + +/* MBEDTLS_ERR_AES_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_AES_HW_ACCEL_FAILED -0x0025 /**< AES hardware accelerator failed. */ #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ @@ -59,18 +72,18 @@ #define inline __inline #endif -#if !defined(MBEDTLS_AES_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_AES_ALT) +// Regular implementation +// + /** * \brief The AES context-type definition. */ -typedef struct +typedef struct mbedtls_aes_context { int nr; /*!< The number of rounds. */ uint32_t *rk; /*!< AES round keys. */ @@ -85,13 +98,30 @@ typedef struct } mbedtls_aes_context; +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief The AES XTS context-type definition. + */ +typedef struct mbedtls_aes_xts_context +{ + mbedtls_aes_context crypt; /*!< The AES context to use for AES block + encryption or decryption. */ + mbedtls_aes_context tweak; /*!< The AES context used for tweak + computation. */ +} mbedtls_aes_xts_context; +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#else /* MBEDTLS_AES_ALT */ +#include "aes_alt.h" +#endif /* MBEDTLS_AES_ALT */ + /** * \brief This function initializes the specified AES context. * * It must be the first API called before using * the context. * - * \param ctx The AES context to initialize. + * \param ctx The AES context to initialize. This must not be \c NULL. */ void mbedtls_aes_init( mbedtls_aes_context *ctx ); @@ -99,21 +129,46 @@ void mbedtls_aes_init( mbedtls_aes_context *ctx ); * \brief This function releases and clears the specified AES context. * * \param ctx The AES context to clear. + * If this is \c NULL, this function does nothing. + * Otherwise, the context must have been at least initialized. */ void mbedtls_aes_free( mbedtls_aes_context *ctx ); +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function initializes the specified AES XTS context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES XTS context to initialize. This must not be \c NULL. + */ +void mbedtls_aes_xts_init( mbedtls_aes_xts_context *ctx ); + +/** + * \brief This function releases and clears the specified AES XTS context. + * + * \param ctx The AES XTS context to clear. + * If this is \c NULL, this function does nothing. + * Otherwise, the context must have been at least initialized. + */ +void mbedtls_aes_xts_free( mbedtls_aes_xts_context *ctx ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + /** * \brief This function sets the encryption key. * * \param ctx The AES context to which the key should be bound. + * It must be initialized. * \param key The encryption key. + * This must be a readable buffer of size \p keybits bits. * \param keybits The size of data passed in bits. Valid options are: *
  • 128 bits
  • *
  • 192 bits
  • *
  • 256 bits
* - * \return \c 0 on success or #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH - * on failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. */ int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits ); @@ -122,17 +177,62 @@ int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, * \brief This function sets the decryption key. * * \param ctx The AES context to which the key should be bound. + * It must be initialized. * \param key The decryption key. + * This must be a readable buffer of size \p keybits bits. * \param keybits The size of data passed. Valid options are: *
  • 128 bits
  • *
  • 192 bits
  • *
  • 256 bits
* - * \return \c 0 on success, or #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. */ int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits ); +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function prepares an XTS context for encryption and + * sets the encryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * It must be initialized. + * \param key The encryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_xts_setkey_enc( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function prepares an XTS context for decryption and + * sets the decryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * It must be initialized. + * \param key The decryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + /** * \brief This function performs an AES single-block encryption or * decryption operation. @@ -146,10 +246,13 @@ int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, * call to this API with the same context. * * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or * #MBEDTLS_AES_DECRYPT. - * \param input The 16-Byte buffer holding the input data. - * \param output The 16-Byte buffer holding the output data. + * \param input The buffer holding the input data. + * It must be readable and at least \c 16 Bytes long. + * \param output The buffer where the output data will be written. + * It must be writeable and at least \c 16 Bytes long. * \return \c 0 on success. */ @@ -172,8 +275,8 @@ int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, * mbedtls_aes_setkey_enc() or mbedtls_aes_setkey_dec() must be called * before the first call to this API with the same context. * - * \note This function operates on aligned blocks, that is, the input size - * must be a multiple of the AES block size of 16 Bytes. + * \note This function operates on full blocks, that is, the input size + * must be a multiple of the AES block size of \c 16 Bytes. * * \note Upon exit, the content of the IV is updated so that you can * call the same function again on the next @@ -184,15 +287,20 @@ int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, * * * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or * #MBEDTLS_AES_DECRYPT. * \param length The length of the input data in Bytes. This must be a - * multiple of the block size (16 Bytes). + * multiple of the block size (\c 16 Bytes). * \param iv Initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. * - * \return \c 0 on success, or #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH * on failure. */ int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, @@ -203,6 +311,50 @@ int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, unsigned char *output ); #endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function performs an AES-XTS encryption or decryption + * operation for an entire XTS data unit. + * + * AES-XTS encrypts or decrypts blocks based on their location as + * defined by a data unit number. The data unit number must be + * provided by \p data_unit. + * + * NIST SP 800-38E limits the maximum size of a data unit to 2^20 + * AES blocks. If the data unit is larger than this, this function + * returns #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH. + * + * \param ctx The AES XTS context to use for AES XTS operations. + * It must be initialized and bound to a key. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param length The length of a data unit in Bytes. This can be any + * length between 16 bytes and 2^24 bytes inclusive + * (between 1 and 2^20 block cipher blocks). + * \param data_unit The address of the data unit encoded as an array of 16 + * bytes in little-endian format. For disk encryption, this + * is typically the index of the block device sector that + * contains the data. + * \param input The buffer holding the input data (which is an entire + * data unit). This function reads \p length Bytes from \p + * input. + * \param output The buffer holding the output data (which is an entire + * data unit). This function writes \p length Bytes to \p + * output. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH if \p length is + * smaller than an AES block in size (16 Bytes) or if \p + * length is larger than 2^20 blocks (16 MiB). + */ +int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + #if defined(MBEDTLS_CIPHER_MODE_CFB) /** * \brief This function performs an AES-CFB128 encryption or decryption @@ -228,13 +380,18 @@ int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, * * * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or * #MBEDTLS_AES_DECRYPT. - * \param length The length of the input data. + * \param length The length of the input data in Bytes. * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. * * \return \c 0 on success. */ @@ -269,12 +426,16 @@ int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, * * * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or * #MBEDTLS_AES_DECRYPT * \param length The length of the input data. * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. * * \return \c 0 on success. */ @@ -286,6 +447,61 @@ int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, unsigned char *output ); #endif /*MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/** + * \brief This function performs an AES-OFB (Output Feedback Mode) + * encryption or decryption operation. + * + * For OFB, you must set up the context with + * mbedtls_aes_setkey_enc(), regardless of whether you are + * performing an encryption or decryption operation. This is + * because OFB mode uses the same key schedule for encryption and + * decryption. + * + * The OFB operation is identical for encryption or decryption, + * therefore no operation mode needs to be specified. + * + * \note Upon exit, the content of iv, the Initialisation Vector, is + * updated so that you can call the same function again on the next + * block(s) of data and get the same result as if it was encrypted + * in one call. This allows a "streaming" usage, by initialising + * iv_off to 0 before the first call, and preserving its value + * between calls. + * + * For non-streaming use, the iv should be initialised on each call + * to a unique value, and iv_off set to 0 on each call. + * + * If you need to retain the contents of the initialisation vector, + * you must either save it manually or use the cipher module + * instead. + * + * \warning For the OFB mode, the initialisation vector must be unique + * every encryption operation. Reuse of an initialisation vector + * will compromise security. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param length The length of the input data. + * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_ofb( mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + #if defined(MBEDTLS_CIPHER_MODE_CTR) /** * \brief This function performs an AES-CTR encryption or decryption @@ -300,20 +516,68 @@ int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, * must use the context initialized with mbedtls_aes_setkey_enc() * for both #MBEDTLS_AES_ENCRYPT and #MBEDTLS_AES_DECRYPT. * - * \warning You must keep the maximum use of your counter in mind. + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that an AES block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. * * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. * \param length The length of the input data. * \param nc_off The offset in the current \p stream_block, for * resuming within the current cipher stream. The * offset pointer should be 0 at the start of a stream. + * It must point to a valid \c size_t. * \param nonce_counter The 128-bit nonce and counter. + * It must be a readable-writeable buffer of \c 16 Bytes. * \param stream_block The saved stream block for resuming. This is * overwritten by the function. + * It must be a readable-writeable buffer of \c 16 Bytes. * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. * - * \return \c 0 on success. + * \return \c 0 on success. */ int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, size_t length, @@ -364,7 +628,7 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, * \brief Deprecated internal AES block encryption function * without return value. * - * \deprecated Superseded by mbedtls_aes_encrypt_ext() in 2.5.0. + * \deprecated Superseded by mbedtls_internal_aes_encrypt() * * \param ctx The AES context to use for encryption. * \param input Plaintext block. @@ -378,7 +642,7 @@ MBEDTLS_DEPRECATED void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, * \brief Deprecated internal AES block decryption function * without return value. * - * \deprecated Superseded by mbedtls_aes_decrypt_ext() in 2.5.0. + * \deprecated Superseded by mbedtls_internal_aes_decrypt() * * \param ctx The AES context to use for decryption. * \param input Ciphertext block. @@ -391,25 +655,18 @@ MBEDTLS_DEPRECATED void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_AES_ALT */ -#include "aes_alt.h" -#endif /* MBEDTLS_AES_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief Checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_aes_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/aesni.h b/app/include/mbedtls/aesni.h index 746baa0e17..a4ca012f8a 100644 --- a/app/include/mbedtls/aesni.h +++ b/app/include/mbedtls/aesni.h @@ -2,6 +2,9 @@ * \file aesni.h * * \brief AES-NI for hardware AES acceleration on some Intel processors + * + * \warning These functions are only for internal use by other library + * functions; you must not call them directly. */ /* * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved @@ -24,6 +27,12 @@ #ifndef MBEDTLS_AESNI_H #define MBEDTLS_AESNI_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "aes.h" #define MBEDTLS_AESNI_AES 0x02000000u @@ -42,7 +51,10 @@ extern "C" { #endif /** - * \brief AES-NI features detection routine + * \brief Internal function to detect the AES-NI feature in CPUs. + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param what The feature to detect * (MBEDTLS_AESNI_AES or MBEDTLS_AESNI_CLMUL) @@ -52,7 +64,10 @@ extern "C" { int mbedtls_aesni_has_support( unsigned int what ); /** - * \brief AES-NI AES-ECB block en(de)cryption + * \brief Internal AES-NI AES-ECB block encryption and decryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param ctx AES context * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT @@ -62,12 +77,15 @@ int mbedtls_aesni_has_support( unsigned int what ); * \return 0 on success (cannot fail) */ int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ); + int mode, + const unsigned char input[16], + unsigned char output[16] ); /** - * \brief GCM multiplication: c = a * b in GF(2^128) + * \brief Internal GCM multiplication: c = a * b in GF(2^128) + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param c Result * \param a First operand @@ -77,21 +95,29 @@ int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, * elements of GF(2^128) as per the GCM spec. */ void mbedtls_aesni_gcm_mult( unsigned char c[16], - const unsigned char a[16], - const unsigned char b[16] ); + const unsigned char a[16], + const unsigned char b[16] ); /** - * \brief Compute decryption round keys from encryption round keys + * \brief Internal round key inversion. This function computes + * decryption round keys from the encryption round keys. + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param invkey Round keys for the equivalent inverse cipher * \param fwdkey Original round keys (for encryption) * \param nr Number of rounds (that is, number of round keys minus one) */ void mbedtls_aesni_inverse_key( unsigned char *invkey, - const unsigned char *fwdkey, int nr ); + const unsigned char *fwdkey, + int nr ); /** - * \brief Perform key expansion (for encryption) + * \brief Internal key expansion for encryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param rk Destination buffer where the round keys are written * \param key Encryption key @@ -100,8 +126,8 @@ void mbedtls_aesni_inverse_key( unsigned char *invkey, * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH */ int mbedtls_aesni_setkey_enc( unsigned char *rk, - const unsigned char *key, - size_t bits ); + const unsigned char *key, + size_t bits ); #ifdef __cplusplus } diff --git a/app/include/mbedtls/arc4.h b/app/include/mbedtls/arc4.h index f9d93f822f..fb044d5b7f 100644 --- a/app/include/mbedtls/arc4.h +++ b/app/include/mbedtls/arc4.h @@ -36,16 +36,17 @@ #include +/* MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED -0x0019 /**< ARC4 hardware accelerator failed. */ -#if !defined(MBEDTLS_ARC4_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_ARC4_ALT) +// Regular implementation +// + /** * \brief ARC4 context structure * @@ -53,7 +54,7 @@ extern "C" { * security risk. We recommend considering stronger ciphers instead. * */ -typedef struct +typedef struct mbedtls_arc4_context { int x; /*!< permutation index */ int y; /*!< permutation index */ @@ -61,6 +62,10 @@ typedef struct } mbedtls_arc4_context; +#else /* MBEDTLS_ARC4_ALT */ +#include "arc4_alt.h" +#endif /* MBEDTLS_ARC4_ALT */ + /** * \brief Initialize ARC4 context * @@ -118,17 +123,7 @@ void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, unsigned char *output ); -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_ARC4_ALT */ -#include "arc4_alt.h" -#endif /* MBEDTLS_ARC4_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief Checkup routine @@ -142,6 +137,8 @@ extern "C" { */ int mbedtls_arc4_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/aria.h b/app/include/mbedtls/aria.h new file mode 100644 index 0000000000..1e8956ed13 --- /dev/null +++ b/app/include/mbedtls/aria.h @@ -0,0 +1,370 @@ +/** + * \file aria.h + * + * \brief ARIA block cipher + * + * The ARIA algorithm is a symmetric block cipher that can encrypt and + * decrypt information. It is defined by the Korean Agency for + * Technology and Standards (KATS) in KS X 1213:2004 (in + * Korean, but see http://210.104.33.10/ARIA/index-e.html in English) + * and also described by the IETF in RFC 5794. + */ +/* Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_ARIA_H +#define MBEDTLS_ARIA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#include "platform_util.h" + +#define MBEDTLS_ARIA_ENCRYPT 1 /**< ARIA encryption. */ +#define MBEDTLS_ARIA_DECRYPT 0 /**< ARIA decryption. */ + +#define MBEDTLS_ARIA_BLOCKSIZE 16 /**< ARIA block size in bytes. */ +#define MBEDTLS_ARIA_MAX_ROUNDS 16 /**< Maxiumum number of rounds in ARIA. */ +#define MBEDTLS_ARIA_MAX_KEYSIZE 32 /**< Maximum size of an ARIA key in bytes. */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#define MBEDTLS_ERR_ARIA_INVALID_KEY_LENGTH MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( -0x005C ) +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#define MBEDTLS_ERR_ARIA_BAD_INPUT_DATA -0x005C /**< Bad input data. */ + +#define MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH -0x005E /**< Invalid data input length. */ + +/* MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE is deprecated and should not be used. + */ +#define MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE -0x005A /**< Feature not available. For example, an unsupported ARIA key size. */ + +/* MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED -0x0058 /**< ARIA hardware accelerator failed. */ + +#if !defined(MBEDTLS_ARIA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The ARIA context-type definition. + */ +typedef struct mbedtls_aria_context +{ + unsigned char nr; /*!< The number of rounds (12, 14 or 16) */ + /*! The ARIA round keys. */ + uint32_t rk[MBEDTLS_ARIA_MAX_ROUNDS + 1][MBEDTLS_ARIA_BLOCKSIZE / 4]; +} +mbedtls_aria_context; + +#else /* MBEDTLS_ARIA_ALT */ +#include "aria_alt.h" +#endif /* MBEDTLS_ARIA_ALT */ + +/** + * \brief This function initializes the specified ARIA context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The ARIA context to initialize. This must not be \c NULL. + */ +void mbedtls_aria_init( mbedtls_aria_context *ctx ); + +/** + * \brief This function releases and clears the specified ARIA context. + * + * \param ctx The ARIA context to clear. This may be \c NULL, in which + * case this function returns immediately. If it is not \c NULL, + * it must point to an initialized ARIA context. + */ +void mbedtls_aria_free( mbedtls_aria_context *ctx ); + +/** + * \brief This function sets the encryption key. + * + * \param ctx The ARIA context to which the key should be bound. + * This must be initialized. + * \param key The encryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The size of \p key in Bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_setkey_enc( mbedtls_aria_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function sets the decryption key. + * + * \param ctx The ARIA context to which the key should be bound. + * This must be initialized. + * \param key The decryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The size of data passed. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_setkey_dec( mbedtls_aria_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function performs an ARIA single-block encryption or + * decryption operation. + * + * It performs encryption or decryption (depending on whether + * the key was set for encryption on decryption) on the input + * data buffer defined in the \p input parameter. + * + * mbedtls_aria_init(), and either mbedtls_aria_setkey_enc() or + * mbedtls_aria_setkey_dec() must be called before the first + * call to this API with the same context. + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param input The 16-Byte buffer holding the input data. + * \param output The 16-Byte buffer holding the output data. + + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_ecb( mbedtls_aria_context *ctx, + const unsigned char input[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char output[MBEDTLS_ARIA_BLOCKSIZE] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief This function performs an ARIA-CBC encryption or decryption operation + * on full blocks. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined in + * the \p input parameter. + * + * It can be called as many times as needed, until all the input + * data is processed. mbedtls_aria_init(), and either + * mbedtls_aria_setkey_enc() or mbedtls_aria_setkey_dec() must be called + * before the first call to this API with the same context. + * + * \note This function operates on aligned blocks, that is, the input size + * must be a multiple of the ARIA block size of 16 Bytes. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the IV, you should + * either save it manually or use the cipher module instead. + * + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_ARIA_ENCRYPT for encryption, or + * #MBEDTLS_ARIA_DECRYPT for decryption. + * \param length The length of the input data in Bytes. This must be a + * multiple of the block size (16 Bytes). + * \param iv Initialization vector (updated after use). + * This must be a readable buffer of size 16 Bytes. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_cbc( mbedtls_aria_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief This function performs an ARIA-CFB128 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt or decrypt), on the input data buffer + * defined in the \p input parameter. + * + * For CFB, you must set up the context with mbedtls_aria_setkey_enc(), + * regardless of whether you are performing an encryption or decryption + * operation, that is, regardless of the \p mode parameter. This is + * because CFB mode uses the same key schedule for encryption and + * decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you must either save it manually or use the cipher + * module instead. + * + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_ARIA_ENCRYPT for encryption, or + * #MBEDTLS_ARIA_DECRYPT for decryption. + * \param length The length of the input data \p input in Bytes. + * \param iv_off The offset in IV (updated after use). + * This must not be larger than 15. + * \param iv The initialization vector (updated after use). + * This must be a readable buffer of size 16 Bytes. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_cfb128( mbedtls_aria_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief This function performs an ARIA-CTR encryption or decryption + * operation. + * + * This function performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer + * defined in the \p input parameter. + * + * Due to the nature of CTR, you must use the same key schedule + * for both encryption and decryption operations. Therefore, you + * must use the context initialized with mbedtls_aria_setkey_enc() + * for both #MBEDTLS_ARIA_ENCRYPT and #MBEDTLS_ARIA_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that an ARIA block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param length The length of the input data \p input in Bytes. + * \param nc_off The offset in Bytes in the current \p stream_block, + * for resuming within the current cipher stream. The + * offset pointer should be \c 0 at the start of a + * stream. This must not be larger than \c 15 Bytes. + * \param nonce_counter The 128-bit nonce and counter. This must point to + * a read/write buffer of length \c 16 bytes. + * \param stream_block The saved stream block for resuming. This must + * point to a read/write buffer of length \c 16 bytes. + * This is overwritten by the function. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_ctr( mbedtls_aria_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine. + * + * \return \c 0 on success, or \c 1 on failure. + */ +int mbedtls_aria_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* aria.h */ diff --git a/app/include/mbedtls/asn1write.h b/app/include/mbedtls/asn1write.h index f76fc807d0..a194243696 100644 --- a/app/include/mbedtls/asn1write.h +++ b/app/include/mbedtls/asn1write.h @@ -24,193 +24,281 @@ #ifndef MBEDTLS_ASN1_WRITE_H #define MBEDTLS_ASN1_WRITE_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "asn1.h" -#define MBEDTLS_ASN1_CHK_ADD(g, f) do { if( ( ret = f ) < 0 ) return( ret ); else \ - g += ret; } while( 0 ) +#define MBEDTLS_ASN1_CHK_ADD(g, f) \ + do \ + { \ + if( ( ret = (f) ) < 0 ) \ + return( ret ); \ + else \ + (g) += ret; \ + } while( 0 ) #ifdef __cplusplus extern "C" { #endif /** - * \brief Write a length field in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write a length field in ASN.1 format. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param len the length to write + * \note This function works backwards in data buffer. * - * \return the length written or a negative error code + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param len The length value to write. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ -int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ); - +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, + size_t len ); /** - * \brief Write a ASN.1 tag in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write an ASN.1 tag in ASN.1 format. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param tag the tag to write + * \note This function works backwards in data buffer. * - * \return the length written or a negative error code + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param tag The tag to write. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, - unsigned char tag ); + unsigned char tag ); /** - * \brief Write raw buffer data - * Note: function works backwards in data buffer + * \brief Write raw buffer data. + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param buf data buffer to write - * \param size length of the data buffer + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param buf The data buffer to write. + * \param size The length of the data buffer. * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, - const unsigned char *buf, size_t size ); + const unsigned char *buf, size_t size ); #if defined(MBEDTLS_BIGNUM_C) /** - * \brief Write a big number (MBEDTLS_ASN1_INTEGER) in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write a arbitrary-precision number (#MBEDTLS_ASN1_INTEGER) + * in ASN.1 format. + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param X the MPI to write + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param X The MPI to write. * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ -int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ); +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, + const mbedtls_mpi *X ); #endif /* MBEDTLS_BIGNUM_C */ /** - * \brief Write a NULL tag (MBEDTLS_ASN1_NULL) with zero data in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write a NULL tag (#MBEDTLS_ASN1_NULL) with zero data + * in ASN.1 format. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) + * \note This function works backwards in data buffer. * - * \return the length written or a negative error code + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ); /** - * \brief Write an OID tag (MBEDTLS_ASN1_OID) and data in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write an OID tag (#MBEDTLS_ASN1_OID) and data + * in ASN.1 format. + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param oid the OID to write - * \param oid_len length of the OID + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param oid The OID to write. + * \param oid_len The length of the OID. * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, - const char *oid, size_t oid_len ); + const char *oid, size_t oid_len ); /** - * \brief Write an AlgorithmIdentifier sequence in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write an AlgorithmIdentifier sequence in ASN.1 format. + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param oid the OID of the algorithm - * \param oid_len length of the OID - * \param par_len length of parameters, which must be already written. + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param oid The OID of the algorithm to write. + * \param oid_len The length of the algorithm's OID. + * \param par_len The length of the parameters, which must be already written. * If 0, NULL parameters are added * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ -int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, - const char *oid, size_t oid_len, - size_t par_len ); +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, + unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ); /** - * \brief Write a boolean tag (MBEDTLS_ASN1_BOOLEAN) and value in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write a boolean tag (#MBEDTLS_ASN1_BOOLEAN) and value + * in ASN.1 format. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param boolean 0 or 1 + * \note This function works backwards in data buffer. * - * \return the length written or a negative error code + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param boolean The boolean value to write, either \c 0 or \c 1. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ -int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ); +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, + int boolean ); /** - * \brief Write an int tag (MBEDTLS_ASN1_INTEGER) and value in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write an int tag (#MBEDTLS_ASN1_INTEGER) and value + * in ASN.1 format. + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param val the integer value + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param val The integer value to write. * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ); /** - * \brief Write a printable string tag (MBEDTLS_ASN1_PRINTABLE_STRING) and - * value in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write a string in ASN.1 format using a specific + * string encoding tag. + + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param tag The string encoding tag to write, e.g. + * #MBEDTLS_ASN1_UTF8_STRING. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, + int tag, const char *text, + size_t text_len ); + +/** + * \brief Write a string in ASN.1 format using the PrintableString + * string encoding tag (#MBEDTLS_ASN1_PRINTABLE_STRING). + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param text the text to write - * \param text_len length of the text + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. */ -int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, - const char *text, size_t text_len ); +int mbedtls_asn1_write_printable_string( unsigned char **p, + unsigned char *start, + const char *text, size_t text_len ); /** - * \brief Write an IA5 string tag (MBEDTLS_ASN1_IA5_STRING) and - * value in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write a UTF8 string in ASN.1 format using the UTF8String + * string encoding tag (#MBEDTLS_ASN1_PRINTABLE_STRING). * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param text the text to write - * \param text_len length of the text + * \note This function works backwards in data buffer. * - * \return the length written or a negative error code + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write a string in ASN.1 format using the IA5String + * string encoding tag (#MBEDTLS_ASN1_IA5_STRING). + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. */ int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, - const char *text, size_t text_len ); + const char *text, size_t text_len ); /** - * \brief Write a bitstring tag (MBEDTLS_ASN1_BIT_STRING) and - * value in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write a bitstring tag (#MBEDTLS_ASN1_BIT_STRING) and + * value in ASN.1 format. + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param buf the bitstring - * \param bits the total number of bits in the bitstring + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param buf The bitstring to write. + * \param bits The total number of bits in the bitstring. * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. */ int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, - const unsigned char *buf, size_t bits ); + const unsigned char *buf, size_t bits ); /** - * \brief Write an octet string tag (MBEDTLS_ASN1_OCTET_STRING) and - * value in ASN.1 format - * Note: function works backwards in data buffer + * \brief Write an octet string tag (#MBEDTLS_ASN1_OCTET_STRING) + * and value in ASN.1 format. + * + * \note This function works backwards in data buffer. * - * \param p reference to current position pointer - * \param start start of the buffer (for bounds-checking) - * \param buf data buffer to write - * \param size length of the data buffer + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param buf The buffer holding the data to write. + * \param size The length of the data buffer \p buf. * - * \return the length written or a negative error code + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. */ int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, - const unsigned char *buf, size_t size ); + const unsigned char *buf, size_t size ); /** * \brief Create or find a specific named_data entry for writing in a @@ -218,15 +306,16 @@ int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, * a new entry is added to the head of the list. * Warning: Destructive behaviour for the val data! * - * \param list Pointer to the location of the head of the list to seek - * through (will be updated in case of a new entry) - * \param oid The OID to look for - * \param oid_len Size of the OID - * \param val Data to store (can be NULL if you want to fill it by hand) - * \param val_len Minimum length of the data buffer needed + * \param list The pointer to the location of the head of the list to seek + * through (will be updated in case of a new entry). + * \param oid The OID to look for. + * \param oid_len The size of the OID. + * \param val The data to store (can be \c NULL if you want to fill + * it by hand). + * \param val_len The minimum length of the data buffer needed. * - * \return NULL if if there was a memory allocation error, or a pointer - * to the new / existing entry. + * \return A pointer to the new / existing entry on success. + * \return \c NULL if if there was a memory allocation error. */ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **list, const char *oid, size_t oid_len, diff --git a/app/include/mbedtls/base64.h b/app/include/mbedtls/base64.h index 7a64f52163..0d024164c5 100644 --- a/app/include/mbedtls/base64.h +++ b/app/include/mbedtls/base64.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_BASE64_H #define MBEDTLS_BASE64_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include #define MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ @@ -75,6 +81,7 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen ); +#if defined(MBEDTLS_SELF_TEST) /** * \brief Checkup routine * @@ -82,6 +89,8 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, */ int mbedtls_base64_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/bignum.h b/app/include/mbedtls/bignum.h index 3bf02a7ee1..1c8607264f 100644 --- a/app/include/mbedtls/bignum.h +++ b/app/include/mbedtls/bignum.h @@ -46,7 +46,12 @@ #define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ #define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */ -#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) +#define MBEDTLS_MPI_CHK(f) \ + do \ + { \ + if( ( ret = (f) ) != 0 ) \ + goto cleanup; \ + } while( 0 ) /* * Maximum size MPIs are allowed to grow to in number of limbs. @@ -177,7 +182,7 @@ extern "C" { /** * \brief MPI structure */ -typedef struct +typedef struct mbedtls_mpi { int s; /*!< integer sign */ size_t n; /*!< total # of limbs */ @@ -186,90 +191,115 @@ typedef struct mbedtls_mpi; /** - * \brief Initialize one MPI (make internal references valid) - * This just makes it ready to be set or freed, + * \brief Initialize an MPI context. + * + * This makes the MPI ready to be set or freed, * but does not define a value for the MPI. * - * \param X One MPI to initialize. + * \param X The MPI context to initialize. This must not be \c NULL. */ void mbedtls_mpi_init( mbedtls_mpi *X ); /** - * \brief Unallocate one MPI + * \brief This function frees the components of an MPI context. * - * \param X One MPI to unallocate. + * \param X The MPI context to be cleared. This may be \c NULL, + * in which case this function is a no-op. If it is + * not \c NULL, it must point to an initialized MPI. */ void mbedtls_mpi_free( mbedtls_mpi *X ); /** - * \brief Enlarge to the specified number of limbs + * \brief Enlarge an MPI to the specified number of limbs. + * + * \note This function does nothing if the MPI is + * already large enough. * - * \param X MPI to grow - * \param nblimbs The target number of limbs + * \param X The MPI to grow. It must be initialized. + * \param nblimbs The target number of limbs. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. */ int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ); /** - * \brief Resize down, keeping at least the specified number of limbs + * \brief This function resizes an MPI downwards, keeping at least the + * specified number of limbs. + * + * If \c X is smaller than \c nblimbs, it is resized up + * instead. * - * \param X MPI to shrink - * \param nblimbs The minimum number of limbs to keep + * \param X The MPI to shrink. This must point to an initialized MPI. + * \param nblimbs The minimum number of limbs to keep. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * (this can only happen when resizing up). + * \return Another negative error code on other kinds of failure. */ int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ); /** - * \brief Copy the contents of Y into X + * \brief Make a copy of an MPI. * - * \param X Destination MPI - * \param Y Source MPI + * \param X The destination MPI. This must point to an initialized MPI. + * \param Y The source MPI. This must point to an initialized MPI. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \note The limb-buffer in the destination MPI is enlarged + * if necessary to hold the value in the source MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. */ int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ); /** - * \brief Swap the contents of X and Y + * \brief Swap the contents of two MPIs. * - * \param X First MPI value - * \param Y Second MPI value + * \param X The first MPI. It must be initialized. + * \param Y The second MPI. It must be initialized. */ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); /** - * \brief Safe conditional assignement X = Y if assign is 1 - * - * \param X MPI to conditionally assign to - * \param Y Value to be assigned - * \param assign 1: perform the assignment, 0: keep X's original value + * \brief Perform a safe conditional copy of MPI which doesn't + * reveal whether the condition was true or not. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * \param X The MPI to conditionally assign to. This must point + * to an initialized MPI. + * \param Y The MPI to be assigned from. This must point to an + * initialized MPI. + * \param assign The condition deciding whether to perform the + * assignment or not. Possible values: + * * \c 1: Perform the assignment `X = Y`. + * * \c 0: Keep the original value of \p X. * * \note This function is equivalent to - * if( assign ) mbedtls_mpi_copy( X, Y ); + * `if( assign ) mbedtls_mpi_copy( X, Y );` * except that it avoids leaking any information about whether * the assignment was done or not (the above code may leak * information through branch prediction and/or memory access * patterns analysis). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. */ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ); /** - * \brief Safe conditional swap X <-> Y if swap is 1 - * - * \param X First mbedtls_mpi value - * \param Y Second mbedtls_mpi value - * \param assign 1: perform the swap, 0: keep X and Y's original values + * \brief Perform a safe conditional swap which doesn't + * reveal whether the condition was true or not. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * \param X The first MPI. This must be initialized. + * \param Y The second MPI. This must be initialized. + * \param assign The condition deciding whether to perform + * the swap or not. Possible values: + * * \c 1: Swap the values of \p X and \p Y. + * * \c 0: Keep the original values of \p X and \p Y. * * \note This function is equivalent to * if( assign ) mbedtls_mpi_swap( X, Y ); @@ -277,415 +307,512 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned * the assignment was done or not (the above code may leak * information through branch prediction and/or memory access * patterns analysis). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + * */ int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); /** - * \brief Set value from integer + * \brief Store integer value in MPI. * - * \param X MPI to set - * \param z Value to use + * \param X The MPI to set. This must be initialized. + * \param z The value to use. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. */ int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ); /** - * \brief Get a specific bit from X + * \brief Get a specific bit from an MPI. * - * \param X MPI to use - * \param pos Zero-based index of the bit in X + * \param X The MPI to query. This must be initialized. + * \param pos Zero-based index of the bit to query. * - * \return Either a 0 or a 1 + * \return \c 0 or \c 1 on success, depending on whether bit \c pos + * of \c X is unset or set. + * \return A negative error code on failure. */ int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ); /** - * \brief Set a bit of X to a specific value of 0 or 1 + * \brief Modify a specific bit in an MPI. * - * \note Will grow X if necessary to set a bit to 1 in a not yet - * existing limb. Will not grow if bit should be set to 0 + * \note This function will grow the target MPI if necessary to set a + * bit to \c 1 in a not yet existing limb. It will not grow if + * the bit should be set to \c 0. * - * \param X MPI to use - * \param pos Zero-based index of the bit in X - * \param val The value to set the bit to (0 or 1) + * \param X The MPI to modify. This must be initialized. + * \param pos Zero-based index of the bit to modify. + * \param val The desired value of bit \c pos: \c 0 or \c 1. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. */ int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ); /** - * \brief Return the number of zero-bits before the least significant - * '1' bit + * \brief Return the number of bits of value \c 0 before the + * least significant bit of value \c 1. * - * Note: Thus also the zero-based index of the least significant '1' bit + * \note This is the same as the zero-based index of + * the least significant bit of value \c 1. * - * \param X MPI to use + * \param X The MPI to query. + * + * \return The number of bits of value \c 0 before the least significant + * bit of value \c 1 in \p X. */ size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ); /** * \brief Return the number of bits up to and including the most - * significant '1' bit' + * significant bit of value \c 1. + * + * * \note This is same as the one-based index of the most + * significant bit of value \c 1. * - * Note: Thus also the one-based index of the most significant '1' bit + * \param X The MPI to query. This must point to an initialized MPI. * - * \param X MPI to use + * \return The number of bits up to and including the most + * significant bit of value \c 1. */ size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ); /** - * \brief Return the total size in bytes + * \brief Return the total size of an MPI value in bytes. + * + * \param X The MPI to use. This must point to an initialized MPI. + * + * \note The value returned by this function may be less than + * the number of bytes used to store \p X internally. + * This happens if and only if there are trailing bytes + * of value zero. * - * \param X MPI to use + * \return The least number of bytes capable of storing + * the absolute value of \p X. */ size_t mbedtls_mpi_size( const mbedtls_mpi *X ); /** - * \brief Import from an ASCII string + * \brief Import an MPI from an ASCII string. * - * \param X Destination MPI - * \param radix Input numeric base - * \param s Null-terminated string buffer + * \param X The destination MPI. This must point to an initialized MPI. + * \param radix The numeric base of the input string. + * \param s Null-terminated string buffer. * - * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ); /** - * \brief Export into an ASCII string + * \brief Export an MPI to an ASCII string. * - * \param X Source MPI - * \param radix Output numeric base - * \param buf Buffer to write the string to - * \param buflen Length of buf - * \param olen Length of the string written, including final NUL byte + * \param X The source MPI. This must point to an initialized MPI. + * \param radix The numeric base of the output string. + * \param buf The buffer to write the string to. This must be writable + * buffer of length \p buflen Bytes. + * \param buflen The available size in Bytes of \p buf. + * \param olen The address at which to store the length of the string + * written, including the final \c NULL byte. This must + * not be \c NULL. * - * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code. - * *olen is always updated to reflect the amount - * of data that has (or would have) been written. + * \note You can call this function with `buflen == 0` to obtain the + * minimum required buffer size in `*olen`. * - * \note Call this function with buflen = 0 to obtain the - * minimum required buffer size in *olen. + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the target buffer \p buf + * is too small to hold the value of \p X in the desired base. + * In this case, `*olen` is nonetheless updated to contain the + * size of \p buf required for a successful call. + * \return Another negative error code on different kinds of failure. */ int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, char *buf, size_t buflen, size_t *olen ); #if defined(MBEDTLS_FS_IO) /** - * \brief Read MPI from a line in an opened file + * \brief Read an MPI from a line in an opened file. * - * \param X Destination MPI - * \param radix Input numeric base - * \param fin Input file handle - * - * \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if - * the file read buffer is too small or a - * MBEDTLS_ERR_MPI_XXX error code + * \param X The destination MPI. This must point to an initialized MPI. + * \param radix The numeric base of the string representation used + * in the source line. + * \param fin The input file handle to use. This must not be \c NULL. * * \note On success, this function advances the file stream * to the end of the current line or to EOF. * - * The function returns 0 on an empty line. + * The function returns \c 0 on an empty line. * * Leading whitespaces are ignored, as is a - * '0x' prefix for radix 16. + * '0x' prefix for radix \c 16. * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the file read buffer + * is too small. + * \return Another negative error code on failure. */ int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ); /** - * \brief Write X into an opened file, or stdout if fout is NULL - * - * \param p Prefix, can be NULL - * \param X Source MPI - * \param radix Output numeric base - * \param fout Output file handle (can be NULL) + * \brief Export an MPI into an opened file. * - * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * \param p A string prefix to emit prior to the MPI data. + * For example, this might be a label, or "0x" when + * printing in base \c 16. This may be \c NULL if no prefix + * is needed. + * \param X The source MPI. This must point to an initialized MPI. + * \param radix The numeric base to be used in the emitted string. + * \param fout The output file handle. This may be \c NULL, in which case + * the output is written to \c stdout. * - * \note Set fout == NULL to print X on the console. + * \return \c 0 if successful. + * \return A negative error code on failure. */ -int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ); +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, + int radix, FILE *fout ); #endif /* MBEDTLS_FS_IO */ /** - * \brief Import X from unsigned binary data, big endian + * \brief Import an MPI from unsigned big endian binary data. * - * \param X Destination MPI - * \param buf Input buffer - * \param buflen Input buffer size + * \param X The destination MPI. This must point to an initialized MPI. + * \param buf The input buffer. This must be a readable buffer of length + * \p buflen Bytes. + * \param buflen The length of the input buffer \p p in Bytes. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ); +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, + size_t buflen ); /** - * \brief Export X into unsigned binary data, big endian. - * Always fills the whole buffer, which will start with zeros - * if the number is smaller. + * \brief Export an MPI into unsigned big endian binary data + * of fixed size. * - * \param X Source MPI - * \param buf Output buffer - * \param buflen Output buffer size + * \param X The source MPI. This must point to an initialized MPI. + * \param buf The output buffer. This must be a writable buffer of length + * \p buflen Bytes. + * \param buflen The size of the output buffer \p buf in Bytes. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't + * large enough to hold the value of \p X. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ); +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, + size_t buflen ); /** - * \brief Left-shift: X <<= count + * \brief Perform a left-shift on an MPI: X <<= count * - * \param X MPI to shift - * \param count Amount to shift + * \param X The MPI to shift. This must point to an initialized MPI. + * \param count The number of bits to shift by. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ); /** - * \brief Right-shift: X >>= count + * \brief Perform a right-shift on an MPI: X >>= count * - * \param X MPI to shift - * \param count Amount to shift + * \param X The MPI to shift. This must point to an initialized MPI. + * \param count The number of bits to shift by. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ); /** - * \brief Compare unsigned values + * \brief Compare the absolute values of two MPIs. * - * \param X Left-hand MPI - * \param Y Right-hand MPI + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param Y The right-hand MPI. This must point to an initialized MPI. * - * \return 1 if |X| is greater than |Y|, - * -1 if |X| is lesser than |Y| or - * 0 if |X| is equal to |Y| + * \return \c 1 if `|X|` is greater than `|Y|`. + * \return \c -1 if `|X|` is lesser than `|Y|`. + * \return \c 0 if `|X|` is equal to `|Y|`. */ int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ); /** - * \brief Compare signed values + * \brief Compare two MPIs. * - * \param X Left-hand MPI - * \param Y Right-hand MPI + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param Y The right-hand MPI. This must point to an initialized MPI. * - * \return 1 if X is greater than Y, - * -1 if X is lesser than Y or - * 0 if X is equal to Y + * \return \c 1 if \p X is greater than \p Y. + * \return \c -1 if \p X is lesser than \p Y. + * \return \c 0 if \p X is equal to \p Y. */ int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ); /** - * \brief Compare signed values + * \brief Compare an MPI with an integer. * - * \param X Left-hand MPI - * \param z The integer value to compare to + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param z The integer value to compare \p X to. * - * \return 1 if X is greater than z, - * -1 if X is lesser than z or - * 0 if X is equal to z + * \return \c 1 if \p X is greater than \p z. + * \return \c -1 if \p X is lesser than \p z. + * \return \c 0 if \p X is equal to \p z. */ int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ); /** - * \brief Unsigned addition: X = |A| + |B| + * \brief Perform an unsigned addition of MPIs: X = |A| + |B| * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param B The second summand. This must point to an initialized MPI. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Unsigned subtraction: X = |A| - |B| + * \brief Perform an unsigned subtraction of MPIs: X = |A| - |B| * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param B The subtrahend. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p B is greater than \p A. + * \return Another negative error code on different kinds of failure. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A */ -int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Signed addition: X = A + B + * \brief Perform a signed addition of MPIs: X = A + B * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param B The second summand. This must point to an initialized MPI. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Signed subtraction: X = A - B + * \brief Perform a signed subtraction of MPIs: X = A - B * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param B The subtrahend. This must point to an initialized MPI. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Signed addition: X = A + b + * \brief Perform a signed addition of an MPI and an integer: X = A + b * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to add + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param b The second summand. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); /** - * \brief Signed subtraction: X = A - b + * \brief Perform a signed subtraction of an MPI and an integer: + * X = A - b * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to subtract + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param b The subtrahend. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); /** - * \brief Baseline multiplication: X = A * B + * \brief Perform a multiplication of two MPIs: X = A * B + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first factor. This must point to an initialized MPI. + * \param B The second factor. This must point to an initialized MPI. * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed */ -int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Baseline multiplication: X = A * b + * \brief Perform a multiplication of an MPI with an unsigned integer: + * X = A * b * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The unsigned integer value to multiply with + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first factor. This must point to an initialized MPI. + * \param b The second factor. * - * \note b is unsigned + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed */ -int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ); +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_uint b ); /** - * \brief Division by mbedtls_mpi: A = Q * B + R + * \brief Perform a division with remainder of two MPIs: + * A = Q * B + R * - * \param Q Destination MPI for the quotient - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param B Right-hand MPI + * \param Q The destination MPI for the quotient. + * This may be \c NULL if the value of the + * quotient is not needed. + * \param R The destination MPI for the remainder value. + * This may be \c NULL if the value of the + * remainder is not needed. + * \param A The dividend. This must point to an initialized MPi. + * \param B The divisor. This must point to an initialized MPI. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0 - * - * \note Either Q or R can be NULL. + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p B equals zero. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Division by int: A = Q * b + R - * - * \param Q Destination MPI for the quotient - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param b Integer to divide by + * \brief Perform a division with remainder of an MPI by an integer: + * A = Q * b + R * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * \param Q The destination MPI for the quotient. + * This may be \c NULL if the value of the + * quotient is not needed. + * \param R The destination MPI for the remainder value. + * This may be \c NULL if the value of the + * remainder is not needed. + * \param A The dividend. This must point to an initialized MPi. + * \param b The divisor. * - * \note Either Q or R can be NULL. + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p b equals zero. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ); +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); /** - * \brief Modulo: R = A mod B + * \brief Perform a modular reduction. R = A mod B * - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param B Right-hand MPI + * \param R The destination MPI for the residue value. + * This must point to an initialized MPI. + * \param A The MPI to compute the residue of. + * This must point to an initialized MPI. + * \param B The base of the modular reduction. + * This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p B equals zero. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p B is negative. + * \return Another negative error code on different kinds of failure. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0, - * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0 */ -int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Modulo: r = A mod b + * \brief Perform a modular reduction with respect to an integer. + * r = A mod b * - * \param r Destination mbedtls_mpi_uint - * \param A Left-hand MPI - * \param b Integer to divide by + * \param r The address at which to store the residue. + * This must not be \c NULL. + * \param A The MPI to compute the residue of. + * This must point to an initialized MPi. + * \param b The integer base of the modular reduction. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0, - * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0 + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p b equals zero. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p b is negative. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ); +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); /** - * \brief Sliding-window exponentiation: X = A^E mod N - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param E Exponent MPI - * \param N Modular MPI - * \param _RR Speed-up MPI used for recalculations + * \brief Perform a sliding-window exponentiation: X = A^E mod N * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or - * if E is negative + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The base of the exponentiation. + * This must point to an initialized MPI. + * \param E The exponent MPI. This must point to an initialized MPI. + * \param N The base for the modular reduction. This must point to an + * initialized MPI. + * \param _RR A helper MPI depending solely on \p N which can be used to + * speed-up multiple modular exponentiations for the same value + * of \p N. This may be \c NULL. If it is not \c NULL, it must + * point to an initialized MPI. If it hasn't been used after + * the call to mbedtls_mpi_init(), this function will compute + * the helper value and store it in \p _RR for reuse on + * subsequent calls to this function. Otherwise, the function + * will assume that \p _RR holds the helper value set by a + * previous call to mbedtls_mpi_exp_mod(), and reuse it. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \c N is negative or + * even, or if \c E is negative. + * \return Another negative error code on different kinds of failures. * - * \note _RR is used to avoid re-computing R*R mod N across - * multiple calls, which speeds up things a bit. It can - * be set to NULL if the extra performance is unneeded. */ -int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ); +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *_RR ); /** - * \brief Fill an MPI X with size bytes of random + * \brief Fill an MPI with a number of random bytes. * - * \param X Destination MPI - * \param size Size in bytes - * \param f_rng RNG function - * \param p_rng RNG parameter + * \param X The destination MPI. This must point to an initialized MPI. + * \param size The number of random bytes to generate. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on failure. * - * \note The bytes obtained from the PRNG are interpreted + * \note The bytes obtained from the RNG are interpreted * as a big-endian representation of an MPI; this can * be relevant in applications like deterministic ECDSA. */ @@ -694,64 +821,135 @@ int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, void *p_rng ); /** - * \brief Greatest common divisor: G = gcd(A, B) - * - * \param G Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed - */ -int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ); - -/** - * \brief Modular inverse: X = A^-1 mod N + * \brief Compute the greatest common divisor: G = gcd(A, B) * - * \param X Destination MPI - * \param A Left-hand MPI - * \param N Right-hand MPI + * \param G The destination MPI. This must point to an initialized MPI. + * \param A The first operand. This must point to an initialized MPI. + * \param B The second operand. This must point to an initialized MPI. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is <= 1, - MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N. + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. */ -int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ); +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, + const mbedtls_mpi *B ); /** - * \brief Miller-Rabin primality test + * \brief Compute the modular inverse: X = A^-1 mod N * - * \param X MPI to check - * \param f_rng RNG function - * \param p_rng RNG parameter + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The MPI to calculate the modular inverse of. This must point + * to an initialized MPI. + * \param N The base of the modular inversion. This must point to an + * initialized MPI. * - * \return 0 if successful (probably prime), - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p N is less than + * or equal to one. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p has no modular inverse + * with respect to \p N. */ -int mbedtls_mpi_is_prime( const mbedtls_mpi *X, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *N ); +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif /** - * \brief Prime number generation - * - * \param X Destination MPI - * \param nbits Required size of X in bits - * ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS ) - * \param dh_flag If 1, then (X-1)/2 will be prime too - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful (probably prime), - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 - */ -int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + * \brief Perform a Miller-Rabin primality test with error + * probability of 2-80. + * + * \deprecated Superseded by mbedtls_mpi_is_prime_ext() which allows + * specifying the number of Miller-Rabin rounds. + * + * \param X The MPI to check for primality. + * This must point to an initialized MPI. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use a + * context parameter. + * + * \return \c 0 if successful, i.e. \p X is probably prime. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p X is not prime. + * \return Another negative error code on other kinds of failure. + */ +MBEDTLS_DEPRECATED int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Miller-Rabin primality test. + * + * \warning If \p X is potentially generated by an adversary, for example + * when validating cryptographic parameters that you didn't + * generate yourself and that are supposed to be prime, then + * \p rounds should be at least the half of the security + * strength of the cryptographic algorithm. On the other hand, + * if \p X is chosen uniformly or non-adversially (as is the + * case when mbedtls_mpi_gen_prime calls this function), then + * \p rounds can be much lower. + * + * \param X The MPI to check for primality. + * This must point to an initialized MPI. + * \param rounds The number of bases to perform the Miller-Rabin primality + * test for. The probability of returning 0 on a composite is + * at most 2-2*\p rounds. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use + * a context parameter. + * + * \return \c 0 if successful, i.e. \p X is probably prime. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p X is not prime. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +/** + * \brief Flags for mbedtls_mpi_gen_prime() + * + * Each of these flags is a constraint on the result X returned by + * mbedtls_mpi_gen_prime(). + */ +typedef enum { + MBEDTLS_MPI_GEN_PRIME_FLAG_DH = 0x0001, /**< (X-1)/2 is prime too */ + MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR = 0x0002, /**< lower error rate from 2-80 to 2-128 */ +} mbedtls_mpi_gen_prime_flag_t; + +/** + * \brief Generate a prime number. + * + * \param X The destination MPI to store the generated prime in. + * This must point to an initialized MPi. + * \param nbits The required size of the destination MPI in bits. + * This must be between \c 3 and #MBEDTLS_MPI_MAX_BITS. + * \param flags A mask of flags of type #mbedtls_mpi_gen_prime_flag_t. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use + * a context parameter. + * + * \return \c 0 if successful, in which case \p X holds a + * probably prime number. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if `nbits` is not between + * \c 3 and #MBEDTLS_MPI_MAX_BITS. + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +#if defined(MBEDTLS_SELF_TEST) + /** * \brief Checkup routine * @@ -759,6 +957,8 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, */ int mbedtls_mpi_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/blowfish.h b/app/include/mbedtls/blowfish.h index c0ef5a04cc..f01573dcaf 100644 --- a/app/include/mbedtls/blowfish.h +++ b/app/include/mbedtls/blowfish.h @@ -33,6 +33,8 @@ #include #include +#include "platform_util.h" + #define MBEDTLS_BLOWFISH_ENCRYPT 1 #define MBEDTLS_BLOWFISH_DECRYPT 0 #define MBEDTLS_BLOWFISH_MAX_KEY_BITS 448 @@ -40,63 +42,87 @@ #define MBEDTLS_BLOWFISH_ROUNDS 16 /**< Rounds to use. When increasing this value, make sure to extend the initialisation vectors */ #define MBEDTLS_BLOWFISH_BLOCKSIZE 8 /* Blowfish uses 64 bit blocks */ -#define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH -0x0016 /**< Invalid key length. */ -#define MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED -0x0017 /**< Blowfish hardware accelerator failed. */ -#define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( -0x0016 ) +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#define MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA -0x0016 /**< Bad input data. */ -#if !defined(MBEDTLS_BLOWFISH_ALT) -// Regular implementation -// +#define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ + +/* MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED -0x0017 /**< Blowfish hardware accelerator failed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_BLOWFISH_ALT) +// Regular implementation +// + /** * \brief Blowfish context structure */ -typedef struct +typedef struct mbedtls_blowfish_context { uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2]; /*!< Blowfish round keys */ uint32_t S[4][256]; /*!< key dependent S-boxes */ } mbedtls_blowfish_context; +#else /* MBEDTLS_BLOWFISH_ALT */ +#include "blowfish_alt.h" +#endif /* MBEDTLS_BLOWFISH_ALT */ + /** - * \brief Initialize Blowfish context + * \brief Initialize a Blowfish context. * - * \param ctx Blowfish context to be initialized + * \param ctx The Blowfish context to be initialized. + * This must not be \c NULL. */ void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ); /** - * \brief Clear Blowfish context + * \brief Clear a Blowfish context. * - * \param ctx Blowfish context to be cleared + * \param ctx The Blowfish context to be cleared. + * This may be \c NULL, in which case this function + * returns immediately. If it is not \c NULL, it must + * point to an initialized Blowfish context. */ void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ); /** - * \brief Blowfish key schedule + * \brief Perform a Blowfish key schedule operation. * - * \param ctx Blowfish context to be initialized - * \param key encryption key - * \param keybits must be between 32 and 448 bits + * \param ctx The Blowfish context to perform the key schedule on. + * \param key The encryption key. This must be a readable buffer of + * length \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be between + * \c 32 and \c 448 and a multiple of \c 8. * - * \return 0 if successful, or MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, unsigned int keybits ); /** - * \brief Blowfish-ECB block encryption/decryption + * \brief Perform a Blowfish-ECB block encryption/decryption operation. * - * \param ctx Blowfish context - * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT - * \param input 8-byte input block - * \param output 8-byte output block + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. Possible values are + * #MBEDTLS_BLOWFISH_ENCRYPT for encryption, or + * #MBEDTLS_BLOWFISH_DECRYPT for decryption. + * \param input The input block. This must be a readable buffer + * of size \c 8 Bytes. + * \param output The output block. This must be a writable buffer + * of size \c 8 Bytes. * - * \return 0 if successful + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, int mode, @@ -105,9 +131,7 @@ int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, #if defined(MBEDTLS_CIPHER_MODE_CBC) /** - * \brief Blowfish-CBC buffer encryption/decryption - * Length should be a multiple of the block - * size (8 bytes) + * \brief Perform a Blowfish-CBC buffer encryption/decryption operation. * * \note Upon exit, the content of the IV is updated so that you can * call the function same function again on the following @@ -117,15 +141,22 @@ int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, * IV, you should either save it manually or use the cipher * module instead. * - * \param ctx Blowfish context - * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. Possible values are + * #MBEDTLS_BLOWFISH_ENCRYPT for encryption, or + * #MBEDTLS_BLOWFISH_DECRYPT for decryption. + * \param length The length of the input data in Bytes. This must be + * multiple of \c 8. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 8 Bytes. It is updated by this function. + * \param input The input data. This must be a readable buffer of length + * \p length Bytes. + * \param output The output data. This must be a writable buffer of length + * \p length Bytes. * - * \return 0 if successful, or - * MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, int mode, @@ -137,7 +168,7 @@ int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, #if defined(MBEDTLS_CIPHER_MODE_CFB) /** - * \brief Blowfish CFB buffer encryption/decryption. + * \brief Perform a Blowfish CFB buffer encryption/decryption operation. * * \note Upon exit, the content of the IV is updated so that you can * call the function same function again on the following @@ -147,15 +178,25 @@ int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, * IV, you should either save it manually or use the cipher * module instead. * - * \param ctx Blowfish context - * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT - * \param length length of the input data - * \param iv_off offset in IV (updated after use) - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. Possible values are + * #MBEDTLS_BLOWFISH_ENCRYPT for encryption, or + * #MBEDTLS_BLOWFISH_DECRYPT for decryption. + * \param length The length of the input data in Bytes. + * \param iv_off The offset in the initialiation vector. + * The value pointed to must be smaller than \c 8 Bytes. + * It is updated by this function to support the aforementioned + * streaming usage. + * \param iv The initialization vector. This must be a read/write buffer + * of size \c 8 Bytes. It is updated after use. + * \param input The input data. This must be a readable buffer of length + * \p length Bytes. + * \param output The output data. This must be a writable buffer of length + * \p length Bytes. * - * \return 0 if successful + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, int mode, @@ -168,22 +209,67 @@ int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, #if defined(MBEDTLS_CIPHER_MODE_CTR) /** - * \brief Blowfish-CTR buffer encryption/decryption + * \brief Perform a Blowfish-CTR buffer encryption/decryption operation. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**64 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 4 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 4 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**32 messages of up to 2**32 blocks each with the same key. * - * Warning: You have to keep the maximum use of your counter in mind! + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. * - * \param ctx Blowfish context - * \param length The length of the data + * Note that for both stategies, sizes are measured in blocks and + * that a Blowfish block is 8 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param length The length of the input data in Bytes. * \param nc_off The offset in the current stream_block (for resuming - * within current cipher stream). The offset pointer to - * should be 0 at the start of a stream. - * \param nonce_counter The 64-bit nonce and counter. - * \param stream_block The saved stream-block for resuming. Is overwritten - * by the function. - * \param input The input data stream - * \param output The output data stream - * - * \return 0 if successful + * within current cipher stream). The offset pointer + * should be \c 0 at the start of a stream and must be + * smaller than \c 8. It is updated by this function. + * \param nonce_counter The 64-bit nonce and counter. This must point to a + * read/write buffer of length \c 8 Bytes. + * \param stream_block The saved stream-block for resuming. This must point to + * a read/write buffer of length \c 8 Bytes. + * \param input The input data. This must be a readable buffer of + * length \p length Bytes. + * \param output The output data. This must be a writable buffer of + * length \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, size_t length, @@ -198,8 +284,4 @@ int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, } #endif -#else /* MBEDTLS_BLOWFISH_ALT */ -#include "blowfish_alt.h" -#endif /* MBEDTLS_BLOWFISH_ALT */ - #endif /* blowfish.h */ diff --git a/app/include/mbedtls/bn_mul.h b/app/include/mbedtls/bn_mul.h index 3a254aae9d..748975ea51 100644 --- a/app/include/mbedtls/bn_mul.h +++ b/app/include/mbedtls/bn_mul.h @@ -571,9 +571,8 @@ #endif /* TriCore */ /* - * gcc -O0 by default uses r7 for the frame pointer, so it complains about our - * use of r7 below, unless -fomit-frame-pointer is passed. Unfortunately, - * passing that option is not easy when building with yotta. + * Note, gcc -O0 by default uses r7 for the frame pointer, so it complains about + * our use of r7 below, unless -fomit-frame-pointer is passed. * * On the other hand, -fomit-frame-pointer is implied by any -Ox options with * x !=0, which we can detect using __OPTIMIZE__ (which is also defined by @@ -643,6 +642,24 @@ "r6", "r7", "r8", "r9", "cc" \ ); +#elif (__ARM_ARCH >= 6) && \ + defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1) + +#define MULADDC_INIT \ + asm( + +#define MULADDC_CORE \ + "ldr r0, [%0], #4 \n\t" \ + "ldr r1, [%1] \n\t" \ + "umaal r1, %2, %3, r0 \n\t" \ + "str r1, [%1], #4 \n\t" + +#define MULADDC_STOP \ + : "=r" (s), "=r" (d), "=r" (c) \ + : "r" (b), "0" (s), "1" (d), "2" (c) \ + : "r0", "r1", "memory" \ + ); + #else #define MULADDC_INIT \ diff --git a/app/include/mbedtls/camellia.h b/app/include/mbedtls/camellia.h index cf07629d9b..3eeb66366d 100644 --- a/app/include/mbedtls/camellia.h +++ b/app/include/mbedtls/camellia.h @@ -33,78 +33,107 @@ #include #include +#include "platform_util.h" + #define MBEDTLS_CAMELLIA_ENCRYPT 1 #define MBEDTLS_CAMELLIA_DECRYPT 0 -#define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH -0x0024 /**< Invalid key length. */ -#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ -#define MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED -0x0027 /**< Camellia hardware accelerator failed. */ +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( -0x0024 ) +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#define MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA -0x0024 /**< Bad input data. */ -#if !defined(MBEDTLS_CAMELLIA_ALT) -// Regular implementation -// +#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ + +/* MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED -0x0027 /**< Camellia hardware accelerator failed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_CAMELLIA_ALT) +// Regular implementation +// + /** * \brief CAMELLIA context structure */ -typedef struct +typedef struct mbedtls_camellia_context { int nr; /*!< number of rounds */ uint32_t rk[68]; /*!< CAMELLIA round keys */ } mbedtls_camellia_context; +#else /* MBEDTLS_CAMELLIA_ALT */ +#include "camellia_alt.h" +#endif /* MBEDTLS_CAMELLIA_ALT */ + /** - * \brief Initialize CAMELLIA context + * \brief Initialize a CAMELLIA context. * - * \param ctx CAMELLIA context to be initialized + * \param ctx The CAMELLIA context to be initialized. + * This must not be \c NULL. */ void mbedtls_camellia_init( mbedtls_camellia_context *ctx ); /** - * \brief Clear CAMELLIA context + * \brief Clear a CAMELLIA context. * - * \param ctx CAMELLIA context to be cleared + * \param ctx The CAMELLIA context to be cleared. This may be \c NULL, + * in which case this function returns immediately. If it is not + * \c NULL, it must be initialized. */ void mbedtls_camellia_free( mbedtls_camellia_context *ctx ); /** - * \brief CAMELLIA key schedule (encryption) + * \brief Perform a CAMELLIA key schedule operation for encryption. * - * \param ctx CAMELLIA context to be initialized - * \param key encryption key - * \param keybits must be 128, 192 or 256 + * \param ctx The CAMELLIA context to use. This must be initialized. + * \param key The encryption key to use. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be either \c 128, + * \c 192 or \c 256. * - * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + * \return \c 0 if successful. + * \return A negative error code on failure. */ -int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, - unsigned int keybits ); +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ); /** - * \brief CAMELLIA key schedule (decryption) + * \brief Perform a CAMELLIA key schedule operation for decryption. * - * \param ctx CAMELLIA context to be initialized - * \param key decryption key - * \param keybits must be 128, 192 or 256 + * \param ctx The CAMELLIA context to use. This must be initialized. + * \param key The decryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be either \c 128, + * \c 192 or \c 256. * - * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + * \return \c 0 if successful. + * \return A negative error code on failure. */ -int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, - unsigned int keybits ); +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ); /** - * \brief CAMELLIA-ECB block encryption/decryption + * \brief Perform a CAMELLIA-ECB block encryption/decryption operation. * - * \param ctx CAMELLIA context - * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT - * \param input 16-byte input block - * \param output 16-byte output block + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * \param input The input block. This must be a readable buffer + * of size \c 16 Bytes. + * \param output The output block. This must be a writable buffer + * of size \c 16 Bytes. * - * \return 0 if successful + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, int mode, @@ -113,9 +142,7 @@ int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, #if defined(MBEDTLS_CIPHER_MODE_CBC) /** - * \brief CAMELLIA-CBC buffer encryption/decryption - * Length should be a multiple of the block - * size (16 bytes) + * \brief Perform a CAMELLIA-CBC buffer encryption/decryption operation. * * \note Upon exit, the content of the IV is updated so that you can * call the function same function again on the following @@ -125,15 +152,22 @@ int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, * IV, you should either save it manually or use the cipher * module instead. * - * \param ctx CAMELLIA context - * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * \param length The length in Bytes of the input data \p input. + * This must be a multiple of \c 16 Bytes. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 16 Bytes. It is updated to allow streaming + * use as explained above. + * \param input The buffer holding the input data. This must point to a + * readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must point to a + * writable buffer of length \p length Bytes. * - * \return 0 if successful, or - * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, int mode, @@ -145,11 +179,14 @@ int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, #if defined(MBEDTLS_CIPHER_MODE_CFB) /** - * \brief CAMELLIA-CFB128 buffer encryption/decryption + * \brief Perform a CAMELLIA-CFB128 buffer encryption/decryption + * operation. * - * Note: Due to the nature of CFB you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and CAMELLIE_DECRYPT. + * \note Due to the nature of CFB mode, you should use the same + * key for both encryption and decryption. In particular, calls + * to this function should be preceded by a key-schedule via + * mbedtls_camellia_setkey_enc() regardless of whether \p mode + * is #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. * * \note Upon exit, the content of the IV is updated so that you can * call the function same function again on the following @@ -159,16 +196,24 @@ int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, * IV, you should either save it manually or use the cipher * module instead. * - * \param ctx CAMELLIA context - * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT - * \param length length of the input data - * \param iv_off offset in IV (updated after use) - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * \param length The length of the input data \p input. Any value is allowed. + * \param iv_off The current offset in the IV. This must be smaller + * than \c 16 Bytes. It is updated after this call to allow + * the aforementioned streaming usage. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 16 Bytes. It is updated after this call to + * allow the aforementioned streaming usage. + * \param input The buffer holding the input data. This must be a readable + * buffer of size \p length Bytes. + * \param output The buffer to hold the output data. This must be a writable + * buffer of length \p length Bytes. * - * \return 0 if successful, or - * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, int mode, @@ -181,26 +226,78 @@ int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, #if defined(MBEDTLS_CIPHER_MODE_CTR) /** - * \brief CAMELLIA-CTR buffer encryption/decryption + * \brief Perform a CAMELLIA-CTR buffer encryption/decryption operation. + * + * *note Due to the nature of CTR mode, you should use the same + * key for both encryption and decryption. In particular, calls + * to this function should be preceded by a key-schedule via + * mbedtls_camellia_setkey_enc() regardless of whether \p mode + * is #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: * - * Warning: You have to keep the maximum use of your counter in mind! + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. * - * Note: Due to the nature of CTR you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and MBEDTLS_CAMELLIA_DECRYPT. + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. * - * \param ctx CAMELLIA context - * \param length The length of the data - * \param nc_off The offset in the current stream_block (for resuming + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first \c 12 Bytes for the + * per-message nonce, and the last \c 4 Bytes for internal use. + * In that case, before calling this function on a new message you + * need to set the first \c 12 Bytes of \p nonce_counter to your + * chosen nonce value, the last four to \c 0, and \p nc_off to \c 0 + * (which will cause \p stream_block to be ignored). That way, you + * can encrypt at most \c 2**96 messages of up to \c 2**32 blocks + * each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be + * unique. The recommended way to ensure uniqueness is to use a + * message counter. An alternative is to generate random nonces, + * but this limits the number of messages that can be securely + * encrypted: for example, with 96-bit random nonces, you should + * not encrypt more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that a CAMELLIA block is \c 16 Bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param length The length of the input data \p input in Bytes. + * Any value is allowed. + * \param nc_off The offset in the current \p stream_block (for resuming * within current cipher stream). The offset pointer to - * should be 0 at the start of a stream. - * \param nonce_counter The 128-bit nonce and counter. - * \param stream_block The saved stream-block for resuming. Is overwritten - * by the function. - * \param input The input data stream - * \param output The output data stream - * - * \return 0 if successful + * should be \c 0 at the start of a stream. It is updated + * at the end of this call. + * \param nonce_counter The 128-bit nonce and counter. This must be a read/write + * buffer of length \c 16 Bytes. + * \param stream_block The saved stream-block for resuming. This must be a + * read/write buffer of length \c 16 Bytes. + * \param input The input data stream. This must be a readable buffer of + * size \p length Bytes. + * \param output The output data stream. This must be a writable buffer + * of size \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, size_t length, @@ -211,17 +308,7 @@ int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, unsigned char *output ); #endif /* MBEDTLS_CIPHER_MODE_CTR */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_CAMELLIA_ALT */ -#include "camellia_alt.h" -#endif /* MBEDTLS_CAMELLIA_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief Checkup routine @@ -230,6 +317,8 @@ extern "C" { */ int mbedtls_camellia_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/ccm.h b/app/include/mbedtls/ccm.h index 630b7fdf6c..f03e3b580e 100644 --- a/app/include/mbedtls/ccm.h +++ b/app/include/mbedtls/ccm.h @@ -1,8 +1,11 @@ /** * \file ccm.h * - * \brief CCM combines Counter mode encryption with CBC-MAC authentication - * for 128-bit block ciphers. + * \brief This file provides an API for the CCM authenticated encryption + * mode for block ciphers. + * + * CCM combines Counter mode encryption with CBC-MAC authentication + * for 128-bit block ciphers. * * Input to CCM includes the following elements: *
  • Payload - data that is both authenticated and encrypted.
  • @@ -11,6 +14,18 @@ *
  • Nonce - A unique value that is assigned to the payload and the * associated data.
* + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + * + * Definition of CCM*: + * IEEE 802.15.4 - IEEE Standard for Local and metropolitan area networks + * Integer representation is fixed most-significant-octet-first order and + * the representation of octets is most-significant-bit-first order. This is + * consistent with RFC 3610. */ /* * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved @@ -34,35 +49,48 @@ #ifndef MBEDTLS_CCM_H #define MBEDTLS_CCM_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "cipher.h" #define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to the function. */ #define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */ -#define MBEDTLS_ERR_CCM_HW_ACCEL_FAILED -0x0011 /**< CCM hardware accelerator failed. */ -#if !defined(MBEDTLS_CCM_ALT) -// Regular implementation -// +/* MBEDTLS_ERR_CCM_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_CCM_HW_ACCEL_FAILED -0x0011 /**< CCM hardware accelerator failed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_CCM_ALT) +// Regular implementation +// + /** * \brief The CCM context-type definition. The CCM context is passed * to the APIs called. */ -typedef struct { +typedef struct mbedtls_ccm_context +{ mbedtls_cipher_context_t cipher_ctx; /*!< The cipher context used. */ } mbedtls_ccm_context; +#else /* MBEDTLS_CCM_ALT */ +#include "ccm_alt.h" +#endif /* MBEDTLS_CCM_ALT */ + /** * \brief This function initializes the specified CCM context, * to make references valid, and prepare the context * for mbedtls_ccm_setkey() or mbedtls_ccm_free(). * - * \param ctx The CCM context to initialize. + * \param ctx The CCM context to initialize. This must not be \c NULL. */ void mbedtls_ccm_init( mbedtls_ccm_context *ctx ); @@ -70,12 +98,14 @@ void mbedtls_ccm_init( mbedtls_ccm_context *ctx ); * \brief This function initializes the CCM context set in the * \p ctx parameter and sets the encryption key. * - * \param ctx The CCM context to initialize. + * \param ctx The CCM context to initialize. This must be an initialized + * context. * \param cipher The 128-bit block cipher to use. - * \param key The encryption key. + * \param key The encryption key. This must not be \c NULL. * \param keybits The key size in bits. This must be acceptable by the cipher. * - * \return \c 0 on success, or a cipher-specific error code. + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. */ int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, mbedtls_cipher_id_t cipher, @@ -86,36 +116,96 @@ int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, * \brief This function releases and clears the specified CCM context * and underlying cipher sub-context. * - * \param ctx The CCM context to clear. + * \param ctx The CCM context to clear. If this is \c NULL, the function + * has no effect. Otherwise, this must be initialized. */ void mbedtls_ccm_free( mbedtls_ccm_context *ctx ); /** * \brief This function encrypts a buffer using CCM. * - * \param ctx The CCM context to use for encryption. + * \note The tag is written to a separate buffer. To concatenate + * the \p tag with the \p output, as done in RFC-3610: + * Counter with CBC-MAC (CCM), use + * \p tag = \p output + \p length, and make sure that the + * output buffer is at least \p length + \p tag_len wide. + * + * \param ctx The CCM context to use for encryption. This must be + * initialized and bound to a key. * \param length The length of the input data in Bytes. - * \param iv Initialization vector (nonce). - * \param iv_len The length of the IV in Bytes: 7, 8, 9, 10, 11, 12, or 13. - * \param add The additional data field. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. If \p add_len is greater than + * zero, \p add must be a readable buffer of at least that + * length. * \param add_len The length of additional data in Bytes. - * Must be less than 2^16 - 2^8. - * \param input The buffer holding the input data. - * \param output The buffer holding the output data. - * Must be at least \p length Bytes wide. - * \param tag The buffer holding the tag. - * \param tag_len The length of the tag to generate in Bytes: + * This must be less than `2^16 - 2^8`. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: * 4, 6, 8, 10, 12, 14 or 16. * + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ); + +/** + * \brief This function encrypts a buffer using CCM*. + * * \note The tag is written to a separate buffer. To concatenate * the \p tag with the \p output, as done in RFC-3610: * Counter with CBC-MAC (CCM), use * \p tag = \p output + \p length, and make sure that the * output buffer is at least \p length + \p tag_len wide. * + * \note When using this function in a variable tag length context, + * the tag length has to be encoded into the \p iv passed to + * this function. + * + * \param ctx The CCM context to use for encryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. This must be a readable buffer of + * at least \p add_len Bytes. + * \param add_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: + * 0, 4, 6, 8, 10, 12, 14 or 16. + * + * \warning Passing \c 0 as \p tag_len means that the message is no + * longer authenticated. + * * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. */ -int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, +int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, @@ -125,22 +215,32 @@ int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, * \brief This function performs a CCM authenticated decryption of a * buffer. * - * \param ctx The CCM context to use for decryption. + * \param ctx The CCM context to use for decryption. This must be + * initialized and bound to a key. * \param length The length of the input data in Bytes. - * \param iv Initialization vector. - * \param iv_len The length of the IV in Bytes: 7, 8, 9, 10, 11, 12, or 13. - * \param add The additional data field. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. This must be a readable buffer + * of at least that \p add_len Bytes.. * \param add_len The length of additional data in Bytes. - * Must be less than 2^16 - 2^8. - * \param input The buffer holding the input data. - * \param output The buffer holding the output data. - * Must be at least \p length Bytes wide. - * \param tag The buffer holding the tag. - * \param tag_len The length of the tag in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: * 4, 6, 8, 10, 12, 14 or 16. * - * \return 0 if successful and authenticated, or - * #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match. + * \return \c 0 on success. This indicates that the message is authentic. + * \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match. + * \return A cipher-specific error code on calculation failure. */ int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, @@ -148,23 +248,57 @@ int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, const unsigned char *input, unsigned char *output, const unsigned char *tag, size_t tag_len ); -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_CCM_ALT */ -#include "ccm_alt.h" -#endif /* MBEDTLS_CCM_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +/** + * \brief This function performs a CCM* authenticated decryption of a + * buffer. + * + * \note When using this function in a variable tag length context, + * the tag length has to be decoded from \p iv and passed to + * this function as \p tag_len. (\p tag needs to be adjusted + * accordingly.) + * + * \param ctx The CCM context to use for decryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. This must be a readable buffer of + * at least that \p add_len Bytes. + * \param add_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field in Bytes. + * 0, 4, 6, 8, 10, 12, 14 or 16. + * + * \warning Passing \c 0 as \p tag_len means that the message is nos + * longer authenticated. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match. + * \return A cipher-specific error code on calculation failure. + */ +int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ); #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) /** * \brief The CCM checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_ccm_self_test( int verbose ); #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ diff --git a/app/include/mbedtls/certs.h b/app/include/mbedtls/certs.h index 8dab7b5ce8..179ebbbad2 100644 --- a/app/include/mbedtls/certs.h +++ b/app/include/mbedtls/certs.h @@ -24,74 +24,226 @@ #ifndef MBEDTLS_CERTS_H #define MBEDTLS_CERTS_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include #ifdef __cplusplus extern "C" { #endif +/* List of all PEM-encoded CA certificates, terminated by NULL; + * PEM encoded if MBEDTLS_PEM_PARSE_C is enabled, DER encoded + * otherwise. */ +extern const char * mbedtls_test_cas[]; +extern const size_t mbedtls_test_cas_len[]; + +/* List of all DER-encoded CA certificates, terminated by NULL */ +extern const unsigned char * mbedtls_test_cas_der[]; +extern const size_t mbedtls_test_cas_der_len[]; + #if defined(MBEDTLS_PEM_PARSE_C) /* Concatenation of all CA certificates in PEM format if available */ extern const char mbedtls_test_cas_pem[]; extern const size_t mbedtls_test_cas_pem_len; -#endif - -/* List of all CA certificates, terminated by NULL */ -extern const char * mbedtls_test_cas[]; -extern const size_t mbedtls_test_cas_len[]; +#endif /* MBEDTLS_PEM_PARSE_C */ /* - * Convenience for users who just want a certificate: - * RSA by default, or ECDSA if RSA is not available + * CA test certificates */ + +extern const char mbedtls_test_ca_crt_ec_pem[]; +extern const char mbedtls_test_ca_key_ec_pem[]; +extern const char mbedtls_test_ca_pwd_ec_pem[]; +extern const char mbedtls_test_ca_key_rsa_pem[]; +extern const char mbedtls_test_ca_pwd_rsa_pem[]; +extern const char mbedtls_test_ca_crt_rsa_sha1_pem[]; +extern const char mbedtls_test_ca_crt_rsa_sha256_pem[]; + +extern const unsigned char mbedtls_test_ca_crt_ec_der[]; +extern const unsigned char mbedtls_test_ca_key_ec_der[]; +extern const unsigned char mbedtls_test_ca_key_rsa_der[]; +extern const unsigned char mbedtls_test_ca_crt_rsa_sha1_der[]; +extern const unsigned char mbedtls_test_ca_crt_rsa_sha256_der[]; + +extern const size_t mbedtls_test_ca_crt_ec_pem_len; +extern const size_t mbedtls_test_ca_key_ec_pem_len; +extern const size_t mbedtls_test_ca_pwd_ec_pem_len; +extern const size_t mbedtls_test_ca_key_rsa_pem_len; +extern const size_t mbedtls_test_ca_pwd_rsa_pem_len; +extern const size_t mbedtls_test_ca_crt_rsa_sha1_pem_len; +extern const size_t mbedtls_test_ca_crt_rsa_sha256_pem_len; + +extern const size_t mbedtls_test_ca_crt_ec_der_len; +extern const size_t mbedtls_test_ca_key_ec_der_len; +extern const size_t mbedtls_test_ca_pwd_ec_der_len; +extern const size_t mbedtls_test_ca_key_rsa_der_len; +extern const size_t mbedtls_test_ca_pwd_rsa_der_len; +extern const size_t mbedtls_test_ca_crt_rsa_sha1_der_len; +extern const size_t mbedtls_test_ca_crt_rsa_sha256_der_len; + +/* Config-dependent dispatch between PEM and DER encoding + * (PEM if enabled, otherwise DER) */ + +extern const char mbedtls_test_ca_crt_ec[]; +extern const char mbedtls_test_ca_key_ec[]; +extern const char mbedtls_test_ca_pwd_ec[]; +extern const char mbedtls_test_ca_key_rsa[]; +extern const char mbedtls_test_ca_pwd_rsa[]; +extern const char mbedtls_test_ca_crt_rsa_sha1[]; +extern const char mbedtls_test_ca_crt_rsa_sha256[]; + +extern const size_t mbedtls_test_ca_crt_ec_len; +extern const size_t mbedtls_test_ca_key_ec_len; +extern const size_t mbedtls_test_ca_pwd_ec_len; +extern const size_t mbedtls_test_ca_key_rsa_len; +extern const size_t mbedtls_test_ca_pwd_rsa_len; +extern const size_t mbedtls_test_ca_crt_rsa_sha1_len; +extern const size_t mbedtls_test_ca_crt_rsa_sha256_len; + +/* Config-dependent dispatch between SHA-1 and SHA-256 + * (SHA-256 if enabled, otherwise SHA-1) */ + +extern const char mbedtls_test_ca_crt_rsa[]; +extern const size_t mbedtls_test_ca_crt_rsa_len; + +/* Config-dependent dispatch between EC and RSA + * (RSA if enabled, otherwise EC) */ + extern const char * mbedtls_test_ca_crt; -extern const size_t mbedtls_test_ca_crt_len; extern const char * mbedtls_test_ca_key; -extern const size_t mbedtls_test_ca_key_len; extern const char * mbedtls_test_ca_pwd; +extern const size_t mbedtls_test_ca_crt_len; +extern const size_t mbedtls_test_ca_key_len; extern const size_t mbedtls_test_ca_pwd_len; + +/* + * Server test certificates + */ + +extern const char mbedtls_test_srv_crt_ec_pem[]; +extern const char mbedtls_test_srv_key_ec_pem[]; +extern const char mbedtls_test_srv_pwd_ec_pem[]; +extern const char mbedtls_test_srv_key_rsa_pem[]; +extern const char mbedtls_test_srv_pwd_rsa_pem[]; +extern const char mbedtls_test_srv_crt_rsa_sha1_pem[]; +extern const char mbedtls_test_srv_crt_rsa_sha256_pem[]; + +extern const unsigned char mbedtls_test_srv_crt_ec_der[]; +extern const unsigned char mbedtls_test_srv_key_ec_der[]; +extern const unsigned char mbedtls_test_srv_key_rsa_der[]; +extern const unsigned char mbedtls_test_srv_crt_rsa_sha1_der[]; +extern const unsigned char mbedtls_test_srv_crt_rsa_sha256_der[]; + +extern const size_t mbedtls_test_srv_crt_ec_pem_len; +extern const size_t mbedtls_test_srv_key_ec_pem_len; +extern const size_t mbedtls_test_srv_pwd_ec_pem_len; +extern const size_t mbedtls_test_srv_key_rsa_pem_len; +extern const size_t mbedtls_test_srv_pwd_rsa_pem_len; +extern const size_t mbedtls_test_srv_crt_rsa_sha1_pem_len; +extern const size_t mbedtls_test_srv_crt_rsa_sha256_pem_len; + +extern const size_t mbedtls_test_srv_crt_ec_der_len; +extern const size_t mbedtls_test_srv_key_ec_der_len; +extern const size_t mbedtls_test_srv_pwd_ec_der_len; +extern const size_t mbedtls_test_srv_key_rsa_der_len; +extern const size_t mbedtls_test_srv_pwd_rsa_der_len; +extern const size_t mbedtls_test_srv_crt_rsa_sha1_der_len; +extern const size_t mbedtls_test_srv_crt_rsa_sha256_der_len; + +/* Config-dependent dispatch between PEM and DER encoding + * (PEM if enabled, otherwise DER) */ + +extern const char mbedtls_test_srv_crt_ec[]; +extern const char mbedtls_test_srv_key_ec[]; +extern const char mbedtls_test_srv_pwd_ec[]; +extern const char mbedtls_test_srv_key_rsa[]; +extern const char mbedtls_test_srv_pwd_rsa[]; +extern const char mbedtls_test_srv_crt_rsa_sha1[]; +extern const char mbedtls_test_srv_crt_rsa_sha256[]; + +extern const size_t mbedtls_test_srv_crt_ec_len; +extern const size_t mbedtls_test_srv_key_ec_len; +extern const size_t mbedtls_test_srv_pwd_ec_len; +extern const size_t mbedtls_test_srv_key_rsa_len; +extern const size_t mbedtls_test_srv_pwd_rsa_len; +extern const size_t mbedtls_test_srv_crt_rsa_sha1_len; +extern const size_t mbedtls_test_srv_crt_rsa_sha256_len; + +/* Config-dependent dispatch between SHA-1 and SHA-256 + * (SHA-256 if enabled, otherwise SHA-1) */ + +extern const char mbedtls_test_srv_crt_rsa[]; +extern const size_t mbedtls_test_srv_crt_rsa_len; + +/* Config-dependent dispatch between EC and RSA + * (RSA if enabled, otherwise EC) */ + extern const char * mbedtls_test_srv_crt; -extern const size_t mbedtls_test_srv_crt_len; extern const char * mbedtls_test_srv_key; +extern const char * mbedtls_test_srv_pwd; +extern const size_t mbedtls_test_srv_crt_len; extern const size_t mbedtls_test_srv_key_len; -extern const char * mbedtls_test_cli_crt; -extern const size_t mbedtls_test_cli_crt_len; -extern const char * mbedtls_test_cli_key; -extern const size_t mbedtls_test_cli_key_len; +extern const size_t mbedtls_test_srv_pwd_len; + +/* + * Client test certificates + */ + +extern const char mbedtls_test_cli_crt_ec_pem[]; +extern const char mbedtls_test_cli_key_ec_pem[]; +extern const char mbedtls_test_cli_pwd_ec_pem[]; +extern const char mbedtls_test_cli_key_rsa_pem[]; +extern const char mbedtls_test_cli_pwd_rsa_pem[]; +extern const char mbedtls_test_cli_crt_rsa_pem[]; + +extern const unsigned char mbedtls_test_cli_crt_ec_der[]; +extern const unsigned char mbedtls_test_cli_key_ec_der[]; +extern const unsigned char mbedtls_test_cli_key_rsa_der[]; +extern const unsigned char mbedtls_test_cli_crt_rsa_der[]; + +extern const size_t mbedtls_test_cli_crt_ec_pem_len; +extern const size_t mbedtls_test_cli_key_ec_pem_len; +extern const size_t mbedtls_test_cli_pwd_ec_pem_len; +extern const size_t mbedtls_test_cli_key_rsa_pem_len; +extern const size_t mbedtls_test_cli_pwd_rsa_pem_len; +extern const size_t mbedtls_test_cli_crt_rsa_pem_len; + +extern const size_t mbedtls_test_cli_crt_ec_der_len; +extern const size_t mbedtls_test_cli_key_ec_der_len; +extern const size_t mbedtls_test_cli_key_rsa_der_len; +extern const size_t mbedtls_test_cli_crt_rsa_der_len; + +/* Config-dependent dispatch between PEM and DER encoding + * (PEM if enabled, otherwise DER) */ + +extern const char mbedtls_test_cli_crt_ec[]; +extern const char mbedtls_test_cli_key_ec[]; +extern const char mbedtls_test_cli_pwd_ec[]; +extern const char mbedtls_test_cli_key_rsa[]; +extern const char mbedtls_test_cli_pwd_rsa[]; +extern const char mbedtls_test_cli_crt_rsa[]; -#if defined(MBEDTLS_ECDSA_C) -extern const char mbedtls_test_ca_crt_ec[]; -extern const size_t mbedtls_test_ca_crt_ec_len; -extern const char mbedtls_test_ca_key_ec[]; -extern const size_t mbedtls_test_ca_key_ec_len; -extern const char mbedtls_test_ca_pwd_ec[]; -extern const size_t mbedtls_test_ca_pwd_ec_len; -extern const char mbedtls_test_srv_crt_ec[]; -extern const size_t mbedtls_test_srv_crt_ec_len; -extern const char mbedtls_test_srv_key_ec[]; -extern const size_t mbedtls_test_srv_key_ec_len; -extern const char mbedtls_test_cli_crt_ec[]; extern const size_t mbedtls_test_cli_crt_ec_len; -extern const char mbedtls_test_cli_key_ec[]; extern const size_t mbedtls_test_cli_key_ec_len; -#endif - -#if defined(MBEDTLS_RSA_C) -extern const char mbedtls_test_ca_crt_rsa[]; -extern const size_t mbedtls_test_ca_crt_rsa_len; -extern const char mbedtls_test_ca_key_rsa[]; -extern const size_t mbedtls_test_ca_key_rsa_len; -extern const char mbedtls_test_ca_pwd_rsa[]; -extern const size_t mbedtls_test_ca_pwd_rsa_len; -extern const char mbedtls_test_srv_crt_rsa[]; -extern const size_t mbedtls_test_srv_crt_rsa_len; -extern const char mbedtls_test_srv_key_rsa[]; -extern const size_t mbedtls_test_srv_key_rsa_len; -extern const char mbedtls_test_cli_crt_rsa[]; -extern const size_t mbedtls_test_cli_crt_rsa_len; -extern const char mbedtls_test_cli_key_rsa[]; +extern const size_t mbedtls_test_cli_pwd_ec_len; extern const size_t mbedtls_test_cli_key_rsa_len; -#endif +extern const size_t mbedtls_test_cli_pwd_rsa_len; +extern const size_t mbedtls_test_cli_crt_rsa_len; + +/* Config-dependent dispatch between EC and RSA + * (RSA if enabled, otherwise EC) */ + +extern const char * mbedtls_test_cli_crt; +extern const char * mbedtls_test_cli_key; +extern const char * mbedtls_test_cli_pwd; +extern const size_t mbedtls_test_cli_crt_len; +extern const size_t mbedtls_test_cli_key_len; +extern const size_t mbedtls_test_cli_pwd_len; #ifdef __cplusplus } diff --git a/app/include/mbedtls/chacha20.h b/app/include/mbedtls/chacha20.h new file mode 100644 index 0000000000..2ae5e6e5f4 --- /dev/null +++ b/app/include/mbedtls/chacha20.h @@ -0,0 +1,226 @@ +/** + * \file chacha20.h + * + * \brief This file contains ChaCha20 definitions and functions. + * + * ChaCha20 is a stream cipher that can encrypt and decrypt + * information. ChaCha was created by Daniel Bernstein as a variant of + * its Salsa cipher https://cr.yp.to/chacha/chacha-20080128.pdf + * ChaCha20 is the variant with 20 rounds, that was also standardized + * in RFC 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CHACHA20_H +#define MBEDTLS_CHACHA20_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA -0x0051 /**< Invalid input parameter(s). */ + +/* MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ +#define MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE -0x0053 /**< Feature not available. For example, s part of the API is not implemented. */ + +/* MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED -0x0055 /**< Chacha20 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_CHACHA20_ALT) + +typedef struct mbedtls_chacha20_context +{ + uint32_t state[16]; /*! The state (before round operations). */ + uint8_t keystream8[64]; /*! Leftover keystream bytes. */ + size_t keystream_bytes_used; /*! Number of keystream bytes already used. */ +} +mbedtls_chacha20_context; + +#else /* MBEDTLS_CHACHA20_ALT */ +#include "chacha20_alt.h" +#endif /* MBEDTLS_CHACHA20_ALT */ + +/** + * \brief This function initializes the specified ChaCha20 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by calls to + * \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts(), then one or more calls to + * to \c mbedtls_chacha20_update(), and finally to + * \c mbedtls_chacha20_free(). + * + * \param ctx The ChaCha20 context to initialize. + * This must not be \c NULL. + */ +void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx ); + +/** + * \brief This function releases and clears the specified + * ChaCha20 context. + * + * \param ctx The ChaCha20 context to clear. This may be \c NULL, + * in which case this function is a no-op. If it is not + * \c NULL, it must point to an initialized context. + * + */ +void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx ); + +/** + * \brief This function sets the encryption/decryption key. + * + * \note After using this function, you must also call + * \c mbedtls_chacha20_starts() to set a nonce before you + * start encrypting/decrypting data with + * \c mbedtls_chacha_update(). + * + * \param ctx The ChaCha20 context to which the key should be bound. + * It must be initialized. + * \param key The encryption/decryption key. This must be \c 32 Bytes + * in length. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or key is NULL. + */ +int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This function sets the nonce and initial counter value. + * + * \note A ChaCha20 context can be re-used with the same key by + * calling this function to change the nonce. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality guarantees for the + * messages encrypted with the same nonce and key. + * + * \param ctx The ChaCha20 context to which the nonce should be bound. + * It must be initialized and bound to a key. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or nonce is + * NULL. + */ +int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx, + const unsigned char nonce[12], + uint32_t counter ); + +/** + * \brief This function encrypts or decrypts data. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \note \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts() must be called at least once + * to setup the context before this function can be called. + * + * \note This function can be called multiple times in a row in + * order to encrypt of decrypt data piecewise with the same + * key and nonce. + * + * \param ctx The ChaCha20 context to use for encryption or decryption. + * It must be initialized and bound to a key and nonce. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function encrypts or decrypts data with ChaCha20 and + * the given key and nonce. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \warning You must never use the same (key, nonce) pair more than + * once. This would void any confidentiality guarantees for + * the messages encrypted with the same nonce and key. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \param key The encryption/decryption key. + * This must be \c 32 Bytes in length. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_crypt( const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t size, + const unsigned char* input, + unsigned char* output ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chacha20_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CHACHA20_H */ diff --git a/app/include/mbedtls/chachapoly.h b/app/include/mbedtls/chachapoly.h new file mode 100644 index 0000000000..49e615d278 --- /dev/null +++ b/app/include/mbedtls/chachapoly.h @@ -0,0 +1,358 @@ +/** + * \file chachapoly.h + * + * \brief This file contains the AEAD-ChaCha20-Poly1305 definitions and + * functions. + * + * ChaCha20-Poly1305 is an algorithm for Authenticated Encryption + * with Associated Data (AEAD) that can be used to encrypt and + * authenticate data. It is based on ChaCha20 and Poly1305 by Daniel + * Bernstein and was standardized in RFC 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CHACHAPOLY_H +#define MBEDTLS_CHACHAPOLY_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/* for shared error codes */ +#include "poly1305.h" + +#define MBEDTLS_ERR_CHACHAPOLY_BAD_STATE -0x0054 /**< The requested operation is not permitted in the current state. */ +#define MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED -0x0056 /**< Authenticated decryption failed: data was not authentic. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + MBEDTLS_CHACHAPOLY_ENCRYPT, /**< The mode value for performing encryption. */ + MBEDTLS_CHACHAPOLY_DECRYPT /**< The mode value for performing decryption. */ +} +mbedtls_chachapoly_mode_t; + +#if !defined(MBEDTLS_CHACHAPOLY_ALT) + +#include "chacha20.h" + +typedef struct mbedtls_chachapoly_context +{ + mbedtls_chacha20_context chacha20_ctx; /**< The ChaCha20 context. */ + mbedtls_poly1305_context poly1305_ctx; /**< The Poly1305 context. */ + uint64_t aad_len; /**< The length (bytes) of the Additional Authenticated Data. */ + uint64_t ciphertext_len; /**< The length (bytes) of the ciphertext. */ + int state; /**< The current state of the context. */ + mbedtls_chachapoly_mode_t mode; /**< Cipher mode (encrypt or decrypt). */ +} +mbedtls_chachapoly_context; + +#else /* !MBEDTLS_CHACHAPOLY_ALT */ +#include "chachapoly_alt.h" +#endif /* !MBEDTLS_CHACHAPOLY_ALT */ + +/** + * \brief This function initializes the specified ChaCha20-Poly1305 context. + * + * It must be the first API called before using + * the context. It must be followed by a call to + * \c mbedtls_chachapoly_setkey() before any operation can be + * done, and to \c mbedtls_chachapoly_free() once all + * operations with that context have been finished. + * + * In order to encrypt or decrypt full messages at once, for + * each message you should make a single call to + * \c mbedtls_chachapoly_crypt_and_tag() or + * \c mbedtls_chachapoly_auth_decrypt(). + * + * In order to encrypt messages piecewise, for each + * message you should make a call to + * \c mbedtls_chachapoly_starts(), then 0 or more calls to + * \c mbedtls_chachapoly_update_aad(), then 0 or more calls to + * \c mbedtls_chachapoly_update(), then one call to + * \c mbedtls_chachapoly_finish(). + * + * \warning Decryption with the piecewise API is discouraged! Always + * use \c mbedtls_chachapoly_auth_decrypt() when possible! + * + * If however this is not possible because the data is too + * large to fit in memory, you need to: + * + * - call \c mbedtls_chachapoly_starts() and (if needed) + * \c mbedtls_chachapoly_update_aad() as above, + * - call \c mbedtls_chachapoly_update() multiple times and + * ensure its output (the plaintext) is NOT used in any other + * way than placing it in temporary storage at this point, + * - call \c mbedtls_chachapoly_finish() to compute the + * authentication tag and compared it in constant time to the + * tag received with the ciphertext. + * + * If the tags are not equal, you must immediately discard + * all previous outputs of \c mbedtls_chachapoly_update(), + * otherwise you can now safely use the plaintext. + * + * \param ctx The ChachaPoly context to initialize. Must not be \c NULL. + */ +void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx ); + +/** + * \brief This function releases and clears the specified + * ChaCha20-Poly1305 context. + * + * \param ctx The ChachaPoly context to clear. This may be \c NULL, in which + * case this function is a no-op. + */ +void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx ); + +/** + * \brief This function sets the ChaCha20-Poly1305 + * symmetric encryption key. + * + * \param ctx The ChaCha20-Poly1305 context to which the key should be + * bound. This must be initialized. + * \param key The \c 256 Bit (\c 32 Bytes) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This function starts a ChaCha20-Poly1305 encryption or + * decryption operation. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \note If the context is being used for AAD only (no data to + * encrypt or decrypt) then \p mode can be set to any value. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param nonce The nonce/IV to use for the message. + * This must be a redable buffer of length \c 12 Bytes. + * \param mode The operation to perform: #MBEDTLS_CHACHAPOLY_ENCRYPT or + * #MBEDTLS_CHACHAPOLY_DECRYPT (discouraged, see warning). + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode ); + +/** + * \brief This function feeds additional data to be authenticated + * into an ongoing ChaCha20-Poly1305 operation. + * + * The Additional Authenticated Data (AAD), also called + * Associated Data (AD) is only authenticated but not + * encrypted nor included in the encrypted output. It is + * usually transmitted separately from the ciphertext or + * computed locally by each party. + * + * \note This function is called before data is encrypted/decrypted. + * I.e. call this function to process the AAD before calling + * \c mbedtls_chachapoly_update(). + * + * You may call this function multiple times to process + * an arbitrary amount of AAD. It is permitted to call + * this function 0 times, if no AAD is used. + * + * This function cannot be called any more if data has + * been processed by \c mbedtls_chachapoly_update(), + * or if the context has been finished. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param aad_len The length in Bytes of the AAD. The length has no + * restrictions. + * \param aad Buffer containing the AAD. + * This pointer can be \c NULL if `aad_len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA + * if \p ctx or \p aad are NULL. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operations has not been started or has been + * finished, or if the AAD has been finished. + */ +int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len ); + +/** + * \brief Thus function feeds data to be encrypted or decrypted + * into an on-going ChaCha20-Poly1305 + * operation. + * + * The direction (encryption or decryption) depends on the + * mode that was given when calling + * \c mbedtls_chachapoly_starts(). + * + * You may call this function multiple times to process + * an arbitrary amount of data. It is permitted to call + * this function 0 times, if no data is to be encrypted + * or decrypted. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param len The length (in bytes) of the data to encrypt or decrypt. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `len == 0`. + * \param output The buffer to where the encrypted or decrypted data is + * written. This must be able to hold \p len bytes. + * This pointer can be \c NULL if `len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function finished the ChaCha20-Poly1305 operation and + * generates the MAC (authentication tag). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param mac The buffer to where the 128-bit (16 bytes) MAC is written. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, + unsigned char mac[16] ); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated encryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * This must be initialized. + * \param length The length (in bytes) of the data to encrypt or decrypt. + * \param nonce The 96-bit (12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated + * data (AAD). This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the encrypted or decrypted data + * is written. This pointer can be \c NULL if `ilen == 0`. + * \param tag The buffer to where the computed 128-bit (16 bytes) MAC + * is written. This must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated decryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * \param length The length (in Bytes) of the data to decrypt. + * \param nonce The \c 96 Bit (\c 12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated data (AAD). + * This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param tag The buffer holding the authentication tag. + * This must be a readable buffer of length \c 16 Bytes. + * \param input The buffer containing the data to decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the decrypted data is written. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED + * if the data was not authentic. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20-Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chachapoly_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CHACHAPOLY_H */ diff --git a/app/include/mbedtls/check_config.h b/app/include/mbedtls/check_config.h index fa7110fe92..d076c2352f 100644 --- a/app/include/mbedtls/check_config.h +++ b/app/include/mbedtls/check_config.h @@ -4,7 +4,7 @@ * \brief Consistency checks for configuration options */ /* - * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -87,6 +87,11 @@ #error "MBEDTLS_CMAC_C defined, but not all prerequisites" #endif +#if defined(MBEDTLS_NIST_KW_C) && \ + ( !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_CIPHER_C) ) +#error "MBEDTLS_NIST_KW_C defined, but not all prerequisites" +#endif + #if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C) #error "MBEDTLS_ECDH_C defined, but not all prerequisites" #endif @@ -103,11 +108,22 @@ #error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites" #endif +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + ( defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \ + defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) || \ + defined(MBEDTLS_ECDSA_SIGN_ALT) || \ + defined(MBEDTLS_ECDSA_VERIFY_ALT) || \ + defined(MBEDTLS_ECDSA_GENKEY_ALT) || \ + defined(MBEDTLS_ECP_INTERNAL_ALT) || \ + defined(MBEDTLS_ECP_ALT) ) +#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation" +#endif + #if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C) #error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites" #endif -#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ +#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \ !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \ !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \ @@ -118,7 +134,9 @@ !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \ !defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \ !defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \ - !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) ) + !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) ) ) #error "MBEDTLS_ECP_C defined, but not all prerequisites" #endif @@ -195,6 +213,10 @@ #error "MBEDTLS_HAVEGE_C defined, but not all prerequisites" #endif +#if defined(MBEDTLS_HKDF_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HKDF_C defined, but not all prerequisites" +#endif + #if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C) #error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites" #endif @@ -259,6 +281,14 @@ #error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites" #endif +#if defined(MBEDTLS_MEMORY_BACKTRACE) && !defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#error "MBEDTLS_MEMORY_BACKTRACE defined, but not all prerequesites" +#endif + +#if defined(MBEDTLS_MEMORY_DEBUG) && !defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#error "MBEDTLS_MEMORY_DEBUG defined, but not all prerequesites" +#endif + #if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM) #error "MBEDTLS_PADLOCK_C defined, but not all prerequisites" #endif @@ -671,7 +701,7 @@ /* * Avoid warning from -pedantic. This is a convenient place for this * workaround since this is included by every single file before the - * #if defined(MBEDTLS_xxx_C) that results in emtpy translation units. + * #if defined(MBEDTLS_xxx_C) that results in empty translation units. */ typedef int mbedtls_iso_c_forbids_empty_translation_units; diff --git a/app/include/mbedtls/cipher.h b/app/include/mbedtls/cipher.h index 1c453a1d32..082a691741 100644 --- a/app/include/mbedtls/cipher.h +++ b/app/include/mbedtls/cipher.h @@ -1,7 +1,9 @@ /** * \file cipher.h * - * \brief The generic cipher wrapper. + * \brief This file contains an abstraction interface for use with the cipher + * primitives provided by the library. It provides a common interface to all of + * the available cipher operations. * * \author Adriaan de Jong */ @@ -34,8 +36,9 @@ #endif #include +#include "platform_util.h" -#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) #define MBEDTLS_CIPHER_MODE_AEAD #endif @@ -43,7 +46,8 @@ #define MBEDTLS_CIPHER_MODE_WITH_PADDING #endif -#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ + defined(MBEDTLS_CHACHA20_C) #define MBEDTLS_CIPHER_MODE_STREAM #endif @@ -59,6 +63,8 @@ #define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */ #define MBEDTLS_ERR_CIPHER_AUTH_FAILED -0x6300 /**< Authentication failed (for AEAD modes). */ #define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT -0x6380 /**< The context is invalid. For example, because it was freed. */ + +/* MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED -0x6400 /**< Cipher hardware accelerator failed. */ #define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length. */ @@ -69,93 +75,122 @@ extern "C" { #endif /** - * \brief An enumeration of supported ciphers. + * \brief Supported cipher types. * - * \warning ARC4 and DES are considered weak ciphers and their use - * constitutes a security risk. We recommend considering stronger + * \warning RC4 and DES are considered weak ciphers and their use + * constitutes a security risk. Arm recommends considering stronger * ciphers instead. */ typedef enum { - MBEDTLS_CIPHER_ID_NONE = 0, - MBEDTLS_CIPHER_ID_NULL, - MBEDTLS_CIPHER_ID_AES, - MBEDTLS_CIPHER_ID_DES, - MBEDTLS_CIPHER_ID_3DES, - MBEDTLS_CIPHER_ID_CAMELLIA, - MBEDTLS_CIPHER_ID_BLOWFISH, - MBEDTLS_CIPHER_ID_ARC4, + MBEDTLS_CIPHER_ID_NONE = 0, /**< Placeholder to mark the end of cipher ID lists. */ + MBEDTLS_CIPHER_ID_NULL, /**< The identity cipher, treated as a stream cipher. */ + MBEDTLS_CIPHER_ID_AES, /**< The AES cipher. */ + MBEDTLS_CIPHER_ID_DES, /**< The DES cipher. */ + MBEDTLS_CIPHER_ID_3DES, /**< The Triple DES cipher. */ + MBEDTLS_CIPHER_ID_CAMELLIA, /**< The Camellia cipher. */ + MBEDTLS_CIPHER_ID_BLOWFISH, /**< The Blowfish cipher. */ + MBEDTLS_CIPHER_ID_ARC4, /**< The RC4 cipher. */ + MBEDTLS_CIPHER_ID_ARIA, /**< The Aria cipher. */ + MBEDTLS_CIPHER_ID_CHACHA20, /**< The ChaCha20 cipher. */ } mbedtls_cipher_id_t; /** - * \brief An enumeration of supported (cipher, mode) pairs. + * \brief Supported {cipher type, cipher mode} pairs. * - * \warning ARC4 and DES are considered weak ciphers and their use - * constitutes a security risk. We recommend considering stronger + * \warning RC4 and DES are considered weak ciphers and their use + * constitutes a security risk. Arm recommends considering stronger * ciphers instead. */ typedef enum { - MBEDTLS_CIPHER_NONE = 0, - MBEDTLS_CIPHER_NULL, - MBEDTLS_CIPHER_AES_128_ECB, - MBEDTLS_CIPHER_AES_192_ECB, - MBEDTLS_CIPHER_AES_256_ECB, - MBEDTLS_CIPHER_AES_128_CBC, - MBEDTLS_CIPHER_AES_192_CBC, - MBEDTLS_CIPHER_AES_256_CBC, - MBEDTLS_CIPHER_AES_128_CFB128, - MBEDTLS_CIPHER_AES_192_CFB128, - MBEDTLS_CIPHER_AES_256_CFB128, - MBEDTLS_CIPHER_AES_128_CTR, - MBEDTLS_CIPHER_AES_192_CTR, - MBEDTLS_CIPHER_AES_256_CTR, - MBEDTLS_CIPHER_AES_128_GCM, - MBEDTLS_CIPHER_AES_192_GCM, - MBEDTLS_CIPHER_AES_256_GCM, - MBEDTLS_CIPHER_CAMELLIA_128_ECB, - MBEDTLS_CIPHER_CAMELLIA_192_ECB, - MBEDTLS_CIPHER_CAMELLIA_256_ECB, - MBEDTLS_CIPHER_CAMELLIA_128_CBC, - MBEDTLS_CIPHER_CAMELLIA_192_CBC, - MBEDTLS_CIPHER_CAMELLIA_256_CBC, - MBEDTLS_CIPHER_CAMELLIA_128_CFB128, - MBEDTLS_CIPHER_CAMELLIA_192_CFB128, - MBEDTLS_CIPHER_CAMELLIA_256_CFB128, - MBEDTLS_CIPHER_CAMELLIA_128_CTR, - MBEDTLS_CIPHER_CAMELLIA_192_CTR, - MBEDTLS_CIPHER_CAMELLIA_256_CTR, - MBEDTLS_CIPHER_CAMELLIA_128_GCM, - MBEDTLS_CIPHER_CAMELLIA_192_GCM, - MBEDTLS_CIPHER_CAMELLIA_256_GCM, - MBEDTLS_CIPHER_DES_ECB, - MBEDTLS_CIPHER_DES_CBC, - MBEDTLS_CIPHER_DES_EDE_ECB, - MBEDTLS_CIPHER_DES_EDE_CBC, - MBEDTLS_CIPHER_DES_EDE3_ECB, - MBEDTLS_CIPHER_DES_EDE3_CBC, - MBEDTLS_CIPHER_BLOWFISH_ECB, - MBEDTLS_CIPHER_BLOWFISH_CBC, - MBEDTLS_CIPHER_BLOWFISH_CFB64, - MBEDTLS_CIPHER_BLOWFISH_CTR, - MBEDTLS_CIPHER_ARC4_128, - MBEDTLS_CIPHER_AES_128_CCM, - MBEDTLS_CIPHER_AES_192_CCM, - MBEDTLS_CIPHER_AES_256_CCM, - MBEDTLS_CIPHER_CAMELLIA_128_CCM, - MBEDTLS_CIPHER_CAMELLIA_192_CCM, - MBEDTLS_CIPHER_CAMELLIA_256_CCM, + MBEDTLS_CIPHER_NONE = 0, /**< Placeholder to mark the end of cipher-pair lists. */ + MBEDTLS_CIPHER_NULL, /**< The identity stream cipher. */ + MBEDTLS_CIPHER_AES_128_ECB, /**< AES cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_AES_192_ECB, /**< AES cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_AES_256_ECB, /**< AES cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_AES_128_CBC, /**< AES cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_AES_192_CBC, /**< AES cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_AES_256_CBC, /**< AES cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_AES_128_CFB128, /**< AES cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_192_CFB128, /**< AES cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_256_CFB128, /**< AES cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_128_CTR, /**< AES cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_AES_192_CTR, /**< AES cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_AES_256_CTR, /**< AES cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_AES_128_GCM, /**< AES cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_AES_192_GCM, /**< AES cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_AES_256_GCM, /**< AES cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_ECB, /**< Camellia cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_ECB, /**< Camellia cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_ECB, /**< Camellia cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CBC, /**< Camellia cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CBC, /**< Camellia cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CBC, /**< Camellia cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, /**< Camellia cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, /**< Camellia cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, /**< Camellia cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CTR, /**< Camellia cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CTR, /**< Camellia cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CTR, /**< Camellia cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_GCM, /**< Camellia cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_GCM, /**< Camellia cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_GCM, /**< Camellia cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_DES_ECB, /**< DES cipher with ECB mode. */ + MBEDTLS_CIPHER_DES_CBC, /**< DES cipher with CBC mode. */ + MBEDTLS_CIPHER_DES_EDE_ECB, /**< DES cipher with EDE ECB mode. */ + MBEDTLS_CIPHER_DES_EDE_CBC, /**< DES cipher with EDE CBC mode. */ + MBEDTLS_CIPHER_DES_EDE3_ECB, /**< DES cipher with EDE3 ECB mode. */ + MBEDTLS_CIPHER_DES_EDE3_CBC, /**< DES cipher with EDE3 CBC mode. */ + MBEDTLS_CIPHER_BLOWFISH_ECB, /**< Blowfish cipher with ECB mode. */ + MBEDTLS_CIPHER_BLOWFISH_CBC, /**< Blowfish cipher with CBC mode. */ + MBEDTLS_CIPHER_BLOWFISH_CFB64, /**< Blowfish cipher with CFB64 mode. */ + MBEDTLS_CIPHER_BLOWFISH_CTR, /**< Blowfish cipher with CTR mode. */ + MBEDTLS_CIPHER_ARC4_128, /**< RC4 cipher with 128-bit mode. */ + MBEDTLS_CIPHER_AES_128_CCM, /**< AES cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_AES_192_CCM, /**< AES cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_AES_256_CCM, /**< AES cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CCM, /**< Camellia cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CCM, /**< Camellia cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CCM, /**< Camellia cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_ARIA_128_ECB, /**< Aria cipher with 128-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_192_ECB, /**< Aria cipher with 192-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_256_ECB, /**< Aria cipher with 256-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_128_CBC, /**< Aria cipher with 128-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_192_CBC, /**< Aria cipher with 192-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_256_CBC, /**< Aria cipher with 256-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_128_CFB128, /**< Aria cipher with 128-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_192_CFB128, /**< Aria cipher with 192-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_256_CFB128, /**< Aria cipher with 256-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_128_CTR, /**< Aria cipher with 128-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_192_CTR, /**< Aria cipher with 192-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_256_CTR, /**< Aria cipher with 256-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_128_GCM, /**< Aria cipher with 128-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_192_GCM, /**< Aria cipher with 192-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_256_GCM, /**< Aria cipher with 256-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_128_CCM, /**< Aria cipher with 128-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_192_CCM, /**< Aria cipher with 192-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_256_CCM, /**< Aria cipher with 256-bit key and CCM mode. */ + MBEDTLS_CIPHER_AES_128_OFB, /**< AES 128-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_192_OFB, /**< AES 192-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_256_OFB, /**< AES 256-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_128_XTS, /**< AES 128-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_AES_256_XTS, /**< AES 256-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_CHACHA20, /**< ChaCha20 stream cipher. */ + MBEDTLS_CIPHER_CHACHA20_POLY1305, /**< ChaCha20-Poly1305 AEAD cipher. */ } mbedtls_cipher_type_t; /** Supported cipher modes. */ typedef enum { - MBEDTLS_MODE_NONE = 0, - MBEDTLS_MODE_ECB, - MBEDTLS_MODE_CBC, - MBEDTLS_MODE_CFB, - MBEDTLS_MODE_OFB, /* Unused! */ - MBEDTLS_MODE_CTR, - MBEDTLS_MODE_GCM, - MBEDTLS_MODE_STREAM, - MBEDTLS_MODE_CCM, + MBEDTLS_MODE_NONE = 0, /**< None. */ + MBEDTLS_MODE_ECB, /**< The ECB cipher mode. */ + MBEDTLS_MODE_CBC, /**< The CBC cipher mode. */ + MBEDTLS_MODE_CFB, /**< The CFB cipher mode. */ + MBEDTLS_MODE_OFB, /**< The OFB cipher mode. */ + MBEDTLS_MODE_CTR, /**< The CTR cipher mode. */ + MBEDTLS_MODE_GCM, /**< The GCM cipher mode. */ + MBEDTLS_MODE_STREAM, /**< The stream cipher mode. */ + MBEDTLS_MODE_CCM, /**< The CCM cipher mode. */ + MBEDTLS_MODE_XTS, /**< The XTS cipher mode. */ + MBEDTLS_MODE_CHACHAPOLY, /**< The ChaCha-Poly cipher mode. */ } mbedtls_cipher_mode_t; /** Supported cipher padding types. */ @@ -163,8 +198,8 @@ typedef enum { MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default). */ MBEDTLS_PADDING_ONE_AND_ZEROS, /**< ISO/IEC 7816-4 padding. */ MBEDTLS_PADDING_ZEROS_AND_LEN, /**< ANSI X.923 padding. */ - MBEDTLS_PADDING_ZEROS, /**< zero padding (not reversible). */ - MBEDTLS_PADDING_NONE, /**< never pad (full blocks only). */ + MBEDTLS_PADDING_ZEROS, /**< Zero padding (not reversible). */ + MBEDTLS_PADDING_NONE, /**< Never pad (full blocks only). */ } mbedtls_cipher_padding_t; /** Type of operation. */ @@ -204,7 +239,8 @@ typedef struct mbedtls_cmac_context_t mbedtls_cmac_context_t; * Cipher information. Allows calling cipher functions * in a generic way. */ -typedef struct { +typedef struct mbedtls_cipher_info_t +{ /** Full cipher identifier. For example, * MBEDTLS_CIPHER_AES_256_CBC. */ @@ -228,7 +264,10 @@ typedef struct { */ unsigned int iv_size; - /** Flags to set. For example, if the cipher supports variable IV sizes or variable key sizes. */ + /** Bitflag comprised of MBEDTLS_CIPHER_VARIABLE_IV_LEN and + * MBEDTLS_CIPHER_VARIABLE_KEY_LEN indicating whether the + * cipher supports variable IV or variable key sizes, respectively. + */ int flags; /** The block size, in Bytes. */ @@ -242,7 +281,8 @@ typedef struct { /** * Generic cipher context. */ -typedef struct { +typedef struct mbedtls_cipher_context_t +{ /** Information about the associated cipher. */ const mbedtls_cipher_info_t *cipher_info; @@ -268,7 +308,8 @@ typedef struct { /** Number of Bytes that have not been processed yet. */ size_t unprocessed_len; - /** Current IV or NONCE_COUNTER for CTR-mode. */ + /** Current IV or NONCE_COUNTER for CTR-mode, data unit (or sector) number + * for XTS-mode. */ unsigned char iv[MBEDTLS_MAX_IV_LENGTH]; /** IV size in Bytes, for ciphers with variable-length IVs. */ @@ -296,10 +337,12 @@ const int *mbedtls_cipher_list( void ); * \brief This function retrieves the cipher-information * structure associated with the given cipher name. * - * \param cipher_name Name of the cipher to search for. + * \param cipher_name Name of the cipher to search for. This must not be + * \c NULL. * * \return The cipher information structure associated with the - * given \p cipher_name, or NULL if not found. + * given \p cipher_name. + * \return \c NULL if the associated cipher information is not found. */ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ); @@ -310,7 +353,8 @@ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher * \param cipher_type Type of the cipher to search for. * * \return The cipher information structure associated with the - * given \p cipher_type, or NULL if not found. + * given \p cipher_type. + * \return \c NULL if the associated cipher information is not found. */ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ); @@ -325,7 +369,8 @@ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher * \param mode The cipher mode. For example, #MBEDTLS_MODE_CBC. * * \return The cipher information structure associated with the - * given \p cipher_id, or NULL if not found. + * given \p cipher_id. + * \return \c NULL if the associated cipher information is not found. */ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, int key_bitlen, @@ -333,6 +378,8 @@ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_ciph /** * \brief This function initializes a \p cipher_context as NONE. + * + * \param ctx The context to be initialized. This must not be \c NULL. */ void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ); @@ -340,6 +387,10 @@ void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ); * \brief This function frees and clears the cipher-specific * context of \p ctx. Freeing \p ctx itself remains the * responsibility of the caller. + * + * \param ctx The context to be freed. If this is \c NULL, the + * function has no effect, otherwise this must point to an + * initialized context. */ void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ); @@ -349,31 +400,35 @@ void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ); * structure with the appropriate values. It also clears * the structure. * - * \param ctx The context to initialize. May not be NULL. + * \param ctx The context to initialize. This must be initialized. * \param cipher_info The cipher to use. * - * \return \c 0 on success, - * #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter failure, - * #MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the - * cipher-specific context failed. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context fails. * * \internal Currently, the function also clears the structure. * In future versions, the caller will be required to call * mbedtls_cipher_init() on the structure first. */ -int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ); +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, + const mbedtls_cipher_info_t *cipher_info ); /** * \brief This function returns the block size of the given cipher. * - * \param ctx The context of the cipher. Must be initialized. + * \param ctx The context of the cipher. This must be initialized. * - * \return The size of the blocks of the cipher, or zero if \p ctx - * has not been initialized. + * \return The block size of the underlying cipher. + * \return \c 0 if \p ctx has not been initialized. */ -static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_context_t *ctx ) +static inline unsigned int mbedtls_cipher_get_block_size( + const mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, 0 ); + if( ctx->cipher_info == NULL ) return 0; return ctx->cipher_info->block_size; @@ -383,14 +438,16 @@ static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_c * \brief This function returns the mode of operation for * the cipher. For example, MBEDTLS_MODE_CBC. * - * \param ctx The context of the cipher. Must be initialized. + * \param ctx The context of the cipher. This must be initialized. * - * \return The mode of operation, or #MBEDTLS_MODE_NONE if - * \p ctx has not been initialized. + * \return The mode of operation. + * \return #MBEDTLS_MODE_NONE if \p ctx has not been initialized. */ -static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtls_cipher_context_t *ctx ) +static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( + const mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, MBEDTLS_MODE_NONE ); + if( ctx->cipher_info == NULL ) return MBEDTLS_MODE_NONE; return ctx->cipher_info->mode; @@ -400,15 +457,17 @@ static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtl * \brief This function returns the size of the IV or nonce * of the cipher, in Bytes. * - * \param ctx The context of the cipher. Must be initialized. + * \param ctx The context of the cipher. This must be initialized. * - * \return
  • If no IV has been set: the recommended IV size. - * 0 for ciphers not using IV or nonce.
  • - *
  • If IV has already been set: the actual size.
+ * \return The recommended IV size if no IV has been set. + * \return \c 0 for ciphers not using an IV or a nonce. + * \return The actual size if an IV has been set. */ -static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ctx ) +static inline int mbedtls_cipher_get_iv_size( + const mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, 0 ); + if( ctx->cipher_info == NULL ) return 0; if( ctx->iv_size != 0 ) @@ -420,14 +479,17 @@ static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ct /** * \brief This function returns the type of the given cipher. * - * \param ctx The context of the cipher. Must be initialized. + * \param ctx The context of the cipher. This must be initialized. * - * \return The type of the cipher, or #MBEDTLS_CIPHER_NONE if - * \p ctx has not been initialized. + * \return The type of the cipher. + * \return #MBEDTLS_CIPHER_NONE if \p ctx has not been initialized. */ -static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_cipher_context_t *ctx ) +static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( + const mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + MBEDTLS_INTERNAL_VALIDATE_RET( + ctx != NULL, MBEDTLS_CIPHER_NONE ); + if( ctx->cipher_info == NULL ) return MBEDTLS_CIPHER_NONE; return ctx->cipher_info->type; @@ -437,14 +499,16 @@ static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_ciphe * \brief This function returns the name of the given cipher * as a string. * - * \param ctx The context of the cipher. Must be initialized. + * \param ctx The context of the cipher. This must be initialized. * - * \return The name of the cipher, or NULL if \p ctx has not - * been not initialized. + * \return The name of the cipher. + * \return NULL if \p ctx has not been not initialized. */ -static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_t *ctx ) +static inline const char *mbedtls_cipher_get_name( + const mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, 0 ); + if( ctx->cipher_info == NULL ) return 0; return ctx->cipher_info->name; @@ -453,15 +517,18 @@ static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_ /** * \brief This function returns the key length of the cipher. * - * \param ctx The context of the cipher. Must be initialized. + * \param ctx The context of the cipher. This must be initialized. * - * \return The key length of the cipher in bits, or - * #MBEDTLS_KEY_LENGTH_NONE if ctx \p has not been + * \return The key length of the cipher in bits. + * \return #MBEDTLS_KEY_LENGTH_NONE if ctx \p has not been * initialized. */ -static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t *ctx ) +static inline int mbedtls_cipher_get_key_bitlen( + const mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + MBEDTLS_INTERNAL_VALIDATE_RET( + ctx != NULL, MBEDTLS_KEY_LENGTH_NONE ); + if( ctx->cipher_info == NULL ) return MBEDTLS_KEY_LENGTH_NONE; return (int) ctx->cipher_info->key_bitlen; @@ -470,15 +537,17 @@ static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t /** * \brief This function returns the operation of the given cipher. * - * \param ctx The context of the cipher. Must be initialized. + * \param ctx The context of the cipher. This must be initialized. * - * \return The type of operation: #MBEDTLS_ENCRYPT or - * #MBEDTLS_DECRYPT, or #MBEDTLS_OPERATION_NONE if \p ctx - * has not been initialized. + * \return The type of operation: #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. + * \return #MBEDTLS_OPERATION_NONE if \p ctx has not been initialized. */ -static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_cipher_context_t *ctx ) +static inline mbedtls_operation_t mbedtls_cipher_get_operation( + const mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + MBEDTLS_INTERNAL_VALIDATE_RET( + ctx != NULL, MBEDTLS_OPERATION_NONE ); + if( ctx->cipher_info == NULL ) return MBEDTLS_OPERATION_NONE; return ctx->operation; @@ -487,20 +556,23 @@ static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_ci /** * \brief This function sets the key to use with the given context. * - * \param ctx The generic cipher context. May not be NULL. Must have - * been initialized using mbedtls_cipher_info_from_type() - * or mbedtls_cipher_info_from_string(). - * \param key The key to use. - * \param key_bitlen The key length to use, in bits. + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param key The key to use. This must be a readable buffer of at + * least \p key_bitlen Bits. + * \param key_bitlen The key length to use, in Bits. * \param operation The operation that the key will be used for: * #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. * - * \returns \c 0 on success, #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if - * parameter verification fails, or a cipher-specific - * error code. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. */ -int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, - int key_bitlen, const mbedtls_operation_t operation ); +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, + const unsigned char *key, + int key_bitlen, + const mbedtls_operation_t operation ); #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) /** @@ -509,59 +581,71 @@ int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *k * * The default passing mode is PKCS7 padding. * - * \param ctx The generic cipher context. + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. * \param mode The padding mode. * - * \returns \c 0 on success, #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE - * if the selected padding mode is not supported, or - * #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE + * if the selected padding mode is not supported. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode * does not support padding. */ -int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ); +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, + mbedtls_cipher_padding_t mode ); #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ /** * \brief This function sets the initialization vector (IV) * or nonce. * - * \param ctx The generic cipher context. - * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * \note Some ciphers do not use IVs nor nonce. For these + * ciphers, this function has no effect. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. This + * must be a readable buffer of at least \p iv_len Bytes. * \param iv_len The IV length for ciphers with variable-size IV. * This parameter is discarded by ciphers with fixed-size IV. * - * \returns \c 0 on success, or #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA - * - * \note Some ciphers do not use IVs nor nonce. For these - * ciphers, this function has no effect. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. */ int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, - const unsigned char *iv, size_t iv_len ); + const unsigned char *iv, + size_t iv_len ); /** * \brief This function resets the cipher state. * - * \param ctx The generic cipher context. + * \param ctx The generic cipher context. This must be initialized. * - * \returns \c 0 on success, #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA - * if parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. */ int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ); -#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) /** * \brief This function adds additional data for AEAD ciphers. - * Only supported with GCM. Must be called - * exactly once, after mbedtls_cipher_reset(). + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called exactly once, after + * mbedtls_cipher_reset(). * - * \param ctx The generic cipher context. - * \param ad The additional data to use. - * \param ad_len the Length of \p ad. + * \param ctx The generic cipher context. This must be initialized. + * \param ad The additional data to use. This must be a readable + * buffer of at least \p ad_len Bytes. + * \param ad_len the Length of \p ad Bytes. * - * \return \c 0 on success, or a specific error code on failure. + * \return \c 0 on success. + * \return A specific error code on failure. */ int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, const unsigned char *ad, size_t ad_len ); -#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ /** * \brief The generic cipher update function. It encrypts or @@ -573,25 +657,29 @@ int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, * Exception: For MBEDTLS_MODE_ECB, expects a single block * in size. For example, 16 Bytes for AES. * - * \param ctx The generic cipher context. - * \param input The buffer holding the input data. + * \note If the underlying cipher is used in GCM mode, all calls + * to this function, except for the last one before + * mbedtls_cipher_finish(), must have \p ilen as a + * multiple of the block size of the cipher. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. * \param ilen The length of the input data. - * \param output The buffer for the output data. Must be able to hold at - * least \p ilen + block_size. Must not be the same buffer - * as input. + * \param output The buffer for the output data. This must be able to + * hold at least `ilen + block_size`. This must not be the + * same buffer as \p input. * \param olen The length of the output data, to be updated with the - * actual number of Bytes written. + * actual number of Bytes written. This must not be + * \c NULL. * - * \returns \c 0 on success, #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if - * parameter verification fails, - * #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an - * unsupported mode for a cipher, or a cipher-specific - * error code. - * - * \note If the underlying cipher is GCM, all calls to this - * function, except the last one before - * mbedtls_cipher_finish(). Must have \p ilen as a - * multiple of the block_size. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher. + * \return A cipher-specific error code on failure. */ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen ); @@ -602,78 +690,94 @@ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *i * contained in it is padded to the size of * the last block, and written to the \p output buffer. * - * \param ctx The generic cipher context. - * \param output The buffer to write data to. Needs block_size available. + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param output The buffer to write data to. This needs to be a writable + * buffer of at least \p block_size Bytes. * \param olen The length of the data written to the \p output buffer. + * This may not be \c NULL. * - * \returns \c 0 on success, #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if - * parameter verification fails, - * #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption - * expected a full block but was not provided one, - * #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding - * while decrypting, or a cipher-specific error code - * on failure for any other reason. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. + * \return A cipher-specific error code on failure. */ int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen ); -#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) /** * \brief This function writes a tag for AEAD ciphers. - * Only supported with GCM. - * Must be called after mbedtls_cipher_finish(). - * - * \param ctx The generic cipher context. - * \param tag The buffer to write the tag to. + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called after mbedtls_cipher_finish(). + * + * \param ctx The generic cipher context. This must be initialized, + * bound to a key, and have just completed a cipher + * operation through mbedtls_cipher_finish() the tag for + * which should be written. + * \param tag The buffer to write the tag to. This must be a writable + * buffer of at least \p tag_len Bytes. * \param tag_len The length of the tag to write. * - * \return \c 0 on success, or a specific error code on failure. + * \return \c 0 on success. + * \return A specific error code on failure. */ int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, unsigned char *tag, size_t tag_len ); /** * \brief This function checks the tag for AEAD ciphers. - * Only supported with GCM. - * Must be called after mbedtls_cipher_finish(). + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called after mbedtls_cipher_finish(). * - * \param ctx The generic cipher context. - * \param tag The buffer holding the tag. + * \param ctx The generic cipher context. This must be initialized. + * \param tag The buffer holding the tag. This must be a readable + * buffer of at least \p tag_len Bytes. * \param tag_len The length of the tag to check. * - * \return \c 0 on success, or a specific error code on failure. + * \return \c 0 on success. + * \return A specific error code on failure. */ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, const unsigned char *tag, size_t tag_len ); -#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ /** * \brief The generic all-in-one encryption/decryption function, * for all ciphers except AEAD constructs. * - * \param ctx The generic cipher context. + * \param ctx The generic cipher context. This must be initialized. * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * This must be a readable buffer of at least \p iv_len + * Bytes. * \param iv_len The IV length for ciphers with variable-size IV. * This parameter is discarded by ciphers with fixed-size * IV. - * \param input The buffer holding the input data. - * \param ilen The length of the input data. - * \param output The buffer for the output data. Must be able to hold at - * least \p ilen + block_size. Must not be the same buffer - * as input. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The buffer for the output data. This must be able to + * hold at least `ilen + block_size`. This must not be the + * same buffer as \p input. * \param olen The length of the output data, to be updated with the - * actual number of Bytes written. + * actual number of Bytes written. This must not be + * \c NULL. * * \note Some ciphers do not use IVs nor nonce. For these * ciphers, use \p iv = NULL and \p iv_len = 0. * - * \returns \c 0 on success, or - * #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or - * #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption - * expected a full block but was not provided one, or - * #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding - * while decrypting, or a cipher-specific error code on - * failure for any other reason. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. + * \return A cipher-specific error code on failure. */ int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, @@ -684,24 +788,32 @@ int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, /** * \brief The generic autenticated encryption (AEAD) function. * - * \param ctx The generic cipher context. + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * This must be a readable buffer of at least \p iv_len + * Bytes. * \param iv_len The IV length for ciphers with variable-size IV. * This parameter is discarded by ciphers with fixed-size IV. - * \param ad The additional data to authenticate. + * \param ad The additional data to authenticate. This must be a + * readable buffer of at least \p ad_len Bytes. * \param ad_len The length of \p ad. - * \param input The buffer holding the input data. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. * \param ilen The length of the input data. - * \param output The buffer for the output data. - * Must be able to hold at least \p ilen. + * \param output The buffer for the output data. This must be able to + * hold at least \p ilen Bytes. * \param olen The length of the output data, to be updated with the - * actual number of Bytes written. - * \param tag The buffer for the authentication tag. + * actual number of Bytes written. This must not be + * \c NULL. + * \param tag The buffer for the authentication tag. This must be a + * writable buffer of at least \p tag_len Bytes. * \param tag_len The desired length of the authentication tag. * - * \returns \c 0 on success, or - * #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or - * a cipher-specific error code. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. */ int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, @@ -713,29 +825,37 @@ int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, /** * \brief The generic autenticated decryption (AEAD) function. * - * \param ctx The generic cipher context. + * \note If the data is not authentic, then the output buffer + * is zeroed out to prevent the unauthentic plaintext being + * used, making this interface safer. + * + * \param ctx The generic cipher context. This must be initialized and + * and bound to a key. * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * This must be a readable buffer of at least \p iv_len + * Bytes. * \param iv_len The IV length for ciphers with variable-size IV. * This parameter is discarded by ciphers with fixed-size IV. - * \param ad The additional data to be authenticated. + * \param ad The additional data to be authenticated. This must be a + * readable buffer of at least \p ad_len Bytes. * \param ad_len The length of \p ad. - * \param input The buffer holding the input data. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. * \param ilen The length of the input data. * \param output The buffer for the output data. - * Must be able to hold at least \p ilen. + * This must be able to hold at least \p ilen Bytes. * \param olen The length of the output data, to be updated with the - * actual number of Bytes written. - * \param tag The buffer holding the authentication tag. + * actual number of Bytes written. This must not be + * \c NULL. + * \param tag The buffer holding the authentication tag. This must be + * a readable buffer of at least \p tag_len Bytes. * \param tag_len The length of the authentication tag. * - * \returns \c 0 on success, or - * #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or - * #MBEDTLS_ERR_CIPHER_AUTH_FAILED if data is not authentic, - * or a cipher-specific error code on failure for any other reason. - * - * \note If the data is not authentic, then the output buffer - * is zeroed out to prevent the unauthentic plaintext being - * used, making this interface safer. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_AUTH_FAILED if data is not authentic. + * \return A cipher-specific error code on failure. */ int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, diff --git a/app/include/mbedtls/cipher_internal.h b/app/include/mbedtls/cipher_internal.h index 969ff9ccb8..c6def0bef7 100644 --- a/app/include/mbedtls/cipher_internal.h +++ b/app/include/mbedtls/cipher_internal.h @@ -64,6 +64,14 @@ struct mbedtls_cipher_base_t unsigned char *output ); #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /** Encrypt using OFB (Full length) */ + int (*ofb_func)( void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, + const unsigned char *input, + unsigned char *output ); +#endif + #if defined(MBEDTLS_CIPHER_MODE_CTR) /** Encrypt using CTR */ int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, @@ -71,6 +79,13 @@ struct mbedtls_cipher_base_t const unsigned char *input, unsigned char *output ); #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + /** Encrypt or decrypt using XTS. */ + int (*xts_func)( void *ctx, mbedtls_operation_t mode, size_t length, + const unsigned char data_unit[16], + const unsigned char *input, unsigned char *output ); +#endif + #if defined(MBEDTLS_CIPHER_MODE_STREAM) /** Encrypt using STREAM */ int (*stream_func)( void *ctx, size_t length, diff --git a/app/include/mbedtls/cmac.h b/app/include/mbedtls/cmac.h index 24839a20eb..9d42b3f209 100644 --- a/app/include/mbedtls/cmac.h +++ b/app/include/mbedtls/cmac.h @@ -1,8 +1,10 @@ /** * \file cmac.h * - * \brief The Cipher-based Message Authentication Code (CMAC) Mode for - * Authentication. + * \brief This file contains CMAC definitions and functions. + * + * The Cipher-based Message Authentication Code (CMAC) Mode for + * Authentication is defined in RFC-4493: The AES-CMAC Algorithm. */ /* * Copyright (C) 2015-2018, Arm Limited (or its affiliates), All Rights Reserved @@ -26,21 +28,28 @@ #ifndef MBEDTLS_CMAC_H #define MBEDTLS_CMAC_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "cipher.h" #ifdef __cplusplus extern "C" { #endif +/* MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED -0x007A /**< CMAC hardware accelerator failed. */ #define MBEDTLS_AES_BLOCK_SIZE 16 #define MBEDTLS_DES3_BLOCK_SIZE 8 #if defined(MBEDTLS_AES_C) -#define MBEDTLS_CIPHER_BLKSIZE_MAX 16 /* The longest block used by CMAC is that of AES. */ +#define MBEDTLS_CIPHER_BLKSIZE_MAX 16 /**< The longest block used by CMAC is that of AES. */ #else -#define MBEDTLS_CIPHER_BLKSIZE_MAX 8 /* The longest block used by CMAC is that of 3DES. */ +#define MBEDTLS_CIPHER_BLKSIZE_MAX 8 /**< The longest block used by CMAC is that of 3DES. */ #endif #if !defined(MBEDTLS_CMAC_ALT) @@ -61,22 +70,25 @@ struct mbedtls_cmac_context_t size_t unprocessed_len; }; +#else /* !MBEDTLS_CMAC_ALT */ +#include "cmac_alt.h" +#endif /* !MBEDTLS_CMAC_ALT */ + /** * \brief This function sets the CMAC key, and prepares to authenticate * the input data. * Must be called with an initialized cipher context. * * \param ctx The cipher context used for the CMAC operation, initialized - * as one of the following types:
    - *
  • MBEDTLS_CIPHER_AES_128_ECB
  • - *
  • MBEDTLS_CIPHER_AES_192_ECB
  • - *
  • MBEDTLS_CIPHER_AES_256_ECB
  • - *
  • MBEDTLS_CIPHER_DES_EDE3_ECB
+ * as one of the following types: MBEDTLS_CIPHER_AES_128_ECB, + * MBEDTLS_CIPHER_AES_192_ECB, MBEDTLS_CIPHER_AES_256_ECB, + * or MBEDTLS_CIPHER_DES_EDE3_ECB. * \param key The CMAC key. * \param keybits The length of the CMAC key in bits. * Must be supported by the cipher. * - * \return \c 0 on success, or a cipher-specific error code. + * \return \c 0 on success. + * \return A cipher-specific error code on failure. */ int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, const unsigned char *key, size_t keybits ); @@ -93,8 +105,9 @@ int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, * \param input The buffer holding the input data. * \param ilen The length of the input data. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA - * if parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. */ int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, size_t ilen ); @@ -110,7 +123,8 @@ int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, * \param ctx The cipher context used for the CMAC operation. * \param output The output buffer for the CMAC checksum result. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA * if parameter verification fails. */ int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, @@ -126,7 +140,8 @@ int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, * * \param ctx The cipher context used for the CMAC operation. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA * if parameter verification fails. */ int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ); @@ -149,7 +164,8 @@ int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ); * \param ilen The length of the input data. * \param output The buffer for the generic CMAC result. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA * if parameter verification fails. */ int mbedtls_cipher_cmac( const mbedtls_cipher_info_t *cipher_info, @@ -180,23 +196,12 @@ int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_len, unsigned char output[16] ); #endif /* MBEDTLS_AES_C */ -#ifdef __cplusplus -} -#endif - -#else /* !MBEDTLS_CMAC_ALT */ -#include "cmac_alt.h" -#endif /* !MBEDTLS_CMAC_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - #if defined(MBEDTLS_SELF_TEST) && ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) ) /** * \brief The CMAC checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_cmac_self_test( int verbose ); #endif /* MBEDTLS_SELF_TEST && ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ diff --git a/app/include/mbedtls/compat-1.3.h b/app/include/mbedtls/compat-1.3.h index 600a0f154c..a58b47243d 100644 --- a/app/include/mbedtls/compat-1.3.h +++ b/app/include/mbedtls/compat-1.3.h @@ -25,6 +25,12 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #if ! defined(MBEDTLS_DEPRECATED_REMOVED) #if defined(MBEDTLS_DEPRECATED_WARNING) @@ -1378,7 +1384,8 @@ #define SSL_ANTI_REPLAY_ENABLED MBEDTLS_SSL_ANTI_REPLAY_ENABLED #define SSL_ARC4_DISABLED MBEDTLS_SSL_ARC4_DISABLED #define SSL_ARC4_ENABLED MBEDTLS_SSL_ARC4_ENABLED -#define SSL_BUFFER_LEN MBEDTLS_SSL_BUFFER_LEN +#define SSL_BUFFER_LEN ( ( ( MBEDTLS_SSL_IN_BUFFER_LEN ) < ( MBEDTLS_SSL_OUT_BUFFER_LEN ) ) \ + ? ( MBEDTLS_SSL_IN_BUFFER_LEN ) : ( MBEDTLS_SSL_OUT_BUFFER_LEN ) ) #define SSL_CACHE_DEFAULT_MAX_ENTRIES MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES #define SSL_CACHE_DEFAULT_TIMEOUT MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT #define SSL_CBC_RECORD_SPLITTING_DISABLED MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED diff --git a/app/include/mbedtls/config.h b/app/include/mbedtls/config.h index 50239e1ff5..834cced87f 100644 --- a/app/include/mbedtls/config.h +++ b/app/include/mbedtls/config.h @@ -8,7 +8,7 @@ * memory footprint. */ /* - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -48,10 +48,14 @@ * Requires support for asm() in compiler. * * Used in: + * library/aria.c * library/timing.c - * library/padlock.c * include/mbedtls/bn_mul.h * + * Required by: + * MBEDTLS_AESNI_C + * MBEDTLS_PADLOCK_C + * * Comment to disable the use of assembly code. */ #define MBEDTLS_HAVE_ASM @@ -84,6 +88,28 @@ */ //#define MBEDTLS_NO_UDBL_DIVISION +/** + * \def MBEDTLS_NO_64BIT_MULTIPLICATION + * + * The platform lacks support for 32x32 -> 64-bit multiplication. + * + * Used in: + * library/poly1305.c + * + * Some parts of the library may use multiplication of two unsigned 32-bit + * operands with a 64-bit result in order to speed up computations. On some + * platforms, this is not available in hardware and has to be implemented in + * software, usually in a library provided by the toolchain. + * + * Sometimes it is not desirable to have to link to that library. This option + * removes the dependency of that library on platforms that lack a hardware + * 64-bit multiplier by embedding a software implementation in Mbed TLS. + * + * Note that depending on the compiler, this may decrease performance compared + * to using the library function provided by the toolchain. + */ +//#define MBEDTLS_NO_64BIT_MULTIPLICATION + /** * \def MBEDTLS_HAVE_SSE2 * @@ -111,12 +137,21 @@ /** * \def MBEDTLS_HAVE_TIME_DATE * - * System has time.h and time(), gmtime() and the clock is correct. - * The time needs to be correct (not necesarily very accurate, but at least + * System has time.h, time(), and an implementation for + * mbedtls_platform_gmtime_r() (see below). + * The time needs to be correct (not necessarily very accurate, but at least * the date should be correct). This is used to verify the validity period of * X.509 certificates. * * Comment if your system does not have a correct clock. + * + * \note mbedtls_platform_gmtime_r() is an abstraction in platform_util.h that + * behaves similarly to the gmtime_r() function from the C standard. Refer to + * the documentation for mbedtls_platform_gmtime_r() for more information. + * + * \note It is possible to configure an implementation for + * mbedtls_platform_gmtime_r() at compile-time by using the macro + * MBEDTLS_PLATFORM_GMTIME_R_ALT. */ #define MBEDTLS_HAVE_TIME_DATE @@ -221,6 +256,72 @@ */ //#define MBEDTLS_DEPRECATED_REMOVED +/** + * \def MBEDTLS_CHECK_PARAMS + * + * This configuration option controls whether the library validates more of + * the parameters passed to it. + * + * When this flag is not defined, the library only attempts to validate an + * input parameter if: (1) they may come from the outside world (such as the + * network, the filesystem, etc.) or (2) not validating them could result in + * internal memory errors such as overflowing a buffer controlled by the + * library. On the other hand, it doesn't attempt to validate parameters whose + * values are fully controlled by the application (such as pointers). + * + * When this flag is defined, the library additionally attempts to validate + * parameters that are fully controlled by the application, and should always + * be valid if the application code is fully correct and trusted. + * + * For example, when a function accepts as input a pointer to a buffer that may + * contain untrusted data, and its documentation mentions that this pointer + * must not be NULL: + * - The pointer is checked to be non-NULL only if this option is enabled. + * - The content of the buffer is always validated. + * + * When this flag is defined, if a library function receives a parameter that + * is invalid: + * 1. The function will invoke the macro MBEDTLS_PARAM_FAILED(). + * 2. If MBEDTLS_PARAM_FAILED() did not terminate the program, the function + * will immediately return. If the function returns an Mbed TLS error code, + * the error code in this case is MBEDTLS_ERR_xxx_BAD_INPUT_DATA. + * + * When defining this flag, you also need to arrange a definition for + * MBEDTLS_PARAM_FAILED(). You can do this by any of the following methods: + * - By default, the library defines MBEDTLS_PARAM_FAILED() to call a + * function mbedtls_param_failed(), but the library does not define this + * function. If you do not make any other arrangements, you must provide + * the function mbedtls_param_failed() in your application. + * See `platform_util.h` for its prototype. + * - If you enable the macro #MBEDTLS_CHECK_PARAMS_ASSERT, then the + * library defines #MBEDTLS_PARAM_FAILED(\c cond) to be `assert(cond)`. + * You can still supply an alternative definition of + * MBEDTLS_PARAM_FAILED(), which may call `assert`. + * - If you define a macro MBEDTLS_PARAM_FAILED() before including `config.h` + * or you uncomment the definition of MBEDTLS_PARAM_FAILED() in `config.h`, + * the library will call the macro that you defined and will not supply + * its own version. Note that if MBEDTLS_PARAM_FAILED() calls `assert`, + * you need to enable #MBEDTLS_CHECK_PARAMS_ASSERT so that library source + * files include ``. + * + * Uncomment to enable validation of application-controlled parameters. + */ +//#define MBEDTLS_CHECK_PARAMS + +/** + * \def MBEDTLS_CHECK_PARAMS_ASSERT + * + * Allow MBEDTLS_PARAM_FAILED() to call `assert`, and make it default to + * `assert`. This macro is only used if #MBEDTLS_CHECK_PARAMS is defined. + * + * If this macro is not defined, then MBEDTLS_PARAM_FAILED() defaults to + * calling a function mbedtls_param_failed(). See the documentation of + * #MBEDTLS_CHECK_PARAMS for details. + * + * Uncomment to allow MBEDTLS_PARAM_FAILED() to call `assert`. + */ +//#define MBEDTLS_CHECK_PARAMS_ASSERT + /* \} name SECTION: System support */ /** @@ -271,23 +372,29 @@ */ //#define MBEDTLS_AES_ALT //#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_ARIA_ALT //#define MBEDTLS_BLOWFISH_ALT //#define MBEDTLS_CAMELLIA_ALT //#define MBEDTLS_CCM_ALT +//#define MBEDTLS_CHACHA20_ALT +//#define MBEDTLS_CHACHAPOLY_ALT //#define MBEDTLS_CMAC_ALT //#define MBEDTLS_DES_ALT //#define MBEDTLS_DHM_ALT //#define MBEDTLS_ECJPAKE_ALT //#define MBEDTLS_GCM_ALT +//#define MBEDTLS_NIST_KW_ALT //#define MBEDTLS_MD2_ALT //#define MBEDTLS_MD4_ALT //#define MBEDTLS_MD5_ALT +//#define MBEDTLS_POLY1305_ALT //#define MBEDTLS_RIPEMD160_ALT //#define MBEDTLS_RSA_ALT //#define MBEDTLS_SHA1_ALT //#define MBEDTLS_SHA256_ALT //#define MBEDTLS_SHA512_ALT //#define MBEDTLS_XTEA_ALT + /* * When replacing the elliptic curve module, pleace consider, that it is * implemented with two .c files: @@ -318,7 +425,7 @@ * \note Because of a signature change, the core AES encryption and decryption routines are * currently named mbedtls_aes_internal_encrypt and mbedtls_aes_internal_decrypt, * respectively. When setting up alternative implementations, these functions should - * be overriden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt + * be overridden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt * must stay untouched. * * \note If you use the AES_xxx_ALT macros, then is is recommended to also set @@ -333,6 +440,16 @@ * dependencies on them, and considering stronger message digests * and ciphers instead. * + * \warning If both MBEDTLS_ECDSA_SIGN_ALT and MBEDTLS_ECDSA_DETERMINISTIC are + * enabled, then the deterministic ECDH signature functions pass the + * the static HMAC-DRBG as RNG to mbedtls_ecdsa_sign(). Therefore + * alternative implementations should use the RNG only for generating + * the ephemeral key and nothing else. If this is not possible, then + * MBEDTLS_ECDSA_DETERMINISTIC should be disabled and an alternative + * implementation should be provided for mbedtls_ecdsa_sign_det_ext() + * (and for mbedtls_ecdsa_sign_det() too if backward compatibility is + * desirable). + * */ //#define MBEDTLS_MD2_PROCESS_ALT //#define MBEDTLS_MD4_PROCESS_ALT @@ -373,11 +490,11 @@ * unsigned char mbedtls_internal_ecp_grp_capable( * const mbedtls_ecp_group *grp ) * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) - * void mbedtls_internal_ecp_deinit( const mbedtls_ecp_group *grp ) + * void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ) * The mbedtls_internal_ecp_grp_capable function should return 1 if the * replacement functions implement arithmetic for the given group and 0 * otherwise. - * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_deinit are + * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_free are * called before and after each point operation and provide an opportunity to * implement optimized set up and tear down instructions. * @@ -440,12 +557,45 @@ /** * \def MBEDTLS_AES_ROM_TABLES * - * Store the AES tables in ROM. + * Use precomputed AES tables stored in ROM. + * + * Uncomment this macro to use precomputed AES tables stored in ROM. + * Comment this macro to generate AES tables in RAM at runtime. + * + * Tradeoff: Using precomputed ROM tables reduces RAM usage by ~8kb + * (or ~2kb if \c MBEDTLS_AES_FEWER_TABLES is used) and reduces the + * initialization time before the first AES operation can be performed. + * It comes at the cost of additional ~8kb ROM use (resp. ~2kb if \c + * MBEDTLS_AES_FEWER_TABLES below is used), and potentially degraded + * performance if ROM access is slower than RAM access. + * + * This option is independent of \c MBEDTLS_AES_FEWER_TABLES. * - * Uncomment this macro to store the AES tables in ROM. */ //#define MBEDTLS_AES_ROM_TABLES +/** + * \def MBEDTLS_AES_FEWER_TABLES + * + * Use less ROM/RAM for AES tables. + * + * Uncommenting this macro omits 75% of the AES tables from + * ROM / RAM (depending on the value of \c MBEDTLS_AES_ROM_TABLES) + * by computing their values on the fly during operations + * (the tables are entry-wise rotations of one another). + * + * Tradeoff: Uncommenting this reduces the RAM / ROM footprint + * by ~6kb but at the cost of more arithmetic operations during + * runtime. Specifically, one has to compare 4 accesses within + * different tables to 4 accesses with additional arithmetic + * operations within the same table. The performance gain/loss + * depends on the system and memory details. + * + * This option is independent of \c MBEDTLS_AES_ROM_TABLES. + * + */ +//#define MBEDTLS_AES_FEWER_TABLES + /** * \def MBEDTLS_CAMELLIA_SMALL_MEMORY * @@ -476,6 +626,20 @@ */ #define MBEDTLS_CIPHER_MODE_CTR +/** + * \def MBEDTLS_CIPHER_MODE_OFB + * + * Enable Output Feedback mode (OFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_OFB + +/** + * \def MBEDTLS_CIPHER_MODE_XTS + * + * Enable Xor-encrypt-xor with ciphertext stealing mode (XTS) for AES. + */ +#define MBEDTLS_CIPHER_MODE_XTS + /** * \def MBEDTLS_CIPHER_NULL_CIPHER * @@ -525,6 +689,13 @@ #define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN #define MBEDTLS_CIPHER_PADDING_ZEROS +/** \def MBEDTLS_CTR_DRBG_USE_128_BIT_KEY + * + * Uncomment this macro to use a 128-bit key in the CTR_DRBG module. + * By default, CTR_DRBG uses a 256-bit key. + */ +//#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY + /** * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES * @@ -556,6 +727,26 @@ */ #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +/** + * \def MBEDTLS_REMOVE_3DES_CIPHERSUITES + * + * Remove 3DES ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on 3DES from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible + * to enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including + * them explicitly. + * + * A man-in-the-browser attacker can recover authentication tokens sent through + * a TLS connection using a 3DES based cipher suite (see "On the Practical + * (In-)Security of 64-bit Block Ciphers" by Karthikeyan Bhargavan and Gaëtan + * Leurent, see https://sweet32.info/SWEET32_CCS16.pdf). If this attack falls + * in your threat model or you are unsure, then you should keep this option + * enabled to remove 3DES based cipher suites. + * + * Comment this macro to keep 3DES in the default ciphersuite list. + */ +#define MBEDTLS_REMOVE_3DES_CIPHERSUITES + /** * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED * @@ -576,6 +767,7 @@ #define MBEDTLS_ECP_DP_BP384R1_ENABLED #define MBEDTLS_ECP_DP_BP512R1_ENABLED #define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_ECP_DP_CURVE448_ENABLED /** * \def MBEDTLS_ECP_NIST_OPTIM @@ -588,6 +780,30 @@ */ #define MBEDTLS_ECP_NIST_OPTIM +/** + * \def MBEDTLS_ECP_RESTARTABLE + * + * Enable "non-blocking" ECC operations that can return early and be resumed. + * + * This allows various functions to pause by returning + * #MBEDTLS_ERR_ECP_IN_PROGRESS (or, for functions in the SSL module, + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) and then be called later again in + * order to further progress and eventually complete their operation. This is + * controlled through mbedtls_ecp_set_max_ops() which limits the maximum + * number of ECC operations a function may perform before pausing; see + * mbedtls_ecp_set_max_ops() for more information. + * + * This is useful in non-threaded environments if you want to avoid blocking + * for too long on ECC (and, hence, X.509 or SSL/TLS) operations. + * + * Uncomment this macro to enable restartable ECC computations. + * + * \note This option only works with the default software implementation of + * elliptic curve functionality. It is incompatible with + * MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT and MBEDTLS_ECDSA_XXX_ALT. + */ +//#define MBEDTLS_ECP_RESTARTABLE + /** * \def MBEDTLS_ECDSA_DETERMINISTIC * @@ -1094,6 +1310,17 @@ */ #define MBEDTLS_SSL_ALL_ALERT_MESSAGES +/** + * \def MBEDTLS_SSL_ASYNC_PRIVATE + * + * Enable asynchronous external private key operations in SSL. This allows + * you to configure an SSL connection to call an external cryptographic + * module to perform private key operations instead of performing the + * operation inside the library. + * + */ +//#define MBEDTLS_SSL_ASYNC_PRIVATE + /** * \def MBEDTLS_SSL_DEBUG_ALL * @@ -1372,7 +1599,7 @@ * \def MBEDTLS_SSL_SESSION_TICKETS * * Enable support for RFC 5077 session tickets in SSL. - * Client-side, provides full support for session tickets (maintainance of a + * Client-side, provides full support for session tickets (maintenance of a * session store remains the responsibility of the application, though). * Server-side, you also need to provide callbacks for writing and parsing * tickets, including authenticated encryption and key management. Example @@ -1538,10 +1765,13 @@ * * \warning TLS-level compression MAY REDUCE SECURITY! See for example the * CRIME attack. Before enabling this option, you should examine with care if - * CRIME or similar exploits may be a applicable to your use case. + * CRIME or similar exploits may be applicable to your use case. * * \note Currently compression can't be used with DTLS. * + * \deprecated This feature is deprecated and will be removed + * in the next major revision of the library. + * * Used in: library/ssl_tls.c * library/ssl_cli.c * library/ssl_srv.c @@ -1580,7 +1810,7 @@ * Enable the AES block cipher. * * Module: library/aes.c - * Caller: library/ssl_tls.c + * Caller: library/cipher.c * library/pem.c * library/ctr_drbg.c * @@ -1655,7 +1885,7 @@ * Enable the ARCFOUR stream cipher. * * Module: library/arc4.c - * Caller: library/ssl_tls.c + * Caller: library/cipher.c * * This module enables the following ciphersuites (if other requisites are * enabled as well): @@ -1749,7 +1979,7 @@ * Enable the Camellia block cipher. * * Module: library/camellia.c - * Caller: library/ssl_tls.c + * Caller: library/cipher.c * * This module enables the following ciphersuites (if other requisites are * enabled as well): @@ -1798,6 +2028,58 @@ */ #define MBEDTLS_CAMELLIA_C +/** + * \def MBEDTLS_ARIA_C + * + * Enable the ARIA block cipher. + * + * Module: library/aria.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * + * MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 + */ +//#define MBEDTLS_ARIA_C + /** * \def MBEDTLS_CCM_C * @@ -1824,6 +2106,26 @@ */ #define MBEDTLS_CERTS_C +/** + * \def MBEDTLS_CHACHA20_C + * + * Enable the ChaCha20 stream cipher. + * + * Module: library/chacha20.c + */ +#define MBEDTLS_CHACHA20_C + +/** + * \def MBEDTLS_CHACHAPOLY_C + * + * Enable the ChaCha20-Poly1305 AEAD algorithm. + * + * Module: library/chachapoly.c + * + * This module requires: MBEDTLS_CHACHA20_C, MBEDTLS_POLY1305_C + */ +#define MBEDTLS_CHACHAPOLY_C + /** * \def MBEDTLS_CIPHER_C * @@ -1852,14 +2154,20 @@ /** * \def MBEDTLS_CTR_DRBG_C * - * Enable the CTR_DRBG AES-256-based random generator. + * Enable the CTR_DRBG AES-based random generator. + * The CTR_DRBG generator uses AES-256 by default. + * To use AES-128 instead, enable \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY above. + * + * \note To achieve a 256-bit security strength with CTR_DRBG, + * you must use AES-256 *and* use sufficient entropy. + * See ctr_drbg.h for more details. * * Module: library/ctr_drbg.c * Caller: * * Requires: MBEDTLS_AES_C * - * This module provides the CTR_DRBG AES-256 random number generator. + * This module provides the CTR_DRBG AES random number generator. */ #define MBEDTLS_CTR_DRBG_C @@ -1884,7 +2192,7 @@ * * Module: library/des.c * Caller: library/pem.c - * library/ssl_tls.c + * library/cipher.c * * This module enables the following ciphersuites (if other requisites are * enabled as well): @@ -2054,6 +2362,21 @@ */ //#define MBEDTLS_HAVEGE_C +/** + * \def MBEDTLS_HKDF_C + * + * Enable the HKDF algorithm (RFC 5869). + * + * Module: library/hkdf.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the Hashed Message Authentication Code + * (HMAC)-based key derivation function (HKDF). + */ +#define MBEDTLS_HKDF_C + /** * \def MBEDTLS_HMAC_DRBG_C * @@ -2068,6 +2391,19 @@ */ #define MBEDTLS_HMAC_DRBG_C +/** + * \def MBEDTLS_NIST_KW_C + * + * Enable the Key Wrapping mode for 128-bit block ciphers, + * as defined in NIST SP 800-38F. Only KW and KWP modes + * are supported. At the moment, only AES is approved by NIST. + * + * Module: library/nist_kw.c + * + * Requires: MBEDTLS_AES_C and MBEDTLS_CIPHER_C + */ +//#define MBEDTLS_NIST_KW_C + /** * \def MBEDTLS_MD_C * @@ -2351,6 +2687,16 @@ */ #define MBEDTLS_PLATFORM_C +/** + * \def MBEDTLS_POLY1305_C + * + * Enable the Poly1305 MAC algorithm. + * + * Module: library/poly1305.c + * Caller: library/chachapoly.c + */ +#define MBEDTLS_POLY1305_C + /** * \def MBEDTLS_RIPEMD160_C * @@ -2734,7 +3080,7 @@ //#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ //#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ -/* Note: your snprintf must correclty zero-terminate the buffer! */ +/* Note: your snprintf must correctly zero-terminate the buffer! */ //#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ @@ -2751,17 +3097,145 @@ //#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ //#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ //#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ -/* Note: your snprintf must correclty zero-terminate the buffer! */ +/* Note: your snprintf must correctly zero-terminate the buffer! */ //#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ //#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ //#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +/** + * \brief This macro is invoked by the library when an invalid parameter + * is detected that is only checked with #MBEDTLS_CHECK_PARAMS + * (see the documentation of that option for context). + * + * When you leave this undefined here, the library provides + * a default definition. If the macro #MBEDTLS_CHECK_PARAMS_ASSERT + * is defined, the default definition is `assert(cond)`, + * otherwise the default definition calls a function + * mbedtls_param_failed(). This function is declared in + * `platform_util.h` for the benefit of the library, but + * you need to define in your application. + * + * When you define this here, this replaces the default + * definition in platform_util.h (which no longer declares the + * function mbedtls_param_failed()) and it is your responsibility + * to make sure this macro expands to something suitable (in + * particular, that all the necessary declarations are visible + * from within the library - you can ensure that by providing + * them in this file next to the macro definition). + * If you define this macro to call `assert`, also define + * #MBEDTLS_CHECK_PARAMS_ASSERT so that library source files + * include ``. + * + * Note that you may define this macro to expand to nothing, in + * which case you don't have to worry about declarations or + * definitions. However, you will then be notified about invalid + * parameters only in non-void functions, and void function will + * just silently return early on invalid parameters, which + * partially negates the benefits of enabling + * #MBEDTLS_CHECK_PARAMS in the first place, so is discouraged. + * + * \param cond The expression that should evaluate to true, but doesn't. + */ +//#define MBEDTLS_PARAM_FAILED( cond ) assert( cond ) + /* SSL Cache options */ //#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ //#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ /* SSL options */ -//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ + +/** \def MBEDTLS_SSL_MAX_CONTENT_LEN + * + * Maximum length (in bytes) of incoming and outgoing plaintext fragments. + * + * This determines the size of both the incoming and outgoing TLS I/O buffers + * in such a way that both are capable of holding the specified amount of + * plaintext data, regardless of the protection mechanism used. + * + * To configure incoming and outgoing I/O buffers separately, use + * #MBEDTLS_SSL_IN_CONTENT_LEN and #MBEDTLS_SSL_OUT_CONTENT_LEN, + * which overwrite the value set by this option. + * + * \note When using a value less than the default of 16KB on the client, it is + * recommended to use the Maximum Fragment Length (MFL) extension to + * inform the server about this limitation. On the server, there + * is no supported, standardized way of informing the client about + * restriction on the maximum size of incoming messages, and unless + * the limitation has been communicated by other means, it is recommended + * to only change the outgoing buffer size #MBEDTLS_SSL_OUT_CONTENT_LEN + * while keeping the default value of 16KB for the incoming buffer. + * + * Uncomment to set the maximum plaintext size of both + * incoming and outgoing I/O buffers. + */ +//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_IN_CONTENT_LEN + * + * Maximum length (in bytes) of incoming plaintext fragments. + * + * This determines the size of the incoming TLS I/O buffer in such a way + * that it is capable of holding the specified amount of plaintext data, + * regardless of the protection mechanism used. + * + * If this option is undefined, it inherits its value from + * #MBEDTLS_SSL_MAX_CONTENT_LEN. + * + * \note When using a value less than the default of 16KB on the client, it is + * recommended to use the Maximum Fragment Length (MFL) extension to + * inform the server about this limitation. On the server, there + * is no supported, standardized way of informing the client about + * restriction on the maximum size of incoming messages, and unless + * the limitation has been communicated by other means, it is recommended + * to only change the outgoing buffer size #MBEDTLS_SSL_OUT_CONTENT_LEN + * while keeping the default value of 16KB for the incoming buffer. + * + * Uncomment to set the maximum plaintext size of the incoming I/O buffer + * independently of the outgoing I/O buffer. + */ +//#define MBEDTLS_SSL_IN_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_OUT_CONTENT_LEN + * + * Maximum length (in bytes) of outgoing plaintext fragments. + * + * This determines the size of the outgoing TLS I/O buffer in such a way + * that it is capable of holding the specified amount of plaintext data, + * regardless of the protection mechanism used. + * + * If this option undefined, it inherits its value from + * #MBEDTLS_SSL_MAX_CONTENT_LEN. + * + * It is possible to save RAM by setting a smaller outward buffer, while keeping + * the default inward 16384 byte buffer to conform to the TLS specification. + * + * The minimum required outward buffer size is determined by the handshake + * protocol's usage. Handshaking will fail if the outward buffer is too small. + * The specific size requirement depends on the configured ciphers and any + * certificate data which is sent during the handshake. + * + * Uncomment to set the maximum plaintext size of the outgoing I/O buffer + * independently of the incoming I/O buffer. + */ +//#define MBEDTLS_SSL_OUT_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_DTLS_MAX_BUFFERING + * + * Maximum number of heap-allocated bytes for the purpose of + * DTLS handshake message reassembly and future message buffering. + * + * This should be at least 9/8 * MBEDTLSSL_IN_CONTENT_LEN + * to account for a reassembled handshake message of maximum size, + * together with its reassembly bitmap. + * + * A value of 2 * MBEDTLS_SSL_IN_CONTENT_LEN (32768 by default) + * should be sufficient for all practical situations as it allows + * to reassembly a large handshake message (such as a certificate) + * while buffering multiple smaller handshake messages. + * + */ +//#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 + //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ //#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ //#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ @@ -2815,25 +3289,53 @@ */ #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE -/* \} name SECTION: Customisation configuration options */ - -/* Target and application specific configurations */ -//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "target_config.h" +/** + * Uncomment the macro to let mbed TLS use your alternate implementation of + * mbedtls_platform_zeroize(). This replaces the default implementation in + * platform_util.c. + * + * mbedtls_platform_zeroize() is a widely used function across the library to + * zero a block of memory. The implementation is expected to be secure in the + * sense that it has been written to prevent the compiler from removing calls + * to mbedtls_platform_zeroize() as part of redundant code elimination + * optimizations. However, it is difficult to guarantee that calls to + * mbedtls_platform_zeroize() will not be optimized by the compiler as older + * versions of the C language standards do not provide a secure implementation + * of memset(). Therefore, MBEDTLS_PLATFORM_ZEROIZE_ALT enables users to + * configure their own implementation of mbedtls_platform_zeroize(), for + * example by using directives specific to their compiler, features from newer + * C standards (e.g using memset_s() in C11) or calling a secure memset() from + * their system (e.g explicit_bzero() in BSD). + */ +//#define MBEDTLS_PLATFORM_ZEROIZE_ALT + +/** + * Uncomment the macro to let Mbed TLS use your alternate implementation of + * mbedtls_platform_gmtime_r(). This replaces the default implementation in + * platform_util.c. + * + * gmtime() is not a thread-safe function as defined in the C standard. The + * library will try to use safer implementations of this function, such as + * gmtime_r() when available. However, if Mbed TLS cannot identify the target + * system, the implementation of mbedtls_platform_gmtime_r() will default to + * using the standard gmtime(). In this case, calls from the library to + * gmtime() will be guarded by the global mutex mbedtls_threading_gmtime_mutex + * if MBEDTLS_THREADING_C is enabled. We recommend that calls from outside the + * library are also guarded with this mutex to avoid race conditions. However, + * if the macro MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, Mbed TLS will + * unconditionally use the implementation for mbedtls_platform_gmtime_r() + * supplied at compile time. + */ +//#define MBEDTLS_PLATFORM_GMTIME_R_ALT -#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE) -#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE -#endif +/* \} name SECTION: Customisation configuration options */ -/* +/* Target and application specific configurations + * * Allow user to override any previous default. * - * Use two macro names for that, as: - * - with yotta the prefix YOTTA_CFG_ is forced - * - without yotta is looks weird to have a YOTTA prefix. */ -#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE) -#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE -#elif defined(MBEDTLS_USER_CONFIG_FILE) +#if defined(MBEDTLS_USER_CONFIG_FILE) #include MBEDTLS_USER_CONFIG_FILE #endif diff --git a/app/include/mbedtls/ctr_drbg.h b/app/include/mbedtls/ctr_drbg.h index 5a32843152..e0b5ed9c93 100644 --- a/app/include/mbedtls/ctr_drbg.h +++ b/app/include/mbedtls/ctr_drbg.h @@ -1,13 +1,44 @@ /** * \file ctr_drbg.h * - * \brief CTR_DRBG is based on AES-256, as defined in NIST SP 800-90A: - * Recommendation for Random Number Generation Using Deterministic - * Random Bit Generators. - * + * \brief This file contains definitions and functions for the + * CTR_DRBG pseudorandom generator. + * + * CTR_DRBG is a standardized way of building a PRNG from a block-cipher + * in counter mode operation, as defined in NIST SP 800-90A: + * Recommendation for Random Number Generation Using Deterministic Random + * Bit Generators. + * + * The Mbed TLS implementation of CTR_DRBG uses AES-256 (default) or AES-128 + * (if \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled at compile time) + * as the underlying block cipher, with a derivation function. + * The initial seeding grabs #MBEDTLS_CTR_DRBG_ENTROPY_LEN bytes of entropy. + * See the documentation of mbedtls_ctr_drbg_seed() for more details. + * + * Based on NIST SP 800-90A §10.2.1 table 3 and NIST SP 800-57 part 1 table 2, + * here are the security strengths achieved in typical configuration: + * - 256 bits under the default configuration of the library, with AES-256 + * and with #MBEDTLS_CTR_DRBG_ENTROPY_LEN set to 48 or more. + * - 256 bits if AES-256 is used, #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set + * to 32 or more, and the DRBG is initialized with an explicit + * nonce in the \c custom parameter to mbedtls_ctr_drbg_seed(). + * - 128 bits if AES-256 is used but #MBEDTLS_CTR_DRBG_ENTROPY_LEN is + * between 24 and 47 and the DRBG is not initialized with an explicit + * nonce (see mbedtls_ctr_drbg_seed()). + * - 128 bits if AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY enabled) + * and #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set to 24 or more (which is + * always the case unless it is explicitly set to a different value + * in config.h). + * + * Note that the value of #MBEDTLS_CTR_DRBG_ENTROPY_LEN defaults to: + * - \c 48 if the module \c MBEDTLS_SHA512_C is enabled and the symbol + * \c MBEDTLS_ENTROPY_FORCE_SHA256 is disabled at compile time. + * This is the default configuration of the library. + * - \c 32 if the module \c MBEDTLS_SHA512_C is disabled at compile time. + * - \c 32 if \c MBEDTLS_ENTROPY_FORCE_SHA256 is enabled at compile time. */ /* - * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * Copyright (C) 2006-2019, Arm Limited (or its affiliates), All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -46,7 +77,23 @@ #define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read or write error in file. */ #define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< The block size used by the cipher. */ -#define MBEDTLS_CTR_DRBG_KEYSIZE 32 /**< The key size used by the cipher. */ + +#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) +#define MBEDTLS_CTR_DRBG_KEYSIZE 16 +/**< The key size in bytes used by the cipher. + * + * Compile-time choice: 16 bytes (128 bits) + * because #MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled. + */ +#else +#define MBEDTLS_CTR_DRBG_KEYSIZE 32 +/**< The key size in bytes used by the cipher. + * + * Compile-time choice: 32 bytes (256 bits) + * because \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is disabled. + */ +#endif + #define MBEDTLS_CTR_DRBG_KEYBITS ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) /**< The key size for the DRBG operation, in bits. */ #define MBEDTLS_CTR_DRBG_SEEDLEN ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) /**< The seed length, calculated as (counter + AES key). */ @@ -59,21 +106,31 @@ * \{ */ +/** \def MBEDTLS_CTR_DRBG_ENTROPY_LEN + * + * \brief The amount of entropy used per seed by default, in bytes. + */ #if !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +/** This is 48 bytes because the entropy module uses SHA-512 + * (\c MBEDTLS_ENTROPY_FORCE_SHA256 is disabled). + */ #define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 -/**< The amount of entropy used per seed by default: - *
  • 48 with SHA-512.
  • - *
  • 32 with SHA-256.
+ +#else /* defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) */ + +/** This is 32 bytes because the entropy module uses SHA-256 + * (the SHA512 module is disabled or + * \c MBEDTLS_ENTROPY_FORCE_SHA256 is enabled). */ -#else -#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32 -/**< Amount of entropy used per seed by default: - *
  • 48 with SHA-512.
  • - *
  • 32 with SHA-256.
+#if !defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) +/** \warning To achieve a 256-bit security strength, you must pass a nonce + * to mbedtls_ctr_drbg_seed(). */ -#endif -#endif +#endif /* !defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) */ +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32 +#endif /* defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) */ +#endif /* !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) */ #if !defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL) #define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 @@ -92,7 +149,7 @@ #if !defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) #define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 -/**< The maximum size of seed or reseed buffer. */ +/**< The maximum size of seed or reseed buffer in bytes. */ #endif /* \} name SECTION: Module settings */ @@ -109,7 +166,7 @@ extern "C" { /** * \brief The CTR_DRBG context structure. */ -typedef struct +typedef struct mbedtls_ctr_drbg_context { unsigned char counter[16]; /*!< The counter (V). */ int reseed_counter; /*!< The reseed counter. */ @@ -150,20 +207,71 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ); * \brief This function seeds and sets up the CTR_DRBG * entropy source for future reseeds. * - * \note Personalization data can be provided in addition to the more generic - * entropy source, to make this instantiation as unique as possible. - * + * A typical choice for the \p f_entropy and \p p_entropy parameters is + * to use the entropy module: + * - \p f_entropy is mbedtls_entropy_func(); + * - \p p_entropy is an instance of ::mbedtls_entropy_context initialized + * with mbedtls_entropy_init() (which registers the platform's default + * entropy sources). + * + * The entropy length is #MBEDTLS_CTR_DRBG_ENTROPY_LEN by default. + * You can override it by calling mbedtls_ctr_drbg_set_entropy_len(). + * + * You can provide a personalization string in addition to the + * entropy source, to make this instantiation as unique as possible. + * + * \note The _seed_material_ value passed to the derivation + * function in the CTR_DRBG Instantiate Process + * described in NIST SP 800-90A §10.2.1.3.2 + * is the concatenation of the string obtained from + * calling \p f_entropy and the \p custom string. + * The origin of the nonce depends on the value of + * the entropy length relative to the security strength. + * - If the entropy length is at least 1.5 times the + * security strength then the nonce is taken from the + * string obtained with \p f_entropy. + * - If the entropy length is less than the security + * strength, then the nonce is taken from \p custom. + * In this case, for compliance with SP 800-90A, + * you must pass a unique value of \p custom at + * each invocation. See SP 800-90A §8.6.7 for more + * details. + */ +#if MBEDTLS_CTR_DRBG_ENTROPY_LEN < MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2 +/** \warning When #MBEDTLS_CTR_DRBG_ENTROPY_LEN is less than + * #MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2, to achieve the + * maximum security strength permitted by CTR_DRBG, + * you must pass a value of \p custom that is a nonce: + * this value must never be repeated in subsequent + * runs of the same application or on a different + * device. + */ +#endif +/** * \param ctx The CTR_DRBG context to seed. + * It must have been initialized with + * mbedtls_ctr_drbg_init(). + * After a successful call to mbedtls_ctr_drbg_seed(), + * you may not call mbedtls_ctr_drbg_seed() again on + * the same context unless you call + * mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init() + * again first. * \param f_entropy The entropy callback, taking as arguments the * \p p_entropy context, the buffer to fill, and the - length of the buffer. - * \param p_entropy The entropy context. - * \param custom Personalization data, that is device-specific - identifiers. Can be NULL. - * \param len The length of the personalization data. - * - * \return \c 0 on success, or - * #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + * length of the buffer. + * \p f_entropy is always called with a buffer size + * equal to the entropy length. + * \param p_entropy The entropy context to pass to \p f_entropy. + * \param custom The personalization string. + * This can be \c NULL, in which case the personalization + * string is empty regardless of the value of \p len. + * \param len The length of the personalization string. + * This must be at most + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + * - #MBEDTLS_CTR_DRBG_ENTROPY_LEN. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. */ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, int (*f_entropy)(void *, unsigned char *, size_t), @@ -183,7 +291,8 @@ void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ); * The default value is off. * * \note If enabled, entropy is gathered at the beginning of - * every call to mbedtls_ctr_drbg_random_with_add(). + * every call to mbedtls_ctr_drbg_random_with_add() + * or mbedtls_ctr_drbg_random(). * Only use this if your entropy source has sufficient * throughput. * @@ -195,18 +304,37 @@ void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, /** * \brief This function sets the amount of entropy grabbed on each - * seed or reseed. The default value is - * #MBEDTLS_CTR_DRBG_ENTROPY_LEN. + * seed or reseed. + * + * The default value is #MBEDTLS_CTR_DRBG_ENTROPY_LEN. + * + * \note The security strength of CTR_DRBG is bounded by the + * entropy length. Thus: + * - When using AES-256 + * (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is disabled, + * which is the default), + * \p len must be at least 32 (in bytes) + * to achieve a 256-bit strength. + * - When using AES-128 + * (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled) + * \p len must be at least 16 (in bytes) + * to achieve a 128-bit strength. * * \param ctx The CTR_DRBG context. - * \param len The amount of entropy to grab. + * \param len The amount of entropy to grab, in bytes. + * This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. */ void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, size_t len ); /** * \brief This function sets the reseed interval. - * The default value is #MBEDTLS_CTR_DRBG_RESEED_INTERVAL. + * + * The reseed interval is the number of calls to mbedtls_ctr_drbg_random() + * or mbedtls_ctr_drbg_random_with_add() after which the entropy function + * is called again. + * + * The default value is #MBEDTLS_CTR_DRBG_RESEED_INTERVAL. * * \param ctx The CTR_DRBG context. * \param interval The reseed interval. @@ -219,67 +347,62 @@ void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, * extracts data from the entropy source. * * \param ctx The CTR_DRBG context. - * \param additional Additional data to add to the state. Can be NULL. + * \param additional Additional data to add to the state. Can be \c NULL. * \param len The length of the additional data. + * This must be less than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - \c entropy_len + * where \c entropy_len is the entropy length + * configured for the context. * - * \return \c 0 on success, or - * #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. */ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, const unsigned char *additional, size_t len ); /** - * \brief This function updates the state of the CTR_DRBG context. - * - * \param ctx The CTR_DRBG context. - * \param additional The data to update the state with. - * \param add_len Length of \p additional in bytes. This must be at - * most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. - * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if - * \p add_len is more than - * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. - * \return An error from the underlying AES cipher on failure. + * \brief This function updates the state of the CTR_DRBG context. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. This must not be + * \c NULL unless \p add_len is \c 0. + * \param add_len Length of \p additional in bytes. This must be at + * most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if + * \p add_len is more than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * \return An error from the underlying AES cipher on failure. */ int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, const unsigned char *additional, size_t add_len ); -/** - * \brief This function updates the state of the CTR_DRBG context. - * - * \warning This function cannot report errors. You should use - * mbedtls_ctr_drbg_update_ret() instead. - * - * \note If \p add_len is greater than - * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first - * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. - * The remaining Bytes are silently discarded. - * - * \param ctx The CTR_DRBG context. - * \param additional The data to update the state with. - * \param add_len Length of \p additional data. - */ -void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, - const unsigned char *additional, - size_t add_len ); - /** * \brief This function updates a CTR_DRBG instance with additional * data and uses it to generate random data. * - * \note The function automatically reseeds if the reseed counter is exceeded. + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. * * \param p_rng The CTR_DRBG context. This must be a pointer to a * #mbedtls_ctr_drbg_context structure. * \param output The buffer to fill. - * \param output_len The length of the buffer. - * \param additional Additional data to update. Can be NULL. - * \param add_len The length of the additional data. - * - * \return \c 0 on success, or - * #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * \param output_len The length of the buffer in bytes. + * \param additional Additional data to update. Can be \c NULL, in which + * case the additional data is empty regardless of + * the value of \p add_len. + * \param add_len The length of the additional data + * if \p additional is not \c NULL. + * This must be less than #MBEDTLS_CTR_DRBG_MAX_INPUT + * and less than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - \c entropy_len + * where \c entropy_len is the entropy length + * configured for the context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. */ int mbedtls_ctr_drbg_random_with_add( void *p_rng, @@ -289,20 +412,51 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, /** * \brief This function uses CTR_DRBG to generate random data. * - * \note The function automatically reseeds if the reseed counter is exceeded. + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. + * * * \param p_rng The CTR_DRBG context. This must be a pointer to a * #mbedtls_ctr_drbg_context structure. * \param output The buffer to fill. - * \param output_len The length of the buffer. + * \param output_len The length of the buffer in bytes. * - * \return \c 0 on success, or - * #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. */ int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function updates the state of the CTR_DRBG context. + * + * \deprecated Superseded by mbedtls_ctr_drbg_update_ret() + * in 2.16.0. + * + * \note If \p add_len is greater than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. + * The remaining Bytes are silently discarded. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. + * \param add_len Length of \p additional data. + */ +MBEDTLS_DEPRECATED void mbedtls_ctr_drbg_update( + mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + #if defined(MBEDTLS_FS_IO) /** * \brief This function writes a seed file. @@ -310,9 +464,9 @@ int mbedtls_ctr_drbg_random( void *p_rng, * \param ctx The CTR_DRBG context. * \param path The name of the file. * - * \return \c 0 on success, - * #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, or - * #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on reseed * failure. */ int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); @@ -324,21 +478,28 @@ int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char * \param ctx The CTR_DRBG context. * \param path The name of the file. * - * \return \c 0 on success, - * #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, - * #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or - * #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG on failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on + * reseed failure. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if the existing + * seed file is too large. */ int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); #endif /* MBEDTLS_FS_IO */ +#if defined(MBEDTLS_SELF_TEST) + /** * \brief The CTR_DRBG checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_ctr_drbg_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + /* Internal functions (do not call directly) */ int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *, int (*)(void *, unsigned char *, size_t), void *, diff --git a/app/include/mbedtls/debug.h b/app/include/mbedtls/debug.h index ef8db67ff1..736444bb76 100644 --- a/app/include/mbedtls/debug.h +++ b/app/include/mbedtls/debug.h @@ -65,6 +65,11 @@ mbedtls_debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ) #endif +#if defined(MBEDTLS_ECDH_C) +#define MBEDTLS_SSL_DEBUG_ECDH( level, ecdh, attr ) \ + mbedtls_debug_printf_ecdh( ssl, level, __FILE__, __LINE__, ecdh, attr ) +#endif + #else /* MBEDTLS_DEBUG_C */ #define MBEDTLS_SSL_DEBUG_MSG( level, args ) do { } while( 0 ) @@ -73,6 +78,7 @@ #define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) #define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) do { } while( 0 ) #define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_ECDH( level, ecdh, attr ) do { } while( 0 ) #endif /* MBEDTLS_DEBUG_C */ @@ -221,6 +227,36 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, const char *text, const mbedtls_x509_crt *crt ); #endif +#if defined(MBEDTLS_ECDH_C) +typedef enum +{ + MBEDTLS_DEBUG_ECDH_Q, + MBEDTLS_DEBUG_ECDH_QP, + MBEDTLS_DEBUG_ECDH_Z, +} mbedtls_debug_ecdh_attr; + +/** + * \brief Print a field of the ECDH structure in the SSL context to the debug + * output. This function is always used through the + * MBEDTLS_SSL_DEBUG_ECDH() macro, which supplies the ssl context, file + * and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param ecdh the ECDH context + * \param attr the identifier of the attribute being output + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_printf_ecdh( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ); +#endif + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/des.h b/app/include/mbedtls/des.h index 5a1a636522..54e6b7894b 100644 --- a/app/include/mbedtls/des.h +++ b/app/include/mbedtls/des.h @@ -42,18 +42,20 @@ #define MBEDTLS_DES_DECRYPT 0 #define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +/* MBEDTLS_ERR_DES_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_DES_HW_ACCEL_FAILED -0x0033 /**< DES hardware accelerator failed. */ #define MBEDTLS_DES_KEY_SIZE 8 -#if !defined(MBEDTLS_DES_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_DES_ALT) +// Regular implementation +// + /** * \brief DES context structure * @@ -61,7 +63,7 @@ extern "C" { * security risk. We recommend considering stronger ciphers * instead. */ -typedef struct +typedef struct mbedtls_des_context { uint32_t sk[32]; /*!< DES subkeys */ } @@ -70,12 +72,16 @@ mbedtls_des_context; /** * \brief Triple-DES context structure */ -typedef struct +typedef struct mbedtls_des3_context { uint32_t sk[96]; /*!< 3DES subkeys */ } mbedtls_des3_context; +#else /* MBEDTLS_DES_ALT */ +#include "des_alt.h" +#endif /* MBEDTLS_DES_ALT */ + /** * \brief Initialize DES context * @@ -331,17 +337,8 @@ int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, */ void mbedtls_des_setkey( uint32_t SK[32], const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_DES_ALT */ -#include "des_alt.h" -#endif /* MBEDTLS_DES_ALT */ -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief Checkup routine @@ -350,6 +347,8 @@ extern "C" { */ int mbedtls_des_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/dhm.h b/app/include/mbedtls/dhm.h index 00fafd8d16..2909f5fbc8 100644 --- a/app/include/mbedtls/dhm.h +++ b/app/include/mbedtls/dhm.h @@ -1,7 +1,13 @@ /** * \file dhm.h * - * \brief Diffie-Hellman-Merkle key exchange. + * \brief This file contains Diffie-Hellman-Merkle (DHM) key exchange + * definitions and functions. + * + * Diffie-Hellman-Merkle (DHM) key exchange is defined in + * RFC-2631: Diffie-Hellman Key Agreement Method and + * Public-Key Cryptography Standards (PKCS) #3: Diffie + * Hellman Key Agreement Standard. * * RFC-3526: More Modular Exponential (MODP) Diffie-Hellman groups for * Internet Key Exchange (IKE) defines a number of standardized @@ -65,7 +71,6 @@ #include MBEDTLS_CONFIG_FILE #endif #include "bignum.h" -#if !defined(MBEDTLS_DHM_ALT) /* * DHM Error codes @@ -79,17 +84,22 @@ #define MBEDTLS_ERR_DHM_INVALID_FORMAT -0x3380 /**< The ASN.1 data is not formatted correctly. */ #define MBEDTLS_ERR_DHM_ALLOC_FAILED -0x3400 /**< Allocation of memory failed. */ #define MBEDTLS_ERR_DHM_FILE_IO_ERROR -0x3480 /**< Read or write of file failed. */ + +/* MBEDTLS_ERR_DHM_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_DHM_HW_ACCEL_FAILED -0x3500 /**< DHM hardware accelerator failed. */ + #define MBEDTLS_ERR_DHM_SET_GROUP_FAILED -0x3580 /**< Setting the modulus and generator failed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_DHM_ALT) + /** * \brief The DHM context structure. */ -typedef struct +typedef struct mbedtls_dhm_context { size_t len; /*!< The size of \p P in Bytes. */ mbedtls_mpi P; /*!< The prime modulus. */ @@ -105,6 +115,10 @@ typedef struct } mbedtls_dhm_context; +#else /* MBEDTLS_DHM_ALT */ +#include "dhm_alt.h" +#endif /* MBEDTLS_DHM_ALT */ + /** * \brief This function initializes the DHM context. * @@ -113,9 +127,15 @@ mbedtls_dhm_context; void mbedtls_dhm_init( mbedtls_dhm_context *ctx ); /** - * \brief This function parses the ServerKeyExchange parameters. + * \brief This function parses the DHM parameters in a + * TLS ServerKeyExchange handshake message + * (DHM modulus, generator, and public key). + * + * \note In a TLS handshake, this is the how the client + * sets up its DHM context from the server's public + * DHM key material. * - * \param ctx The DHM context. + * \param ctx The DHM context to use. This must be initialized. * \param p On input, *p must be the start of the input buffer. * On output, *p is updated to point to the end of the data * that has been read. On success, this is the first byte @@ -125,38 +145,44 @@ void mbedtls_dhm_init( mbedtls_dhm_context *ctx ); * failures. * \param end The end of the input buffer. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_DHM_XXX error code - * on failure. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. */ int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, - unsigned char **p, - const unsigned char *end ); + unsigned char **p, + const unsigned char *end ); /** - * \brief This function sets up and writes the ServerKeyExchange - * parameters. - * - * \param ctx The DHM context. - * \param x_size The private value size in Bytes. - * \param olen The number of characters written. - * \param output The destination buffer. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. - * - * \note The destination buffer must be large enough to hold - * the reduced binary presentation of the modulus, the generator - * and the public key, each wrapped with a 2-byte length field. - * It is the responsibility of the caller to ensure that enough - * space is available. Refer to \c mbedtls_mpi_size to computing - * the byte-size of an MPI. + * \brief This function generates a DHM key pair and exports its + * public part together with the DHM parameters in the format + * used in a TLS ServerKeyExchange handshake message. * - * \note This function assumes that \c ctx->P and \c ctx->G - * have already been properly set. For that, use + * \note This function assumes that the DHM parameters \c ctx->P + * and \c ctx->G have already been properly set. For that, use * mbedtls_dhm_set_group() below in conjunction with * mbedtls_mpi_read_binary() and mbedtls_mpi_read_string(). * - * \return \c 0 on success, or an \c MBEDTLS_ERR_DHM_XXX error code - * on failure. + * \note In a TLS handshake, this is the how the server generates + * and exports its DHM key material. + * + * \param ctx The DHM context to use. This must be initialized + * and have the DHM parameters set. It may or may not + * already have imported the peer's public key. + * \param x_size The private key size in Bytes. + * \param olen The address at which to store the number of Bytes + * written on success. This must not be \c NULL. + * \param output The destination buffer. This must be a writable buffer of + * sufficient size to hold the reduced binary presentation of + * the modulus, the generator and the public key, each wrapped + * with a 2-byte length field. It is the responsibility of the + * caller to ensure that enough space is available. Refer to + * mbedtls_mpi_size() to computing the byte-size of an MPI. + * \param f_rng The RNG function. Must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. */ int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t *olen, @@ -164,54 +190,66 @@ int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, void *p_rng ); /** - * \brief Set prime modulus and generator + * \brief This function sets the prime modulus and generator. * - * \param ctx The DHM context. - * \param P The MPI holding DHM prime modulus. - * \param G The MPI holding DHM generator. + * \note This function can be used to set \c ctx->P, \c ctx->G + * in preparation for mbedtls_dhm_make_params(). * - * \note This function can be used to set P, G - * in preparation for \c mbedtls_dhm_make_params. + * \param ctx The DHM context to configure. This must be initialized. + * \param P The MPI holding the DHM prime modulus. This must be + * an initialized MPI. + * \param G The MPI holding the DHM generator. This must be an + * initialized MPI. * - * \return \c 0 if successful, or an \c MBEDTLS_ERR_DHM_XXX error code - * on failure. + * \return \c 0 if successful. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. */ int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx, const mbedtls_mpi *P, const mbedtls_mpi *G ); /** - * \brief This function imports the public value G^Y of the peer. + * \brief This function imports the raw public value of the peer. * - * \param ctx The DHM context. - * \param input The input buffer. - * \param ilen The size of the input buffer. + * \note In a TLS handshake, this is the how the server imports + * the Client's public DHM key. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_DHM_XXX error code - * on failure. + * \param ctx The DHM context to use. This must be initialized and have + * its DHM parameters set, e.g. via mbedtls_dhm_set_group(). + * It may or may not already have generated its own private key. + * \param input The input buffer containing the \c G^Y value of the peer. + * This must be a readable buffer of size \p ilen Bytes. + * \param ilen The size of the input buffer \p input in Bytes. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. */ int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, const unsigned char *input, size_t ilen ); /** - * \brief This function creates its own private value \c X and - * exports \c G^X. + * \brief This function creates a DHM key pair and exports + * the raw public key in big-endian format. * - * \param ctx The DHM context. - * \param x_size The private value size in Bytes. - * \param output The destination buffer. - * \param olen The length of the destination buffer. Must be at least - equal to ctx->len (the size of \c P). - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. + * \note The destination buffer is always fully written + * so as to contain a big-endian representation of G^X mod P. + * If it is larger than \c ctx->len, it is padded accordingly + * with zero-bytes at the beginning. * - * \note The destination buffer will always be fully written - * so as to contain a big-endian presentation of G^X mod P. - * If it is larger than ctx->len, it will accordingly be - * padded with zero-bytes in the beginning. + * \param ctx The DHM context to use. This must be initialized and + * have the DHM parameters set. It may or may not already + * have imported the peer's public key. + * \param x_size The private key size in Bytes. + * \param output The destination buffer. This must be a writable buffer of + * size \p olen Bytes. + * \param olen The length of the destination buffer. This must be at least + * equal to `ctx->len` (the size of \c P). + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context argument. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_DHM_XXX error code - * on failure. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. */ int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t olen, @@ -219,25 +257,30 @@ int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, void *p_rng ); /** - * \brief This function derives and exports the shared secret - * \c (G^Y)^X mod \c P. + * \brief This function derives and exports the shared secret + * \c (G^Y)^X mod \c P. * - * \param ctx The DHM context. - * \param output The destination buffer. - * \param output_size The size of the destination buffer. Must be at least - * the size of ctx->len. - * \param olen On exit, holds the actual number of Bytes written. - * \param f_rng The RNG function, for blinding purposes. - * \param p_rng The RNG parameter. + * \note If \p f_rng is not \c NULL, it is used to blind the input as + * a countermeasure against timing attacks. Blinding is used + * only if our private key \c X is re-used, and not used + * otherwise. We recommend always passing a non-NULL + * \p f_rng argument. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_DHM_XXX error code - * on failure. + * \param ctx The DHM context to use. This must be initialized + * and have its own private key generated and the peer's + * public key imported. + * \param output The buffer to write the generated shared key to. This + * must be a writable buffer of size \p output_size Bytes. + * \param output_size The size of the destination buffer. This must be at + * least the size of \c ctx->len (the size of \c P). + * \param olen On exit, holds the actual number of Bytes written. + * \param f_rng The RNG function, for blinding purposes. This may + * b \c NULL if blinding isn't needed. + * \param p_rng The RNG context. This may be \c NULL if \p f_rng + * doesn't need a context argument. * - * \note If non-NULL, \p f_rng is used to blind the input as - * a countermeasure against timing attacks. Blinding is used - * only if our secret value \p X is re-used and omitted - * otherwise. Therefore, we recommend always passing a - * non-NULL \p f_rng argument. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. */ int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, unsigned char *output, size_t output_size, size_t *olen, @@ -245,9 +288,12 @@ int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, void *p_rng ); /** - * \brief This function frees and clears the components of a DHM key. + * \brief This function frees and clears the components + * of a DHM context. * - * \param ctx The DHM context to free and clear. + * \param ctx The DHM context to free and clear. This may be \c NULL, + * in which case this function is a no-op. If it is not \c NULL, + * it must point to an initialized DHM context. */ void mbedtls_dhm_free( mbedtls_dhm_context *ctx ); @@ -256,16 +302,19 @@ void mbedtls_dhm_free( mbedtls_dhm_context *ctx ); /** * \brief This function parses DHM parameters in PEM or DER format. * - * \param dhm The DHM context to initialize. - * \param dhmin The input buffer. - * \param dhminlen The size of the buffer, including the terminating null - * Byte for PEM data. + * \param dhm The DHM context to import the DHM parameters into. + * This must be initialized. + * \param dhmin The input buffer. This must be a readable buffer of + * length \p dhminlen Bytes. + * \param dhminlen The size of the input buffer \p dhmin, including the + * terminating \c NULL Byte for PEM data. * - * \return \c 0 on success, or a specific DHM or PEM error code - * on failure. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX error + * code on failure. */ int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, - size_t dhminlen ); + size_t dhminlen ); #if defined(MBEDTLS_FS_IO) /** \ingroup x509_module */ @@ -273,34 +322,29 @@ int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, * \brief This function loads and parses DHM parameters from a file. * * \param dhm The DHM context to load the parameters to. + * This must be initialized. * \param path The filename to read the DHM parameters from. + * This must not be \c NULL. * - * \return \c 0 on success, or a specific DHM or PEM error code - * on failure. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX + * error code on failure. */ int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ); #endif /* MBEDTLS_FS_IO */ #endif /* MBEDTLS_ASN1_PARSE_C */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_DHM_ALT */ -#include "dhm_alt.h" -#endif /* MBEDTLS_DHM_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief The DMH checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_dhm_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ #ifdef __cplusplus } #endif @@ -348,15 +392,6 @@ int mbedtls_dhm_self_test( int verbose ); #if !defined(MBEDTLS_DEPRECATED_REMOVED) -#if defined(MBEDTLS_DEPRECATED_WARNING) -#define MBEDTLS_DEPRECATED __attribute__((deprecated)) -MBEDTLS_DEPRECATED typedef char const * mbedtls_deprecated_constant_t; -#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL ) \ - ( (mbedtls_deprecated_constant_t) ( VAL ) ) -#else -#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL ) VAL -#endif /* ! MBEDTLS_DEPRECATED_WARNING */ - /** * \warning The origin of the primes in RFC 5114 is not documented and * their use therefore constitutes a security risk! diff --git a/app/include/mbedtls/ecdh.h b/app/include/mbedtls/ecdh.h index 99cfde00d0..4479a1d46f 100644 --- a/app/include/mbedtls/ecdh.h +++ b/app/include/mbedtls/ecdh.h @@ -1,10 +1,11 @@ /** * \file ecdh.h * - * \brief The Elliptic Curve Diffie-Hellman (ECDH) protocol APIs. + * \brief This file contains ECDH definitions and functions. * - * ECDH is an anonymous key agreement protocol allowing two parties to - * establish a shared secret over an insecure channel. Each party must have an + * The Elliptic Curve Diffie-Hellman (ECDH) protocol is an anonymous + * key agreement protocol allowing two parties to establish a shared + * secret over an insecure channel. Each party must have an * elliptic-curve public–private key pair. * * For more information, see NIST SP 800-56A Rev. 2: Recommendation for @@ -33,28 +34,82 @@ #ifndef MBEDTLS_ECDH_H #define MBEDTLS_ECDH_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "ecp.h" +/* + * Use a backward compatible ECDH context. + * + * This flag is always enabled for now and future versions might add a + * configuration option that conditionally undefines this flag. + * The configuration option in question may have a different name. + * + * Features undefining this flag, must have a warning in their description in + * config.h stating that the feature breaks backward compatibility. + */ +#define MBEDTLS_ECDH_LEGACY_CONTEXT + #ifdef __cplusplus extern "C" { #endif /** - * Defines the source of the imported EC key: - *
  • Our key.
  • - *
  • The key of the peer.
+ * Defines the source of the imported EC key. */ typedef enum { - MBEDTLS_ECDH_OURS, - MBEDTLS_ECDH_THEIRS, + MBEDTLS_ECDH_OURS, /**< Our key. */ + MBEDTLS_ECDH_THEIRS, /**< The key of the peer. */ } mbedtls_ecdh_side; +#if !defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +/** + * Defines the ECDH implementation used. + * + * Later versions of the library may add new variants, therefore users should + * not make any assumptions about them. + */ +typedef enum +{ + MBEDTLS_ECDH_VARIANT_NONE = 0, /*!< Implementation not defined. */ + MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0,/*!< The default Mbed TLS implementation */ +} mbedtls_ecdh_variant; + /** + * The context used by the default ECDH implementation. + * + * Later versions might change the structure of this context, therefore users + * should not make any assumptions about the structure of + * mbedtls_ecdh_context_mbed. + */ +typedef struct mbedtls_ecdh_context_mbed +{ + mbedtls_ecp_group grp; /*!< The elliptic curve used. */ + mbedtls_mpi d; /*!< The private key. */ + mbedtls_ecp_point Q; /*!< The public key. */ + mbedtls_ecp_point Qp; /*!< The value of the public key of the peer. */ + mbedtls_mpi z; /*!< The shared secret. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx rs; /*!< The restart context for EC computations. */ +#endif +} mbedtls_ecdh_context_mbed; +#endif + +/** + * + * \warning Performing multiple operations concurrently on the same + * ECDSA context is not supported; objects of this type + * should not be shared between multiple threads. * \brief The ECDH context structure. */ -typedef struct +typedef struct mbedtls_ecdh_context { +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) mbedtls_ecp_group grp; /*!< The elliptic curve used. */ mbedtls_mpi d; /*!< The private key. */ mbedtls_ecp_point Q; /*!< The public key. */ @@ -64,6 +119,29 @@ typedef struct mbedtls_ecp_point Vi; /*!< The blinding value. */ mbedtls_ecp_point Vf; /*!< The unblinding value. */ mbedtls_mpi _d; /*!< The previous \p d. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + int restart_enabled; /*!< The flag for restartable mode. */ + mbedtls_ecp_restart_ctx rs; /*!< The restart context for EC computations. */ +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#else + uint8_t point_format; /*!< The format of point export in TLS messages + as defined in RFC 4492. */ + mbedtls_ecp_group_id grp_id;/*!< The elliptic curve used. */ + mbedtls_ecdh_variant var; /*!< The ECDH implementation/structure used. */ + union + { + mbedtls_ecdh_context_mbed mbed_ecdh; + } ctx; /*!< Implementation-specific context. The + context in use is specified by the \c var + field. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + uint8_t restart_enabled; /*!< The flag for restartable mode. Functions of + an alternative implementation not supporting + restartable mode must return + MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED error + if this flag is set. */ +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */ } mbedtls_ecdh_context; @@ -75,16 +153,22 @@ mbedtls_ecdh_context; * implemented during the ECDH key exchange. The second core * computation is performed by mbedtls_ecdh_compute_shared(). * - * \param grp The ECP group. + * \see ecp.h + * + * \param grp The ECP group to use. This must be initialized and have + * domain parameters loaded, for example through + * mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). * \param d The destination MPI (private key). + * This must be initialized. * \param Q The destination point (public key). - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. + * This must be initialized. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX or + * \return \c 0 on success. + * \return Another \c MBEDTLS_ERR_ECP_XXX or * \c MBEDTLS_MPI_XXX error code on failure. - * - * \see ecp.h */ int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int (*f_rng)(void *, unsigned char *, size_t), @@ -97,21 +181,32 @@ int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp * implemented during the ECDH key exchange. The first core * computation is performed by mbedtls_ecdh_gen_public(). * - * \param grp The ECP group. + * \see ecp.h + * + * \note If \p f_rng is not NULL, it is used to implement + * countermeasures against side-channel attacks. + * For more information, see mbedtls_ecp_mul(). + * + * \param grp The ECP group to use. This must be initialized and have + * domain parameters loaded, for example through + * mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). * \param z The destination MPI (shared secret). + * This must be initialized. * \param Q The public key from another party. + * This must be initialized. * \param d Our secret exponent (private key). - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX or + * This must be initialized. + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results during the ECP computations is + * not needed (discouraged). See the documentation of + * mbedtls_ecp_mul() for more. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a + * context argument. + * + * \return \c 0 on success. + * \return Another \c MBEDTLS_ERR_ECP_XXX or * \c MBEDTLS_MPI_XXX error code on failure. - * - * \see ecp.h - * - * \note If \p f_rng is not NULL, it is used to implement - * countermeasures against potential elaborate timing - * attacks. For more information, see mbedtls_ecp_mul(). */ int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, @@ -121,39 +216,62 @@ int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, /** * \brief This function initializes an ECDH context. * - * \param ctx The ECDH context to initialize. + * \param ctx The ECDH context to initialize. This must not be \c NULL. */ void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ); /** - * \brief This function frees a context. + * \brief This function sets up the ECDH context with the information + * given. * - * \param ctx The context to free. - */ -void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ); - -/** - * \brief This function generates a public key and a TLS - * ServerKeyExchange payload. + * This function should be called after mbedtls_ecdh_init() but + * before mbedtls_ecdh_make_params(). There is no need to call + * this function before mbedtls_ecdh_read_params(). * * This is the first function used by a TLS server for ECDHE * ciphersuites. * - * \param ctx The ECDH context. - * \param olen The number of characters written. - * \param buf The destination buffer. - * \param blen The length of the destination buffer. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. + * \param ctx The ECDH context to set up. This must be initialized. + * \param grp_id The group id of the group to set up the context for. * - * \note This function assumes that the ECP group (grp) of the - * \p ctx context has already been properly set, - * for example, using mbedtls_ecp_group_load(). + * \return \c 0 on success. + */ +int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, + mbedtls_ecp_group_id grp_id ); + +/** + * \brief This function frees a context. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX error code - * on failure. + * \param ctx The context to free. This may be \c NULL, in which + * case this function does nothing. If it is not \c NULL, + * it must point to an initialized ECDH context. + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ); + +/** + * \brief This function generates an EC key pair and exports its + * in the format used in a TLS ServerKeyExchange handshake + * message. + * + * This is the second function used by a TLS server for ECDHE + * ciphersuites. (It is called after mbedtls_ecdh_setup().) * * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param olen The address at which to store the number of Bytes written. + * \param buf The destination buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. */ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, unsigned char *buf, size_t blen, @@ -161,23 +279,32 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, void *p_rng ); /** - * \brief This function parses and processes a TLS ServerKeyExhange - * payload. + * \brief This function parses the ECDHE parameters in a + * TLS ServerKeyExchange handshake message. * - * This is the first function used by a TLS client for ECDHE - * ciphersuites. + * \note In a TLS handshake, this is the how the client + * sets up its ECDHE context from the server's public + * ECDHE key material. + * + * \see ecp.h * - * \param ctx The ECDH context. - * \param buf The pointer to the start of the input buffer. - * \param end The address for one Byte past the end of the buffer. + * \param ctx The ECDHE context to use. This must be initialized. + * \param buf On input, \c *buf must be the start of the input buffer. + * On output, \c *buf is updated to point to the end of the + * data that has been read. On success, this is the first byte + * past the end of the ServerKeyExchange parameters. + * On error, this is the point at which an error has been + * detected, which is usually not useful except to debug + * failures. + * \param end The end of the input buffer. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX error code - * on failure. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. * - * \see ecp.h */ int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, - const unsigned char **buf, const unsigned char *end ); + const unsigned char **buf, + const unsigned char *end ); /** * \brief This function sets up an ECDH context from an EC key. @@ -186,38 +313,47 @@ int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, * ServerKeyEchange for static ECDH, and imports ECDH * parameters from the EC key information of a certificate. * - * \param ctx The ECDH context to set up. - * \param key The EC key to use. - * \param side Defines the source of the key: - *
  • 1: Our key.
  • -
  • 0: The key of the peer.
+ * \see ecp.h * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX error code - * on failure. + * \param ctx The ECDH context to set up. This must be initialized. + * \param key The EC key to use. This must be initialized. + * \param side Defines the source of the key. Possible values are: + * - #MBEDTLS_ECDH_OURS: The key is ours. + * - #MBEDTLS_ECDH_THEIRS: The key is that of the peer. + * + * \return \c 0 on success. + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. * - * \see ecp.h */ -int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, - mbedtls_ecdh_side side ); +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ); /** - * \brief This function generates a public key and a TLS - * ClientKeyExchange payload. + * \brief This function generates a public key and exports it + * as a TLS ClientKeyExchange payload. * * This is the second function used by a TLS client for ECDH(E) * ciphersuites. * - * \param ctx The ECDH context. - * \param olen The number of Bytes written. - * \param buf The destination buffer. - * \param blen The size of the destination buffer. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX error code - * on failure. - * * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, the latter usually by + * mbedtls_ecdh_read_params(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The destination buffer. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The size of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. */ int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, unsigned char *buf, size_t blen, @@ -225,23 +361,26 @@ int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, void *p_rng ); /** - * \brief This function parses and processes a TLS ClientKeyExchange - * payload. + * \brief This function parses and processes the ECDHE payload of a + * TLS ClientKeyExchange message. * - * This is the second function used by a TLS server for ECDH(E) - * ciphersuites. + * This is the third function used by a TLS server for ECDH(E) + * ciphersuites. (It is called after mbedtls_ecdh_setup() and + * mbedtls_ecdh_make_params().) * - * \param ctx The ECDH context. - * \param buf The start of the input buffer. - * \param blen The length of the input buffer. + * \see ecp.h * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX error code - * on failure. + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param buf The pointer to the ClientKeyExchange payload. This must + * be a readable buffer of length \p blen Bytes. + * \param blen The length of the input buffer \p buf in Bytes. * - * \see ecp.h + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. */ int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, - const unsigned char *buf, size_t blen ); + const unsigned char *buf, size_t blen ); /** * \brief This function derives and exports the shared secret. @@ -249,27 +388,51 @@ int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, * This is the last function used by both TLS client * and servers. * - * \param ctx The ECDH context. - * \param olen The number of Bytes written. - * \param buf The destination buffer. - * \param blen The length of the destination buffer. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX error code - * on failure. + * \note If \p f_rng is not NULL, it is used to implement + * countermeasures against side-channel attacks. + * For more information, see mbedtls_ecp_mul(). * * \see ecp.h - * - * \note If \p f_rng is not NULL, it is used to implement - * countermeasures against potential elaborate timing - * attacks. For more information, see mbedtls_ecp_mul(). + + * \param ctx The ECDH context to use. This must be initialized + * and have its own private key generated and the peer's + * public key imported. + * \param olen The address at which to store the total number of + * Bytes written on success. This must not be \c NULL. + * \param buf The buffer to write the generated shared key to. This + * must be a writable buffer of size \p blen Bytes. + * \param blen The length of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function, for blinding purposes. This may + * b \c NULL if blinding isn't needed. + * \param p_rng The RNG context. This may be \c NULL if \p f_rng + * doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. */ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, unsigned char *buf, size_t blen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief This function enables restartable EC computations for this + * context. (Default: disabled.) + * + * \see \c mbedtls_ecp_set_max_ops() + * + * \note It is not possible to safely disable restartable + * computations once enabled, except by free-ing the context, + * which cancels possible in-progress operations. + * + * \param ctx The ECDH context to use. This must be initialized. + */ +void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/ecdsa.h b/app/include/mbedtls/ecdsa.h index ff6efbc3ff..932acc6d14 100644 --- a/app/include/mbedtls/ecdsa.h +++ b/app/include/mbedtls/ecdsa.h @@ -1,9 +1,10 @@ /** * \file ecdsa.h * - * \brief The Elliptic Curve Digital Signature Algorithm (ECDSA). + * \brief This file contains ECDSA definitions and functions. * - * ECDSA is defined in Standards for Efficient Cryptography Group (SECG): + * The Elliptic Curve Digital Signature Algorithm (ECDSA) is defined in + * Standards for Efficient Cryptography Group (SECG): * SEC1 Elliptic Curve Cryptography. * The use of ECDSA for TLS is defined in RFC-4492: Elliptic Curve * Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS). @@ -31,6 +32,12 @@ #ifndef MBEDTLS_ECDSA_H #define MBEDTLS_ECDSA_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "ecp.h" #include "md.h" @@ -54,29 +61,71 @@ /** The maximal size of an ECDSA signature in Bytes. */ #define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) ) +#ifdef __cplusplus +extern "C" { +#endif + /** * \brief The ECDSA context structure. + * + * \warning Performing multiple operations concurrently on the same + * ECDSA context is not supported; objects of this type + * should not be shared between multiple threads. */ typedef mbedtls_ecp_keypair mbedtls_ecdsa_context; -#ifdef __cplusplus -extern "C" { +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Internal restart context for ecdsa_verify() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_ver mbedtls_ecdsa_restart_ver_ctx; + +/** + * \brief Internal restart context for ecdsa_sign() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_sig mbedtls_ecdsa_restart_sig_ctx; + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief Internal restart context for ecdsa_sign_det() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_det mbedtls_ecdsa_restart_det_ctx; #endif +/** + * \brief General context for resuming ECDSA operations + */ +typedef struct +{ + mbedtls_ecp_restart_ctx ecp; /*!< base context for ECP restart and + shared administrative info */ + mbedtls_ecdsa_restart_ver_ctx *ver; /*!< ecdsa_verify() sub-context */ + mbedtls_ecdsa_restart_sig_ctx *sig; /*!< ecdsa_sign() sub-context */ +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + mbedtls_ecdsa_restart_det_ctx *det; /*!< ecdsa_sign_det() sub-context */ +#endif +} mbedtls_ecdsa_restart_ctx; + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +/* Now we can declare functions that take a pointer to that */ +typedef void mbedtls_ecdsa_restart_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + /** * \brief This function computes the ECDSA signature of a * previously-hashed message. * - * \note The deterministic version is usually preferred. - * - * \param grp The ECP group. - * \param r The first output integer. - * \param s The second output integer. - * \param d The private signing key. - * \param buf The message hash. - * \param blen The length of \p buf. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. + * \note The deterministic version implemented in + * mbedtls_ecdsa_sign_det() is usually preferred. * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated @@ -84,10 +133,28 @@ extern "C" { * (SECG): SEC1 Elliptic Curve Cryptography, section * 4.1.3, step 5. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX - * or \c MBEDTLS_MPI_XXX error code on failure. - * * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized. + * \param buf The content to be signed. This is usually the hash of + * the original data to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX + * or \c MBEDTLS_MPI_XXX error code on failure. */ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, @@ -97,62 +164,139 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, /** * \brief This function computes the ECDSA signature of a * previously-hashed message, deterministic version. + * * For more information, see RFC-6979: Deterministic * Usage of the Digital Signature Algorithm (DSA) and Elliptic * Curve Digital Signature Algorithm (ECDSA). * - * \param grp The ECP group. - * \param r The first output integer. - * \param s The second output integer. - * \param d The private signing key. - * \param buf The message hash. - * \param blen The length of \p buf. - * \param md_alg The MD algorithm used to hash the message. - * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as * defined in Standards for Efficient Cryptography Group * (SECG): SEC1 Elliptic Curve Cryptography, section * 4.1.3, step 5. * - * \return \c 0 on success, - * or an \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * \warning Since the output of the internal RNG is always the same for + * the same key and message, this limits the efficiency of + * blinding and leaks information through side channels. For + * secure behavior use mbedtls_ecdsa_sign_det_ext() instead. + * + * (Optimally the blinding is a random value that is different + * on every execution. In this case the blinding is still + * random from the attackers perspective, but is the same on + * each execution. This means that this blinding does not + * prevent attackers from recovering secrets by combining + * several measurement traces, but may prevent some attacks + * that exploit relationships between secret data.) + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized + * and setup, for example through mbedtls_ecp_gen_privkey(). + * \param buf The hashed content to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param md_alg The hash algorithm used to hash the original data. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX * error code on failure. + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ); +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message, deterministic version. + * + * For more information, see RFC-6979: Deterministic + * Usage of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. * * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized + * and setup, for example through mbedtls_ecp_gen_privkey(). + * \param buf The hashed content to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param md_alg The hash algorithm used to hash the original data. + * \param f_rng_blind The RNG function used for blinding. This must not be + * \c NULL. + * \param p_rng_blind The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure. */ -int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, - const mbedtls_mpi *d, const unsigned char *buf, size_t blen, - mbedtls_md_type_t md_alg ); +int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, + size_t), + void *p_rng_blind ); #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ /** * \brief This function verifies the ECDSA signature of a * previously-hashed message. * - * \param grp The ECP group. - * \param buf The message hash. - * \param blen The length of \p buf. - * \param Q The public key to use for verification. - * \param r The first integer of the signature. - * \param s The second integer of the signature. - * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as * defined in Standards for Efficient Cryptography Group * (SECG): SEC1 Elliptic Curve Cryptography, section * 4.1.4, step 3. * - * \return \c 0 on success, - * #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid, - * or an \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX - * error code on failure for any other reason. - * * \see ecp.h + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param buf The hashed content that was signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param Q The public key to use for verification. This must be + * initialized and setup. + * \param r The first integer of the signature. + * This must be initialized. + * \param s The second integer of the signature. + * This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature + * is invalid. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure for any other reason. */ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, - const unsigned char *buf, size_t blen, - const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s); + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, + const mbedtls_mpi *s); /** * \brief This function computes the ECDSA signature and writes it @@ -169,38 +313,92 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, * of the Digital Signature Algorithm (DSA) and Elliptic * Curve Digital Signature Algorithm (ECDSA)
. * - * \param ctx The ECDSA context. - * \param md_alg The message digest that was used to hash the message. - * \param hash The message hash. - * \param hlen The length of the hash. - * \param sig The buffer that holds the signature. - * \param slen The length of the signature written. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. - * - * \note The \p sig buffer must be at least twice as large as the - * size of the curve used, plus 9. For example, 73 Bytes if - * a 256-bit curve is used. A buffer length of - * #MBEDTLS_ECDSA_MAX_LEN is always safe. - * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as * defined in Standards for Efficient Cryptography Group * (SECG): SEC1 Elliptic Curve Cryptography, section * 4.1.3, step 5. * - * \return \c 0 on success, - * or an \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or - * \c MBEDTLS_ERR_ASN1_XXX error code on failure. - * * \see ecp.h + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param md_alg The message digest that was used to hash the message. + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p blen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param f_rng The RNG function. This must not be \c NULL if + * #MBEDTLS_ECDSA_DETERMINISTIC is unset. Otherwise, + * it is unused and may be set to \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't use a context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ -int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hlen, unsigned char *sig, size_t *slen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +/** + * \brief This function computes the ECDSA signature and writes it + * to a buffer, in a restartable way. + * + * \see \c mbedtls_ecdsa_write_signature() + * + * \note This function is like \c mbedtls_ecdsa_write_signature() + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param md_alg The message digest that was used to hash the message. + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p blen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param f_rng The RNG function. This must not be \c NULL if + * #MBEDTLS_ECDSA_DETERMINISTIC is unset. Otherwise, + * it is unused and may be set to \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't use a context. + * \param rs_ctx The restart context to use. This may be \c NULL to disable + * restarting. If it is not \c NULL, it must point to an + * initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecdsa_restart_ctx *rs_ctx ); + #if defined(MBEDTLS_ECDSA_DETERMINISTIC) #if ! defined(MBEDTLS_DEPRECATED_REMOVED) #if defined(MBEDTLS_DEPRECATED_WARNING) @@ -209,31 +407,17 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t #define MBEDTLS_DEPRECATED #endif /** - * \brief This function computes an ECDSA signature and writes it to a buffer, - * serialized as defined in RFC-4492: Elliptic Curve Cryptography - * (ECC) Cipher Suites for Transport Layer Security (TLS). + * \brief This function computes an ECDSA signature and writes + * it to a buffer, serialized as defined in RFC-4492: + * Elliptic Curve Cryptography (ECC) Cipher Suites for + * Transport Layer Security (TLS). * - * The deterministic version is defined in RFC-6979: - * Deterministic Usage of the Digital Signature Algorithm (DSA) and - * Elliptic Curve Digital Signature Algorithm (ECDSA). + * The deterministic version is defined in RFC-6979: + * Deterministic Usage of the Digital Signature Algorithm (DSA) + * and Elliptic Curve Digital Signature Algorithm (ECDSA). * * \warning It is not thread-safe to use the same context in * multiple threads. - - * - * \deprecated Superseded by mbedtls_ecdsa_write_signature() in 2.0.0 - * - * \param ctx The ECDSA context. - * \param hash The Message hash. - * \param hlen The length of the hash. - * \param sig The buffer that holds the signature. - * \param slen The length of the signature written. - * \param md_alg The MD algorithm used to hash the message. - * - * \note The \p sig buffer must be at least twice as large as the - * size of the curve used, plus 9. For example, 73 Bytes if a - * 256-bit curve is used. A buffer length of - * #MBEDTLS_ECDSA_MAX_LEN is always safe. * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as @@ -241,11 +425,29 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t * (SECG): SEC1 Elliptic Curve Cryptography, section * 4.1.3, step 5. * - * \return \c 0 on success, - * or an \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or - * \c MBEDTLS_ERR_ASN1_XXX error code on failure. - * * \see ecp.h + * + * \deprecated Superseded by mbedtls_ecdsa_write_signature() in + * Mbed TLS version 2.0 and later. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p blen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param md_alg The message digest that was used to hash the message. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. */ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, @@ -258,75 +460,143 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, /** * \brief This function reads and verifies an ECDSA signature. * - * \param ctx The ECDSA context. - * \param hash The message hash. - * \param hlen The size of the hash. - * \param sig The signature to read and verify. - * \param slen The size of \p sig. - * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as * defined in Standards for Efficient Cryptography Group * (SECG): SEC1 Elliptic Curve Cryptography, section * 4.1.4, step 3. * - * \return \c 0 on success, - * #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid, - * #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid - * signature in sig but its length is less than \p siglen, - * or an \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX - * error code on failure for any other reason. - * * \see ecp.h + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and public key bound to it. + * \param hash The message hash that was signed. This must be a readable + * buffer of length \p size Bytes. + * \param hlen The size of the hash \p hash. + * \param sig The signature to read and verify. This must be a readable + * buffer of length \p slen Bytes. + * \param slen The size of \p sig in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. + * \return #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid + * signature in \p sig, but its length is less than \p siglen. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX + * error code on failure for any other reason. */ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, const unsigned char *sig, size_t slen ); +/** + * \brief This function reads and verifies an ECDSA signature, + * in a restartable way. + * + * \see \c mbedtls_ecdsa_read_signature() + * + * \note This function is like \c mbedtls_ecdsa_read_signature() + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and public key bound to it. + * \param hash The message hash that was signed. This must be a readable + * buffer of length \p size Bytes. + * \param hlen The size of the hash \p hash. + * \param sig The signature to read and verify. This must be a readable + * buffer of length \p slen Bytes. + * \param slen The size of \p sig in Bytes. + * \param rs_ctx The restart context to use. This may be \c NULL to disable + * restarting. If it is not \c NULL, it must point to an + * initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. + * \return #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid + * signature in \p sig, but its length is less than \p siglen. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen, + mbedtls_ecdsa_restart_ctx *rs_ctx ); + /** * \brief This function generates an ECDSA keypair on the given curve. * + * \see ecp.h + * * \param ctx The ECDSA context to store the keypair in. + * This must be initialized. * \param gid The elliptic curve to use. One of the various * \c MBEDTLS_ECP_DP_XXX macros depending on configuration. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX code on - * failure. - * - * \see ecp.h + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. */ int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); /** - * \brief This function sets an ECDSA context from an EC key pair. + * \brief This function sets up an ECDSA context from an EC key pair. * - * \param ctx The ECDSA context to set. - * \param key The EC key to use. + * \see ecp.h * - * \return \c 0 on success, or an \c MBEDTLS_ERR_ECP_XXX code on - * failure. + * \param ctx The ECDSA context to setup. This must be initialized. + * \param key The EC key to use. This must be initialized and hold + * a private-public key pair or a public key. In the former + * case, the ECDSA context may be used for signature creation + * and verification after this call. In the latter case, it + * may be used for signature verification. * - * \see ecp.h + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. */ -int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ); +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, + const mbedtls_ecp_keypair *key ); /** * \brief This function initializes an ECDSA context. * * \param ctx The ECDSA context to initialize. + * This must not be \c NULL. */ void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ); /** * \brief This function frees an ECDSA context. * - * \param ctx The ECDSA context to free. + * \param ctx The ECDSA context to free. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must be initialized. */ void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ); +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context. + * + * \param ctx The restart context to initialize. + * This must not be \c NULL. + */ +void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx ); + +/** + * \brief Free the components of a restart context. + * + * \param ctx The restart context to free. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must be initialized. + */ +void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/ecjpake.h b/app/include/mbedtls/ecjpake.h index d86e8207f1..3d8d02ae64 100644 --- a/app/include/mbedtls/ecjpake.h +++ b/app/include/mbedtls/ecjpake.h @@ -40,12 +40,15 @@ * The payloads are serialized in a way suitable for use in TLS, but could * also be use outside TLS. */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif #include "ecp.h" #include "md.h" -#if !defined(MBEDTLS_ECJPAKE_ALT) - #ifdef __cplusplus extern "C" { #endif @@ -58,6 +61,7 @@ typedef enum { MBEDTLS_ECJPAKE_SERVER, /**< Server */ } mbedtls_ecjpake_role; +#if !defined(MBEDTLS_ECJPAKE_ALT) /** * EC J-PAKE context structure. * @@ -69,7 +73,7 @@ typedef enum { * convetion from the Thread v1.0 spec. Correspondance is indicated in the * description as a pair C: client name, S: server name */ -typedef struct +typedef struct mbedtls_ecjpake_context { const mbedtls_md_info_t *md_info; /**< Hash to use */ mbedtls_ecp_group grp; /**< Elliptic curve */ @@ -88,29 +92,38 @@ typedef struct mbedtls_mpi s; /**< Pre-shared secret (passphrase) */ } mbedtls_ecjpake_context; +#else /* MBEDTLS_ECJPAKE_ALT */ +#include "ecjpake_alt.h" +#endif /* MBEDTLS_ECJPAKE_ALT */ + /** - * \brief Initialize a context - * (just makes it ready for setup() or free()). + * \brief Initialize an ECJPAKE context. * - * \param ctx context to initialize + * \param ctx The ECJPAKE context to initialize. + * This must not be \c NULL. */ void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ); /** - * \brief Set up a context for use + * \brief Set up an ECJPAKE context for use. * * \note Currently the only values for hash/curve allowed by the - * standard are MBEDTLS_MD_SHA256/MBEDTLS_ECP_DP_SECP256R1. + * standard are #MBEDTLS_MD_SHA256/#MBEDTLS_ECP_DP_SECP256R1. * - * \param ctx context to set up - * \param role Our role: client or server - * \param hash hash function to use (MBEDTLS_MD_XXX) - * \param curve elliptic curve identifier (MBEDTLS_ECP_DP_XXX) - * \param secret pre-shared secret (passphrase) - * \param len length of the shared secret + * \param ctx The ECJPAKE context to set up. This must be initialized. + * \param role The role of the caller. This must be either + * #MBEDTLS_ECJPAKE_CLIENT or #MBEDTLS_ECJPAKE_SERVER. + * \param hash The identifier of the hash function to use, + * for example #MBEDTLS_MD_SHA256. + * \param curve The identifier of the elliptic curve to use, + * for example #MBEDTLS_ECP_DP_SECP256R1. + * \param secret The pre-shared secret (passphrase). This must be + * a readable buffer of length \p len Bytes. It need + * only be valid for the duration of this call. + * \param len The length of the pre-shared secret \p secret. * - * \return 0 if successfull, - * a negative error code otherwise + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, mbedtls_ecjpake_role role, @@ -120,29 +133,34 @@ int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, size_t len ); /** - * \brief Check if a context is ready for use + * \brief Check if an ECJPAKE context is ready for use. * - * \param ctx Context to check + * \param ctx The ECJPAKE context to check. This must be + * initialized. * - * \return 0 if the context is ready for use, - * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + * \return \c 0 if the context is ready for use. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise. */ int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ); /** * \brief Generate and write the first round message * (TLS: contents of the Client/ServerHello extension, - * excluding extension type and length bytes) + * excluding extension type and length bytes). * - * \param ctx Context to use - * \param buf Buffer to write the contents to - * \param len Buffer size - * \param olen Will be updated with the number of bytes written - * \param f_rng RNG function - * \param p_rng RNG parameter + * \param ctx The ECJPAKE context to use. This must be + * initialized and set up. + * \param buf The buffer to write the contents to. This must be a + * writable buffer of length \p len Bytes. + * \param len The length of \p buf in Bytes. + * \param olen The address at which to store the total number + * of Bytes written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. * - * \return 0 if successfull, - * a negative error code otherwise + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, unsigned char *buf, size_t len, size_t *olen, @@ -152,14 +170,16 @@ int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, /** * \brief Read and process the first round message * (TLS: contents of the Client/ServerHello extension, - * excluding extension type and length bytes) + * excluding extension type and length bytes). * - * \param ctx Context to use - * \param buf Pointer to extension contents - * \param len Extension length + * \param ctx The ECJPAKE context to use. This must be initialized + * and set up. + * \param buf The buffer holding the first round message. This must + * be a readable buffer of length \p len Bytes. + * \param len The length in Bytes of \p buf. * - * \return 0 if successfull, - * a negative error code otherwise + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, const unsigned char *buf, @@ -167,17 +187,21 @@ int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, /** * \brief Generate and write the second round message - * (TLS: contents of the Client/ServerKeyExchange) + * (TLS: contents of the Client/ServerKeyExchange). * - * \param ctx Context to use - * \param buf Buffer to write the contents to - * \param len Buffer size - * \param olen Will be updated with the number of bytes written - * \param f_rng RNG function - * \param p_rng RNG parameter + * \param ctx The ECJPAKE context to use. This must be initialized, + * set up, and already have performed round one. + * \param buf The buffer to write the round two contents to. + * This must be a writable buffer of length \p len Bytes. + * \param len The size of \p buf in Bytes. + * \param olen The address at which to store the total number of Bytes + * written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. * - * \return 0 if successfull, - * a negative error code otherwise + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, unsigned char *buf, size_t len, size_t *olen, @@ -186,14 +210,16 @@ int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, /** * \brief Read and process the second round message - * (TLS: contents of the Client/ServerKeyExchange) + * (TLS: contents of the Client/ServerKeyExchange). * - * \param ctx Context to use - * \param buf Pointer to the message - * \param len Message length + * \param ctx The ECJPAKE context to use. This must be initialized + * and set up and already have performed round one. + * \param buf The buffer holding the second round message. This must + * be a readable buffer of length \p len Bytes. + * \param len The length in Bytes of \p buf. * - * \return 0 if successfull, - * a negative error code otherwise + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, const unsigned char *buf, @@ -201,17 +227,21 @@ int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, /** * \brief Derive the shared secret - * (TLS: Pre-Master Secret) + * (TLS: Pre-Master Secret). * - * \param ctx Context to use - * \param buf Buffer to write the contents to - * \param len Buffer size - * \param olen Will be updated with the number of bytes written - * \param f_rng RNG function - * \param p_rng RNG parameter + * \param ctx The ECJPAKE context to use. This must be initialized, + * set up and have performed both round one and two. + * \param buf The buffer to write the derived secret to. This must + * be a writable buffer of length \p len Bytes. + * \param len The length of \p buf in Bytes. + * \param olen The address at which to store the total number of Bytes + * written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. * - * \return 0 if successfull, - * a negative error code otherwise + * \return \c 0 if successful. + * \return A negative error code on failure. */ int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, unsigned char *buf, size_t len, size_t *olen, @@ -219,26 +249,17 @@ int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, void *p_rng ); /** - * \brief Free a context's content + * \brief This clears an ECJPAKE context and frees any + * embedded data structure. * - * \param ctx context to free + * \param ctx The ECJPAKE context to free. This may be \c NULL, + * in which case this function does nothing. If it is not + * \c NULL, it must point to an initialized ECJPAKE context. */ void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx ); -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_ECJPAKE_ALT */ -#include "ecjpake_alt.h" -#endif /* MBEDTLS_ECJPAKE_ALT */ - #if defined(MBEDTLS_SELF_TEST) -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief Checkup routine * @@ -246,10 +267,11 @@ extern "C" { */ int mbedtls_ecjpake_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif -#endif /* MBEDTLS_SELF_TEST */ #endif /* ecjpake.h */ diff --git a/app/include/mbedtls/ecp.h b/app/include/mbedtls/ecp.h index 7b8ffff44e..065a4cc0b9 100644 --- a/app/include/mbedtls/ecp.h +++ b/app/include/mbedtls/ecp.h @@ -1,10 +1,21 @@ /** * \file ecp.h * - * \brief Elliptic curves over GF(p) + * \brief This file provides an API for Elliptic Curves over GF(P) (ECP). + * + * The use of ECP in cryptography and TLS is defined in + * Standards for Efficient Cryptography Group (SECG): SEC1 + * Elliptic Curve Cryptography and + * RFC-4492: Elliptic Curve Cryptography (ECC) Cipher Suites + * for Transport Layer Security (TLS). + * + * RFC-2409: The Internet Key Exchange (IKE) defines ECP + * group types. + * */ + /* - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -19,11 +30,18 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * This file is part of mbed TLS (https://tls.mbed.org) + * This file is part of Mbed TLS (https://tls.mbed.org) */ + #ifndef MBEDTLS_ECP_H #define MBEDTLS_ECP_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "bignum.h" /* @@ -31,160 +49,165 @@ */ #define MBEDTLS_ERR_ECP_BAD_INPUT_DATA -0x4F80 /**< Bad input parameters to function. */ #define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL -0x4F00 /**< The buffer is too small to write to. */ -#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE -0x4E80 /**< Requested curve not available. */ +#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE -0x4E80 /**< The requested feature is not available, for example, the requested curve is not supported. */ #define MBEDTLS_ERR_ECP_VERIFY_FAILED -0x4E00 /**< The signature is not valid. */ #define MBEDTLS_ERR_ECP_ALLOC_FAILED -0x4D80 /**< Memory allocation failed. */ -#define MBEDTLS_ERR_ECP_RANDOM_FAILED -0x4D00 /**< Generation of random value, such as (ephemeral) key, failed. */ +#define MBEDTLS_ERR_ECP_RANDOM_FAILED -0x4D00 /**< Generation of random value, such as ephemeral key, failed. */ #define MBEDTLS_ERR_ECP_INVALID_KEY -0x4C80 /**< Invalid private or public key. */ #define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH -0x4C00 /**< The buffer contains a valid signature followed by more data. */ -#define MBEDTLS_ERR_ECP_HW_ACCEL_FAILED -0x4B80 /**< ECP hardware accelerator failed. */ -#if !defined(MBEDTLS_ECP_ALT) -/* - * default mbed TLS elliptic curve arithmetic implementation - * - * (in case MBEDTLS_ECP_ALT is defined then the developer has to provide an - * alternative implementation for the whole module and it will replace this - * one.) - */ +/* MBEDTLS_ERR_ECP_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_ECP_HW_ACCEL_FAILED -0x4B80 /**< The ECP hardware accelerator failed. */ + +#define MBEDTLS_ERR_ECP_IN_PROGRESS -0x4B00 /**< Operation in progress, call again with the same parameters to continue. */ #ifdef __cplusplus extern "C" { #endif /** - * Domain parameters (curve, subgroup and generator) identifiers. + * Domain-parameter identifiers: curve, subgroup, and generator. * - * Only curves over prime fields are supported. + * \note Only curves over prime fields are supported. * * \warning This library does not support validation of arbitrary domain - * parameters. Therefore, only well-known domain parameters from trusted + * parameters. Therefore, only standardized domain parameters from trusted * sources should be used. See mbedtls_ecp_group_load(). */ typedef enum { - MBEDTLS_ECP_DP_NONE = 0, - MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ - MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ - MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ - MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */ - MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */ - MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */ - MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */ - MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */ - MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */ - MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */ - MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */ - MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_NONE = 0, /*!< Curve not defined. */ + MBEDTLS_ECP_DP_SECP192R1, /*!< Domain parameters for the 192-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP224R1, /*!< Domain parameters for the 224-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP256R1, /*!< Domain parameters for the 256-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP384R1, /*!< Domain parameters for the 384-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP521R1, /*!< Domain parameters for the 521-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_BP256R1, /*!< Domain parameters for 256-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP384R1, /*!< Domain parameters for 384-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP512R1, /*!< Domain parameters for 512-bit Brainpool curve. */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Domain parameters for Curve25519. */ + MBEDTLS_ECP_DP_SECP192K1, /*!< Domain parameters for 192-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_SECP224K1, /*!< Domain parameters for 224-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_SECP256K1, /*!< Domain parameters for 256-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_CURVE448, /*!< Domain parameters for Curve448. */ } mbedtls_ecp_group_id; /** - * Number of supported curves (plus one for NONE). + * The number of supported curves, plus one for #MBEDTLS_ECP_DP_NONE. * - * (Montgomery curves excluded for now.) + * \note Montgomery curves are currently excluded. */ #define MBEDTLS_ECP_DP_MAX 12 /** - * Curve information for use by other modules + * Curve information, for use by other modules. */ -typedef struct +typedef struct mbedtls_ecp_curve_info { - mbedtls_ecp_group_id grp_id; /*!< Internal identifier */ - uint16_t tls_id; /*!< TLS NamedCurve identifier */ - uint16_t bit_size; /*!< Curve size in bits */ - const char *name; /*!< Human-friendly name */ + mbedtls_ecp_group_id grp_id; /*!< An internal identifier. */ + uint16_t tls_id; /*!< The TLS NamedCurve identifier. */ + uint16_t bit_size; /*!< The curve size in bits. */ + const char *name; /*!< A human-friendly name. */ } mbedtls_ecp_curve_info; /** - * \brief ECP point structure (jacobian coordinates) + * \brief The ECP point structure, in Jacobian coordinates. * * \note All functions expect and return points satisfying - * the following condition: Z == 0 or Z == 1. (Other - * values of Z are used by internal functions only.) - * The point is zero, or "at infinity", if Z == 0. - * Otherwise, X and Y are its standard (affine) coordinates. + * the following condition: Z == 0 or + * Z == 1. Other values of \p Z are + * used only by internal functions. + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, \p X and \p Y are its standard (affine) + * coordinates. */ -typedef struct +typedef struct mbedtls_ecp_point { - mbedtls_mpi X; /*!< the point's X coordinate */ - mbedtls_mpi Y; /*!< the point's Y coordinate */ - mbedtls_mpi Z; /*!< the point's Z coordinate */ + mbedtls_mpi X; /*!< The X coordinate of the ECP point. */ + mbedtls_mpi Y; /*!< The Y coordinate of the ECP point. */ + mbedtls_mpi Z; /*!< The Z coordinate of the ECP point. */ } mbedtls_ecp_point; -/** - * \brief ECP group structure - * - * We consider two types of curves equations: - * 1. Short Weierstrass y^2 = x^3 + A x + B mod P (SEC1 + RFC 4492) - * 2. Montgomery, y^2 = x^3 + A x^2 + x mod P (Curve25519 + draft) - * In both cases, a generator G for a prime-order subgroup is fixed. In the - * short weierstrass, this subgroup is actually the whole curve, and its - * cardinal is denoted by N. - * - * In the case of Short Weierstrass curves, our code requires that N is an odd - * prime. (Use odd in mbedtls_ecp_mul() and prime in mbedtls_ecdsa_sign() for blinding.) - * - * In the case of Montgomery curves, we don't store A but (A + 2) / 4 which is - * the quantity actually used in the formulas. Also, nbits is not the size of N - * but the required size for private keys. +#if !defined(MBEDTLS_ECP_ALT) +/* + * default mbed TLS elliptic curve arithmetic implementation * - * If modp is NULL, reduction modulo P is done using a generic algorithm. - * Otherwise, it must point to a function that takes an mbedtls_mpi in the range - * 0..2^(2*pbits)-1 and transforms it in-place in an integer of little more - * than pbits, so that the integer may be efficiently brought in the 0..P-1 - * range by a few additions or substractions. It must return 0 on success and - * non-zero on failure. + * (in case MBEDTLS_ECP_ALT is defined then the developer has to provide an + * alternative implementation for the whole module and it will replace this + * one.) */ -typedef struct -{ - mbedtls_ecp_group_id id; /*!< internal group identifier */ - mbedtls_mpi P; /*!< prime modulus of the base field */ - mbedtls_mpi A; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ - mbedtls_mpi B; /*!< 1. B in the equation, or 2. unused */ - mbedtls_ecp_point G; /*!< generator of the (sub)group used */ - mbedtls_mpi N; /*!< 1. the order of G, or 2. unused */ - size_t pbits; /*!< number of bits in P */ - size_t nbits; /*!< number of bits in 1. P, or 2. private keys */ - unsigned int h; /*!< internal: 1 if the constants are static */ - int (*modp)(mbedtls_mpi *); /*!< function for fast reduction mod P */ - int (*t_pre)(mbedtls_ecp_point *, void *); /*!< unused */ - int (*t_post)(mbedtls_ecp_point *, void *); /*!< unused */ - void *t_data; /*!< unused */ - mbedtls_ecp_point *T; /*!< pre-computed points for ecp_mul_comb() */ - size_t T_size; /*!< number for pre-computed points */ -} -mbedtls_ecp_group; /** - * \brief ECP key pair structure - * - * A generic key pair that could be used for ECDSA, fixed ECDH, etc. + * \brief The ECP group structure. + * + * We consider two types of curve equations: + *
  • Short Weierstrass: y^2 = x^3 + A x + B mod P + * (SEC1 + RFC-4492)
  • + *
  • Montgomery: y^2 = x^3 + A x^2 + x mod P (Curve25519, + * Curve448)
+ * In both cases, the generator (\p G) for a prime-order subgroup is fixed. + * + * For Short Weierstrass, this subgroup is the whole curve, and its + * cardinality is denoted by \p N. Our code requires that \p N is an + * odd prime as mbedtls_ecp_mul() requires an odd number, and + * mbedtls_ecdsa_sign() requires that it is prime for blinding purposes. + * + * For Montgomery curves, we do not store \p A, but (A + 2) / 4, + * which is the quantity used in the formulas. Additionally, \p nbits is + * not the size of \p N but the required size for private keys. + * + * If \p modp is NULL, reduction modulo \p P is done using a generic algorithm. + * Otherwise, \p modp must point to a function that takes an \p mbedtls_mpi in the + * range of 0..2^(2*pbits)-1, and transforms it in-place to an integer + * which is congruent mod \p P to the given MPI, and is close enough to \p pbits + * in size, so that it may be efficiently brought in the 0..P-1 range by a few + * additions or subtractions. Therefore, it is only an approximative modular + * reduction. It must return 0 on success and non-zero on failure. + * + * \note Alternative implementations must keep the group IDs distinct. If + * two group structures have the same ID, then they must be + * identical. * - * \note Members purposefully in the same order as struc mbedtls_ecdsa_context. */ -typedef struct +typedef struct mbedtls_ecp_group { - mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ - mbedtls_mpi d; /*!< our secret value */ - mbedtls_ecp_point Q; /*!< our public value */ + mbedtls_ecp_group_id id; /*!< An internal group identifier. */ + mbedtls_mpi P; /*!< The prime modulus of the base field. */ + mbedtls_mpi A; /*!< For Short Weierstrass: \p A in the equation. For + Montgomery curves: (A + 2) / 4. */ + mbedtls_mpi B; /*!< For Short Weierstrass: \p B in the equation. + For Montgomery curves: unused. */ + mbedtls_ecp_point G; /*!< The generator of the subgroup used. */ + mbedtls_mpi N; /*!< The order of \p G. */ + size_t pbits; /*!< The number of bits in \p P.*/ + size_t nbits; /*!< For Short Weierstrass: The number of bits in \p P. + For Montgomery curves: the number of bits in the + private keys. */ + unsigned int h; /*!< \internal 1 if the constants are static. */ + int (*modp)(mbedtls_mpi *); /*!< The function for fast pseudo-reduction + mod \p P (see above).*/ + int (*t_pre)(mbedtls_ecp_point *, void *); /*!< Unused. */ + int (*t_post)(mbedtls_ecp_point *, void *); /*!< Unused. */ + void *t_data; /*!< Unused. */ + mbedtls_ecp_point *T; /*!< Pre-computed points for ecp_mul_comb(). */ + size_t T_size; /*!< The number of pre-computed points. */ } -mbedtls_ecp_keypair; +mbedtls_ecp_group; /** * \name SECTION: Module settings * * The configuration options you can set for this module are in this section. - * Either change them in config.h or define them on the compiler command line. + * Either change them in config.h, or define them using the compiler command line. * \{ */ #if !defined(MBEDTLS_ECP_MAX_BITS) /** - * Maximum size of the groups (that is, of N and P) + * The maximum size of the groups, that is, of \c N and \c P. */ -#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +#define MBEDTLS_ECP_MAX_BITS 521 /**< The maximum size of groups, in bits. */ #endif #define MBEDTLS_ECP_MAX_BYTES ( ( MBEDTLS_ECP_MAX_BITS + 7 ) / 8 ) @@ -207,11 +230,10 @@ mbedtls_ecp_keypair; * 521 145 141 135 120 97 * 384 214 209 198 177 146 * 256 320 320 303 262 226 - * 224 475 475 453 398 342 * 192 640 640 633 587 476 */ -#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< The maximum window size used. */ #endif /* MBEDTLS_ECP_WINDOW_SIZE */ #if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM) @@ -226,33 +248,188 @@ mbedtls_ecp_keypair; * * Change this value to 0 to reduce peak memory usage. */ -#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up. */ #endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */ /* \} name SECTION: Module settings */ +#else /* MBEDTLS_ECP_ALT */ +#include "ecp_alt.h" +#endif /* MBEDTLS_ECP_ALT */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Internal restart context for multiplication + * + * \note Opaque struct + */ +typedef struct mbedtls_ecp_restart_mul mbedtls_ecp_restart_mul_ctx; + +/** + * \brief Internal restart context for ecp_muladd() + * + * \note Opaque struct + */ +typedef struct mbedtls_ecp_restart_muladd mbedtls_ecp_restart_muladd_ctx; + +/** + * \brief General context for resuming ECC operations + */ +typedef struct +{ + unsigned ops_done; /*!< current ops count */ + unsigned depth; /*!< call depth (0 = top-level) */ + mbedtls_ecp_restart_mul_ctx *rsm; /*!< ecp_mul_comb() sub-context */ + mbedtls_ecp_restart_muladd_ctx *ma; /*!< ecp_muladd() sub-context */ +} mbedtls_ecp_restart_ctx; + +/* + * Operation counts for restartable functions + */ +#define MBEDTLS_ECP_OPS_CHK 3 /*!< basic ops count for ecp_check_pubkey() */ +#define MBEDTLS_ECP_OPS_DBL 8 /*!< basic ops count for ecp_double_jac() */ +#define MBEDTLS_ECP_OPS_ADD 11 /*!< basic ops count for see ecp_add_mixed() */ +#define MBEDTLS_ECP_OPS_INV 120 /*!< empirical equivalent for mpi_mod_inv() */ + +/** + * \brief Internal; for restartable functions in other modules. + * Check and update basic ops budget. + * + * \param grp Group structure + * \param rs_ctx Restart context + * \param ops Number of basic ops to do + * + * \return \c 0 if doing \p ops basic ops is still allowed, + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS otherwise. + */ +int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp, + mbedtls_ecp_restart_ctx *rs_ctx, + unsigned ops ); + +/* Utility macro for checking and updating ops budget */ +#define MBEDTLS_ECP_BUDGET( ops ) \ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, rs_ctx, \ + (unsigned) (ops) ) ); + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define MBEDTLS_ECP_BUDGET( ops ) /* no-op; for compatibility */ + +/* We want to declare restartable versions of existing functions anyway */ +typedef void mbedtls_ecp_restart_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief The ECP key-pair structure. + * + * A generic key-pair that may be used for ECDSA and fixed ECDH, for example. + * + * \note Members are deliberately in the same order as in the + * ::mbedtls_ecdsa_context structure. + */ +typedef struct mbedtls_ecp_keypair +{ + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; /*!< our public value */ +} +mbedtls_ecp_keypair; + /* * Point formats, from RFC 4492's enum ECPointFormat */ -#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format */ -#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format */ +#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format. */ +#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format. */ /* * Some other constants from RFC 4492 */ -#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< ECCurveType's named_curve */ +#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< The named_curve of ECCurveType. */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Set the maximum number of basic operations done in a row. + * + * If more operations are needed to complete a computation, + * #MBEDTLS_ERR_ECP_IN_PROGRESS will be returned by the + * function performing the computation. It is then the + * caller's responsibility to either call again with the same + * parameters until it returns 0 or an error code; or to free + * the restart context if the operation is to be aborted. + * + * It is strictly required that all input parameters and the + * restart context be the same on successive calls for the + * same operation, but output parameters need not be the + * same; they must not be used until the function finally + * returns 0. + * + * This only applies to functions whose documentation + * mentions they may return #MBEDTLS_ERR_ECP_IN_PROGRESS (or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS for functions in the + * SSL module). For functions that accept a "restart context" + * argument, passing NULL disables restart and makes the + * function equivalent to the function with the same name + * with \c _restartable removed. For functions in the ECDH + * module, restart is disabled unless the function accepts + * an "ECDH context" argument and + * mbedtls_ecdh_enable_restart() was previously called on + * that context. For function in the SSL module, restart is + * only enabled for specific sides and key exchanges + * (currently only for clients and ECDHE-ECDSA). + * + * \param max_ops Maximum number of basic operations done in a row. + * Default: 0 (unlimited). + * Lower (non-zero) values mean ECC functions will block for + * a lesser maximum amount of time. + * + * \note A "basic operation" is defined as a rough equivalent of a + * multiplication in GF(p) for the NIST P-256 curve. + * As an indication, with default settings, a scalar + * multiplication (full run of \c mbedtls_ecp_mul()) is: + * - about 3300 basic operations for P-256 + * - about 9400 basic operations for P-384 + * + * \note Very low values are not always respected: sometimes + * functions need to block for a minimum number of + * operations, and will do so even if max_ops is set to a + * lower value. That minimum depends on the curve size, and + * can be made lower by decreasing the value of + * \c MBEDTLS_ECP_WINDOW_SIZE. As an indication, here is the + * lowest effective value for various curves and values of + * that parameter (w for short): + * w=6 w=5 w=4 w=3 w=2 + * P-256 208 208 160 136 124 + * P-384 682 416 320 272 248 + * P-521 1364 832 640 544 496 + * + * \note This setting is currently ignored by Curve25519. + */ +void mbedtls_ecp_set_max_ops( unsigned max_ops ); + +/** + * \brief Check if restart is enabled (max_ops != 0) + * + * \return \c 0 if \c max_ops == 0 (restart disabled) + * \return \c 1 otherwise (restart enabled) + */ +int mbedtls_ecp_restart_is_enabled( void ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ /** - * \brief Get the list of supported curves in order of preferrence - * (full information) + * \brief This function retrieves the information defined in + * mbedtls_ecp_curve_info() for all supported curves in order + * of preference. * - * \return A statically allocated array, the last entry is 0. + * \return A statically allocated array. The last entry is 0. */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); /** - * \brief Get the list of supported curves in order of preferrence - * (grp_id only) + * \brief This function retrieves the list of internal group + * identifiers of all supported curves in the order of + * preference. * * \return A statically allocated array, * terminated with MBEDTLS_ECP_DP_NONE. @@ -260,416 +437,689 @@ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ); /** - * \brief Get curve information from an internal group identifier + * \brief This function retrieves curve information from an internal + * group identifier. * - * \param grp_id A MBEDTLS_ECP_DP_XXX value + * \param grp_id An \c MBEDTLS_ECP_DP_XXX value. * - * \return The associated curve information or NULL + * \return The associated curve information on success. + * \return NULL on failure. */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ); /** - * \brief Get curve information from a TLS NamedCurve value + * \brief This function retrieves curve information from a TLS + * NamedCurve value. * - * \param tls_id A MBEDTLS_ECP_DP_XXX value + * \param tls_id An \c MBEDTLS_ECP_DP_XXX value. * - * \return The associated curve information or NULL + * \return The associated curve information on success. + * \return NULL on failure. */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ); /** - * \brief Get curve information from a human-readable name + * \brief This function retrieves curve information from a + * human-readable name. * - * \param name The name + * \param name The human-readable name. * - * \return The associated curve information or NULL + * \return The associated curve information on success. + * \return NULL on failure. */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ); /** - * \brief Initialize a point (as zero) + * \brief This function initializes a point as zero. + * + * \param pt The point to initialize. */ void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ); /** - * \brief Initialize a group (to something meaningless) + * \brief This function initializes an ECP group context + * without loading any domain parameters. + * + * \note After this function is called, domain parameters + * for various ECP groups can be loaded through the + * mbedtls_ecp_group_load() or mbedtls_ecp_tls_read_group() + * functions. */ void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ); /** - * \brief Initialize a key pair (as an invalid one) + * \brief This function initializes a key pair as an invalid one. + * + * \param key The key pair to initialize. */ void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ); /** - * \brief Free the components of a point + * \brief This function frees the components of a point. + * + * \param pt The point to free. */ void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ); /** - * \brief Free the components of an ECP group + * \brief This function frees the components of an ECP group. + * + * \param grp The group to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized ECP group. */ void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ); /** - * \brief Free the components of a key pair + * \brief This function frees the components of a key pair. + * + * \param key The key pair to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized ECP key pair. */ void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ); +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context. + * + * \param ctx The restart context to initialize. This must + * not be \c NULL. + */ +void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx ); + /** - * \brief Copy the contents of point Q into P + * \brief Free the components of a restart context. * - * \param P Destination point - * \param Q Source point + * \param ctx The restart context to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized restart context. + */ +void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief This function copies the contents of point \p Q into + * point \p P. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \param P The destination point. This must be initialized. + * \param Q The source point. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code for other kinds of failure. */ int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); /** - * \brief Copy the contents of a group object + * \brief This function copies the contents of group \p src into + * group \p dst. * - * \param dst Destination group - * \param src Source group + * \param dst The destination group. This must be initialized. + * \param src The source group. This must be initialized. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. */ -int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ); +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, + const mbedtls_ecp_group *src ); /** - * \brief Set a point to zero + * \brief This function sets a point to the point at infinity. * - * \param pt Destination point + * \param pt The point to set. This must be initialized. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. */ int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ); /** - * \brief Tell if a point is zero + * \brief This function checks if a point is the point at infinity. * - * \param pt Point to test + * \param pt The point to test. This must be initialized. * - * \return 1 if point is zero, 0 otherwise + * \return \c 1 if the point is zero. + * \return \c 0 if the point is non-zero. + * \return A negative error code on failure. */ int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ); /** - * \brief Compare two points + * \brief This function compares two points. * - * \note This assumes the points are normalized. Otherwise, + * \note This assumes that the points are normalized. Otherwise, * they may compare as "not equal" even if they are. * - * \param P First point to compare - * \param Q Second point to compare + * \param P The first point to compare. This must be initialized. + * \param Q The second point to compare. This must be initialized. * - * \return 0 if the points are equal, - * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + * \return \c 0 if the points are equal. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the points are not equal. */ int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); /** - * \brief Import a non-zero point from two ASCII strings + * \brief This function imports a non-zero point from two ASCII + * strings. * - * \param P Destination point - * \param radix Input numeric base - * \param x First affine coordinate as a null-terminated string - * \param y Second affine coordinate as a null-terminated string + * \param P The destination point. This must be initialized. + * \param radix The numeric base of the input. + * \param x The first affine coordinate, as a null-terminated string. + * \param y The second affine coordinate, as a null-terminated string. * - * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on failure. */ int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, const char *x, const char *y ); /** - * \brief Export a point into unsigned binary data - * - * \param grp Group to which the point should belong - * \param P Point to export - * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro - * \param olen Length of the actual output - * \param buf Output buffer - * \param buflen Length of the output buffer - * - * \return 0 if successful, - * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA - * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * \brief This function exports a point into unsigned binary data. + * + * \param grp The group to which the point should belong. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param P The point to export. This must be initialized. + * \param format The point format. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * \param olen The address at which to store the length of + * the output in Bytes. This must not be \c NULL. + * \param buf The output buffer. This must be a writable buffer + * of length \p buflen Bytes. + * \param buflen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output buffer + * is too small to hold the point. + * \return Another negative error code on other kinds of failure. */ int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, int format, size_t *olen, unsigned char *buf, size_t buflen ); /** - * \brief Import a point from unsigned binary data - * - * \param grp Group to which the point should belong - * \param P Point to import - * \param buf Input buffer - * \param ilen Actual length of input - * - * \return 0 if successful, - * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, - * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * \brief This function imports a point from unsigned binary data. + * + * \note This function does not check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() + * for that. + * + * \param grp The group to which the point should belong. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param P The destination context to import the point to. + * This must be initialized. + * \param buf The input buffer. This must be a readable buffer + * of length \p ilen Bytes. + * \param ilen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format * is not implemented. - * - * \note This function does NOT check that the point actually - * belongs to the given group, see mbedtls_ecp_check_pubkey() for - * that. */ -int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, - const unsigned char *buf, size_t ilen ); +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen ); /** - * \brief Import a point from a TLS ECPoint record - * - * \param grp ECP group used - * \param pt Destination point - * \param buf $(Start of input buffer) - * \param len Buffer length - * - * \note buf is updated to point right after the ECPoint on exit - * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_XXX if initialization failed - * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + * \brief This function imports a point from a TLS ECPoint record. + * + * \note On function return, \p *buf is updated to point immediately + * after the ECPoint record. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The destination point. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization + * failure. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. */ -int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, - const unsigned char **buf, size_t len ); +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); /** - * \brief Export a point as a TLS ECPoint record - * - * \param grp ECP group used - * \param pt Point to export - * \param format Export format - * \param olen length of data written - * \param buf Buffer to write to - * \param blen Buffer length - * - * \return 0 if successful, - * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA - * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * \brief This function exports a point as a TLS ECPoint record + * defined in RFC 4492, Section 5.4. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to be exported. This must be initialized. + * \param format The point format to use. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * \param olen The address at which to store the length in Bytes + * of the data written. + * \param buf The target buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the target buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the target buffer + * is too small to hold the exported point. + * \return Another negative error code on other kinds of failure. */ -int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, - int format, size_t *olen, - unsigned char *buf, size_t blen ); +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); /** - * \brief Set a group using well-known domain parameters + * \brief This function sets up an ECP group context + * from a standardized set of domain parameters. * - * \param grp Destination group - * \param id Index in the list of well-known domain parameters + * \note The index should be a value of the NamedCurve enum, + * as defined in RFC-4492: Elliptic Curve Cryptography + * (ECC) Cipher Suites for Transport Layer Security (TLS), + * usually in the form of an \c MBEDTLS_ECP_DP_XXX macro. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_XXX if initialization failed - * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups + * \param grp The group context to setup. This must be initialized. + * \param id The identifier of the domain parameter set to load. * - * \note Index should be a value of RFC 4492's enum NamedCurve, - * usually in the form of a MBEDTLS_ECP_DP_XXX macro. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if \p id doesn't + * correspond to a known group. + * \return Another negative error code on other kinds of failure. */ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ); /** - * \brief Set a group from a TLS ECParameters record + * \brief This function sets up an ECP group context from a TLS + * ECParameters record as defined in RFC 4492, Section 5.4. * - * \param grp Destination group - * \param buf &(Start of input buffer) - * \param len Buffer length + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. * - * \note buf is updated to point right after ECParameters on exit + * \param grp The group context to setup. This must be initialized. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. * - * \return 0 if successful, - * MBEDTLS_ERR_MPI_XXX if initialization failed - * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. */ -int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ); +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, + const unsigned char **buf, size_t len ); /** - * \brief Write the TLS ECParameters record for a group - * - * \param grp ECP group used - * \param olen Number of bytes actually written - * \param buf Buffer to write to - * \param blen Buffer length - * - * \return 0 if successful, - * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * \brief This function extracts an elliptic curve group ID from a + * TLS ECParameters record as defined in RFC 4492, Section 5.4. + * + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. + * + * \param grp The address at which to store the group id. + * This must not be \c NULL. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, + size_t len ); +/** + * \brief This function exports an elliptic curve as a TLS + * ECParameters record as defined in RFC 4492, Section 5.4. + * + * \param grp The ECP group to be exported. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The buffer to write to. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output + * buffer is too small to hold the exported group. + * \return Another negative error code on other kinds of failure. */ -int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, - unsigned char *buf, size_t blen ); +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, + size_t *olen, + unsigned char *buf, size_t blen ); /** - * \brief Multiplication by an integer: R = m * P - * (Not thread-safe to use same group in multiple threads) - * - * \note In order to prevent timing attacks, this function - * executes the exact same sequence of (base field) - * operations for any valid m. It avoids any if-branch or - * array index depending on the value of m. - * - * \note If f_rng is not NULL, it is used to randomize intermediate - * results in order to prevent potential timing attacks - * targeting these results. It is recommended to always - * provide a non-NULL f_rng (the overhead is negligible). - * - * \param grp ECP group - * \param R Destination point - * \param m Integer by which to multiply - * \param P Point to multiply - * \param f_rng RNG function (see notes) - * \param p_rng RNG parameter - * - * \return 0 if successful, - * MBEDTLS_ERR_ECP_INVALID_KEY if m is not a valid privkey - * or P is not a valid pubkey, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \brief This function performs a scalar multiplication of a point + * by an integer: \p R = \p m * \p P. + * + * It is not thread-safe to use same group in multiple threads. + * + * \note To prevent timing attacks, this function + * executes the exact same sequence of base-field + * operations for any valid \p m. It avoids any if-branch or + * array index depending on the value of \p m. + * + * \note If \p f_rng is not NULL, it is used to randomize + * intermediate results to prevent potential timing attacks + * targeting these results. We recommend always providing + * a non-NULL \p f_rng. The overhead is negligible. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply. This must be initialized. + * \param P The point to multiply. This must be initialized. + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results isn't desired (discouraged). + * \param p_rng The RNG context to be passed to \p p_rng. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private + * key, or \p P is not a valid public key. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. */ int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); /** - * \brief Multiplication and addition of two points by integers: - * R = m * P + n * Q - * (Not thread-safe to use same group in multiple threads) - * - * \note In contrast to mbedtls_ecp_mul(), this function does not guarantee - * a constant execution flow and timing. - * - * \param grp ECP group - * \param R Destination point - * \param m Integer by which to multiply P - * \param P Point to multiply by m - * \param n Integer by which to multiply Q - * \param Q Point to be multiplied by n - * - * \return 0 if successful, - * MBEDTLS_ERR_ECP_INVALID_KEY if m or n is not a valid privkey - * or P or Q is not a valid pubkey, - * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * \brief This function performs multiplication of a point by + * an integer: \p R = \p m * \p P in a restartable way. + * + * \see mbedtls_ecp_mul() + * + * \note This function does the same as \c mbedtls_ecp_mul(), but + * it can return early and restart according to the limit set + * with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply. This must be initialized. + * \param P The point to multiply. This must be initialized. + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results isn't desired (discouraged). + * \param p_rng The RNG context to be passed to \p p_rng. + * \param rs_ctx The restart context (NULL disables restart). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private + * key, or \p P is not a valid public key. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ); + +/** + * \brief This function performs multiplication and addition of two + * points by integers: \p R = \p m * \p P + \p n * \p Q + * + * It is not thread-safe to use same group in multiple threads. + * + * \note In contrast to mbedtls_ecp_mul(), this function does not + * guarantee a constant execution flow and timing. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply \p P. + * This must be initialized. + * \param P The point to multiply by \p m. This must be initialized. + * \param n The integer by which to multiply \p Q. + * This must be initialized. + * \param Q The point to be multiplied by \p n. + * This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not + * valid private keys, or \p P or \p Q are not valid public + * keys. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. */ int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, const mbedtls_mpi *n, const mbedtls_ecp_point *Q ); /** - * \brief Check that a point is a valid public key on this curve - * - * \param grp Curve/group the point should belong to - * \param pt Point to check - * - * \return 0 if point is a valid public key, - * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. - * - * \note This function only checks the point is non-zero, has valid - * coordinates and lies on the curve, but not that it is - * indeed a multiple of G. This is additional check is more - * expensive, isn't required by standards, and shouldn't be - * necessary if the group used has a small cofactor. In - * particular, it is useless for the NIST groups which all - * have a cofactor of 1. - * - * \note Uses bare components rather than an mbedtls_ecp_keypair structure - * in order to ease use with other structures such as - * mbedtls_ecdh_context of mbedtls_ecdsa_context. + * \brief This function performs multiplication and addition of two + * points by integers: \p R = \p m * \p P + \p n * \p Q in a + * restartable way. + * + * \see \c mbedtls_ecp_muladd() + * + * \note This function works the same as \c mbedtls_ecp_muladd(), + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply \p P. + * This must be initialized. + * \param P The point to multiply by \p m. This must be initialized. + * \param n The integer by which to multiply \p Q. + * This must be initialized. + * \param Q The point to be multiplied by \p n. + * This must be initialized. + * \param rs_ctx The restart context (NULL disables restart). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not + * valid private keys, or \p P or \p Q are not valid public + * keys. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another negative error code on other kinds of failure. */ -int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ); +int mbedtls_ecp_muladd_restartable( + mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q, + mbedtls_ecp_restart_ctx *rs_ctx ); /** - * \brief Check that an mbedtls_mpi is a valid private key for this curve - * - * \param grp Group used - * \param d Integer to check - * - * \return 0 if point is a valid private key, - * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. - * - * \note Uses bare components rather than an mbedtls_ecp_keypair structure - * in order to ease use with other structures such as - * mbedtls_ecdh_context of mbedtls_ecdsa_context. + * \brief This function checks that a point is a valid public key + * on this curve. + * + * It only checks that the point is non-zero, has + * valid coordinates and lies on the curve. It does not verify + * that it is indeed a multiple of \p G. This additional + * check is computationally more expensive, is not required + * by standards, and should not be necessary if the group + * used has a small cofactor. In particular, it is useless for + * the NIST groups which all have a cofactor of 1. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure, to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group the point should belong to. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to check. This must be initialized. + * + * \return \c 0 if the point is a valid public key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if the point is not + * a valid public key for the given curve. + * \return Another negative error code on other kinds of failure. */ -int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ); +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt ); /** - * \brief Generate a keypair with configurable base point - * - * \param grp ECP group - * \param G Chosen base point - * \param d Destination MPI (secret part) - * \param Q Destination point (public part) - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful, - * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code - * - * \note Uses bare components rather than an mbedtls_ecp_keypair structure - * in order to ease use with other structures such as - * mbedtls_ecdh_context of mbedtls_ecdsa_context. + * \brief This function checks that an \p mbedtls_mpi is a + * valid private key for this curve. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group the private key should belong to. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The integer to check. This must be initialized. + * + * \return \c 0 if the point is a valid private key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if the point is not a valid + * private key for the given curve. + * \return Another negative error code on other kinds of failure. */ -int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, - const mbedtls_ecp_point *G, - mbedtls_mpi *d, mbedtls_ecp_point *Q, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, + const mbedtls_mpi *d ); /** - * \brief Generate a keypair - * - * \param grp ECP group - * \param d Destination MPI (secret part) - * \param Q Destination point (public part) - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful, - * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code - * - * \note Uses bare components rather than an mbedtls_ecp_keypair structure - * in order to ease use with other structures such as - * mbedtls_ecdh_context of mbedtls_ecdsa_context. + * \brief This function generates a private key. + * + * \param grp The ECP group to generate a private key for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The destination MPI (secret part). This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. */ -int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, +int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp, + mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); /** - * \brief Generate a keypair + * \brief This function generates a keypair with a configurable base + * point. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group to generate a key pair for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param G The base point to use. This must be initialized + * and belong to \p grp. It replaces the default base + * point \c grp->G used by mbedtls_ecp_gen_keypair(). + * \param d The destination MPI (secret part). + * This must be initialized. + * \param Q The destination point (public part). + * This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function generates an ECP keypair. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group to generate a key pair for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The destination MPI (secret part). + * This must be initialized. + * \param Q The destination point (public part). + * This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, + mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function generates an ECP key. * - * \param grp_id ECP group identifier - * \param key Destination keypair - * \param f_rng RNG function - * \param p_rng RNG parameter + * \param grp_id The ECP group identifier. + * \param key The destination key. This must be initialized. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. * - * \return 0 if successful, - * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. */ int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); /** - * \brief Check a public-private key pair - * - * \param pub Keypair structure holding a public key - * \param prv Keypair structure holding a private (plus public) key - * - * \return 0 if successful (keys are valid and match), or - * MBEDTLS_ERR_ECP_BAD_INPUT_DATA, or - * a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX code. + * \brief This function checks that the keypair objects + * \p pub and \p prv have the same group and the + * same public point, and that the private key in + * \p prv is consistent with the public key. + * + * \param pub The keypair structure holding the public key. This + * must be initialized. If it contains a private key, that + * part is ignored. + * \param prv The keypair structure holding the full keypair. + * This must be initialized. + * + * \return \c 0 on success, meaning that the keys are valid and match. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the keys are invalid or do not match. + * \return An \c MBEDTLS_ERR_ECP_XXX or an \c MBEDTLS_ERR_MPI_XXX + * error code on calculation failure. */ -int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ); +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, + const mbedtls_ecp_keypair *prv ); #if defined(MBEDTLS_SELF_TEST) /** - * \brief Checkup routine + * \brief The ECP checkup routine. * - * \return 0 if successful, or 1 if a test failed + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_ecp_self_test( int verbose ); @@ -679,8 +1129,4 @@ int mbedtls_ecp_self_test( int verbose ); } #endif -#else /* MBEDTLS_ECP_ALT */ -#include "ecp_alt.h" -#endif /* MBEDTLS_ECP_ALT */ - #endif /* ecp.h */ diff --git a/app/include/mbedtls/ecp_internal.h b/app/include/mbedtls/ecp_internal.h index 18040697ad..7625ed48e1 100644 --- a/app/include/mbedtls/ecp_internal.h +++ b/app/include/mbedtls/ecp_internal.h @@ -61,6 +61,12 @@ #ifndef MBEDTLS_ECP_INTERNAL_H #define MBEDTLS_ECP_INTERNAL_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #if defined(MBEDTLS_ECP_INTERNAL_ALT) /** diff --git a/app/include/mbedtls/entropy.h b/app/include/mbedtls/entropy.h index fcb4d02557..ca06dc3c58 100644 --- a/app/include/mbedtls/entropy.h +++ b/app/include/mbedtls/entropy.h @@ -107,7 +107,7 @@ typedef int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, s /** * \brief Entropy source state */ -typedef struct +typedef struct mbedtls_entropy_source_state { mbedtls_entropy_f_source_ptr f_source; /**< The entropy source callback */ void * p_source; /**< The callback data pointer */ @@ -120,7 +120,7 @@ mbedtls_entropy_source_state; /** * \brief Entropy context structure */ -typedef struct +typedef struct mbedtls_entropy_context { int accumulator_started; #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) @@ -166,7 +166,7 @@ void mbedtls_entropy_free( mbedtls_entropy_context *ctx ); * \param threshold Minimum required from source before entropy is released * ( with mbedtls_entropy_func() ) (in bytes) * \param strong MBEDTLS_ENTROPY_SOURCE_STRONG or - * MBEDTSL_ENTROPY_SOURCE_WEAK. + * MBEDTLS_ENTROPY_SOURCE_WEAK. * At least one strong source needs to be added. * Weaker sources (such as the cycle counter) can be used as * a complement. diff --git a/app/include/mbedtls/error.h b/app/include/mbedtls/error.h index 8b4d3a8755..bee0fe485a 100644 --- a/app/include/mbedtls/error.h +++ b/app/include/mbedtls/error.h @@ -4,7 +4,7 @@ * \brief Error to string translation */ /* - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -24,6 +24,12 @@ #ifndef MBEDTLS_ERROR_H #define MBEDTLS_ERROR_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include /** @@ -53,7 +59,7 @@ * GCM 3 0x0012-0x0014 0x0013-0x0013 * BLOWFISH 3 0x0016-0x0018 0x0017-0x0017 * THREADING 3 0x001A-0x001E - * AES 4 0x0020-0x0022 0x0023-0x0025 + * AES 5 0x0020-0x0022 0x0021-0x0025 * CAMELLIA 3 0x0024-0x0026 0x0027-0x0027 * XTEA 2 0x0028-0x0028 0x0029-0x0029 * BASE64 2 0x002A-0x002C @@ -62,7 +68,8 @@ * DES 2 0x0032-0x0032 0x0033-0x0033 * CTR_DBRG 4 0x0034-0x003A * ENTROPY 3 0x003C-0x0040 0x003D-0x003F - * NET 11 0x0042-0x0052 0x0043-0x0045 + * NET 13 0x0042-0x0052 0x0043-0x0049 + * ARIA 4 0x0058-0x005E * ASN1 7 0x0060-0x006C * CMAC 1 0x007A-0x007A * PBKDF2 1 0x007C-0x007C @@ -73,9 +80,13 @@ * MD4 1 0x002D-0x002D * MD5 1 0x002F-0x002F * RIPEMD160 1 0x0031-0x0031 - * SHA1 1 0x0035-0x0035 - * SHA256 1 0x0037-0x0037 - * SHA512 1 0x0039-0x0039 + * SHA1 1 0x0035-0x0035 0x0073-0x0073 + * SHA256 1 0x0037-0x0037 0x0074-0x0074 + * SHA512 1 0x0039-0x0039 0x0075-0x0075 + * CHACHA20 3 0x0051-0x0055 + * POLY1305 3 0x0057-0x005B + * CHACHAPOLY 2 0x0054-0x0056 + * PLATFORM 1 0x0070-0x0072 * * High-level module nr (3 bits - 0x0...-0x7...) * Name ID Nr of Errors @@ -86,11 +97,12 @@ * DHM 3 11 * PK 3 15 (Started from top) * RSA 4 11 - * ECP 4 9 (Started from top) + * ECP 4 10 (Started from top) * MD 5 5 + * HKDF 5 1 (Started from top) * CIPHER 6 8 - * SSL 6 17 (Started from top) - * SSL 7 31 + * SSL 6 23 (Started from top) + * SSL 7 32 * * Module dependent error code (5 bits 0x.00.-0x.F8.) */ diff --git a/app/include/mbedtls/gcm.h b/app/include/mbedtls/gcm.h index 00ed42190c..fd130abd7c 100644 --- a/app/include/mbedtls/gcm.h +++ b/app/include/mbedtls/gcm.h @@ -1,9 +1,11 @@ /** * \file gcm.h * - * \brief Galois/Counter Mode (GCM) for 128-bit block ciphers, as defined - * in D. McGrew, J. Viega, The Galois/Counter Mode of Operation - * (GCM), Natl. Inst. Stand. Technol. + * \brief This file contains GCM definitions and functions. + * + * The Galois/Counter Mode (GCM) for 128-bit block ciphers is defined + * in D. McGrew, J. Viega, The Galois/Counter Mode of Operation + * (GCM), Natl. Inst. Stand. Technol. * * For more information on GCM, see NIST SP 800-38D: Recommendation for * Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC. @@ -31,6 +33,12 @@ #ifndef MBEDTLS_GCM_H #define MBEDTLS_GCM_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "cipher.h" #include @@ -39,19 +47,23 @@ #define MBEDTLS_GCM_DECRYPT 0 #define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */ + +/* MBEDTLS_ERR_GCM_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_GCM_HW_ACCEL_FAILED -0x0013 /**< GCM hardware accelerator failed. */ -#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function. */ -#if !defined(MBEDTLS_GCM_ALT) +#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_GCM_ALT) + /** * \brief The GCM context structure. */ -typedef struct { +typedef struct mbedtls_gcm_context +{ mbedtls_cipher_context_t cipher_ctx; /*!< The cipher context used. */ uint64_t HL[16]; /*!< Precalculated HTable low. */ uint64_t HH[16]; /*!< Precalculated HTable high. */ @@ -66,6 +78,10 @@ typedef struct { } mbedtls_gcm_context; +#else /* !MBEDTLS_GCM_ALT */ +#include "gcm_alt.h" +#endif /* !MBEDTLS_GCM_ALT */ + /** * \brief This function initializes the specified GCM context, * to make references valid, and prepares the context @@ -75,7 +91,7 @@ mbedtls_gcm_context; * cipher, nor set the key. For this purpose, use * mbedtls_gcm_setkey(). * - * \param ctx The GCM context to initialize. + * \param ctx The GCM context to initialize. This must not be \c NULL. */ void mbedtls_gcm_init( mbedtls_gcm_context *ctx ); @@ -83,15 +99,17 @@ void mbedtls_gcm_init( mbedtls_gcm_context *ctx ); * \brief This function associates a GCM context with a * cipher algorithm and a key. * - * \param ctx The GCM context to initialize. + * \param ctx The GCM context. This must be initialized. * \param cipher The 128-bit block cipher to use. - * \param key The encryption key. + * \param key The encryption key. This must be a readable buffer of at + * least \p keybits bits. * \param keybits The key size in bits. Valid options are: *
  • 128 bits
  • *
  • 192 bits
  • *
  • 256 bits
* - * \return \c 0 on success, or a cipher specific error code. + * \return \c 0 on success. + * \return A cipher-specific error code on failure. */ int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, mbedtls_cipher_id_t cipher, @@ -101,17 +119,18 @@ int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, /** * \brief This function performs GCM encryption or decryption of a buffer. * - * \note For encryption, the output buffer can be the same as the input buffer. - * For decryption, the output buffer cannot be the same as input buffer. - * If the buffers overlap, the output buffer must trail at least 8 Bytes - * behind the input buffer. + * \note For encryption, the output buffer can be the same as the + * input buffer. For decryption, the output buffer cannot be + * the same as input buffer. If the buffers overlap, the output + * buffer must trail at least 8 Bytes behind the input buffer. * * \warning When this function performs a decryption, it outputs the * authentication tag and does not verify that the data is * authentic. You should use this function to perform encryption * only. For decryption, use mbedtls_gcm_auth_decrypt() instead. * - * \param ctx The GCM context to use for encryption or decryption. + * \param ctx The GCM context to use for encryption or decryption. This + * must be initialized. * \param mode The operation to perform: * - #MBEDTLS_GCM_ENCRYPT to perform authenticated encryption. * The ciphertext is written to \p output and the @@ -125,22 +144,28 @@ int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, * calling this function in decryption mode. * \param length The length of the input data, which is equal to the length * of the output data. - * \param iv The initialization vector. + * \param iv The initialization vector. This must be a readable buffer of + * at least \p iv_len Bytes. * \param iv_len The length of the IV. - * \param add The buffer holding the additional data. + * \param add The buffer holding the additional data. This must be of at + * least that size in Bytes. * \param add_len The length of the additional data. - * \param input The buffer holding the input data. Its size is \b length. - * \param output The buffer for holding the output data. It must have room - * for \b length bytes. + * \param input The buffer holding the input data. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size in Bytes. + * \param output The buffer for holding the output data. If \p length is greater + * than zero, this must be a writable buffer of at least that + * size in Bytes. * \param tag_len The length of the tag to generate. - * \param tag The buffer for holding the tag. + * \param tag The buffer for holding the tag. This must be a readable + * buffer of at least \p tag_len Bytes. * * \return \c 0 if the encryption or decryption was performed * successfully. Note that in #MBEDTLS_GCM_DECRYPT mode, * this does not indicate that the data is authentic. - * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths are not valid. - * \return #MBEDTLS_ERR_GCM_HW_ACCEL_FAILED or a cipher-specific - * error code if the encryption or decryption failed. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths or pointers are + * not valid or a cipher-specific error code if the encryption + * or decryption failed. */ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, int mode, @@ -158,28 +183,34 @@ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, * \brief This function performs a GCM authenticated decryption of a * buffer. * - * \note For decryption, the output buffer cannot be the same as input buffer. - * If the buffers overlap, the output buffer must trail at least 8 Bytes - * behind the input buffer. + * \note For decryption, the output buffer cannot be the same as + * input buffer. If the buffers overlap, the output buffer + * must trail at least 8 Bytes behind the input buffer. * - * \param ctx The GCM context. + * \param ctx The GCM context. This must be initialized. * \param length The length of the ciphertext to decrypt, which is also * the length of the decrypted plaintext. - * \param iv The initialization vector. + * \param iv The initialization vector. This must be a readable buffer + * of at least \p iv_len Bytes. * \param iv_len The length of the IV. - * \param add The buffer holding the additional data. + * \param add The buffer holding the additional data. This must be of at + * least that size in Bytes. * \param add_len The length of the additional data. - * \param tag The buffer holding the tag to verify. + * \param tag The buffer holding the tag to verify. This must be a + * readable buffer of at least \p tag_len Bytes. * \param tag_len The length of the tag to verify. - * \param input The buffer holding the ciphertext. Its size is \b length. - * \param output The buffer for holding the decrypted plaintext. It must - * have room for \b length bytes. + * \param input The buffer holding the ciphertext. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size. + * \param output The buffer for holding the decrypted plaintext. If \p length + * is greater than zero, this must be a writable buffer of at + * least that size. * * \return \c 0 if successful and authenticated. * \return #MBEDTLS_ERR_GCM_AUTH_FAILED if the tag does not match. - * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths are not valid. - * \return #MBEDTLS_ERR_GCM_HW_ACCEL_FAILED or a cipher-specific - * error code if the decryption failed. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths or pointers are + * not valid or a cipher-specific error code if the decryption + * failed. */ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, size_t length, @@ -196,15 +227,18 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, * \brief This function starts a GCM encryption or decryption * operation. * - * \param ctx The GCM context. + * \param ctx The GCM context. This must be initialized. * \param mode The operation to perform: #MBEDTLS_GCM_ENCRYPT or * #MBEDTLS_GCM_DECRYPT. - * \param iv The initialization vector. + * \param iv The initialization vector. This must be a readable buffer of + * at least \p iv_len Bytes. * \param iv_len The length of the IV. - * \param add The buffer holding the additional data, or NULL if \p add_len is 0. - * \param add_len The length of the additional data. If 0, \p add is NULL. + * \param add The buffer holding the additional data, or \c NULL + * if \p add_len is \c 0. + * \param add_len The length of the additional data. If \c 0, + * \p add may be \c NULL. * - * \return \c 0 on success. + * \return \c 0 on success. */ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, int mode, @@ -221,16 +255,22 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, * Bytes. Only the last call before calling * mbedtls_gcm_finish() can be less than 16 Bytes. * - * \note For decryption, the output buffer cannot be the same as input buffer. - * If the buffers overlap, the output buffer must trail at least 8 Bytes - * behind the input buffer. + * \note For decryption, the output buffer cannot be the same as + * input buffer. If the buffers overlap, the output buffer + * must trail at least 8 Bytes behind the input buffer. * - * \param ctx The GCM context. - * \param length The length of the input data. This must be a multiple of 16 except in the last call before mbedtls_gcm_finish(). - * \param input The buffer holding the input data. - * \param output The buffer for holding the output data. + * \param ctx The GCM context. This must be initialized. + * \param length The length of the input data. This must be a multiple of + * 16 except in the last call before mbedtls_gcm_finish(). + * \param input The buffer holding the input data. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size in Bytes. + * \param output The buffer for holding the output data. If \p length is + * greater than zero, this must be a writable buffer of at + * least that size in Bytes. * - * \return \c 0 on success, or #MBEDTLS_ERR_GCM_BAD_INPUT on failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure. */ int mbedtls_gcm_update( mbedtls_gcm_context *ctx, size_t length, @@ -244,11 +284,14 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx, * It wraps up the GCM stream, and generates the * tag. The tag can have a maximum length of 16 Bytes. * - * \param ctx The GCM context. - * \param tag The buffer for holding the tag. - * \param tag_len The length of the tag to generate. Must be at least four. + * \param ctx The GCM context. This must be initialized. + * \param tag The buffer for holding the tag. This must be a readable + * buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to generate. This must be at least + * four. * - * \return \c 0 on success, or #MBEDTLS_ERR_GCM_BAD_INPUT on failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure. */ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, unsigned char *tag, @@ -258,29 +301,23 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, * \brief This function clears a GCM context and the underlying * cipher sub-context. * - * \param ctx The GCM context to clear. + * \param ctx The GCM context to clear. If this is \c NULL, the call has + * no effect. Otherwise, this must be initialized. */ void mbedtls_gcm_free( mbedtls_gcm_context *ctx ); -#ifdef __cplusplus -} -#endif - -#else /* !MBEDTLS_GCM_ALT */ -#include "gcm_alt.h" -#endif /* !MBEDTLS_GCM_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief The GCM checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_gcm_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/havege.h b/app/include/mbedtls/havege.h index d4cb3ed38d..4c1c86087a 100644 --- a/app/include/mbedtls/havege.h +++ b/app/include/mbedtls/havege.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_HAVEGE_H #define MBEDTLS_HAVEGE_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include #define MBEDTLS_HAVEGE_COLLECT_SIZE 1024 @@ -35,7 +41,7 @@ extern "C" { /** * \brief HAVEGE state structure */ -typedef struct +typedef struct mbedtls_havege_state { int PT1, PT2, offset[2]; int pool[MBEDTLS_HAVEGE_COLLECT_SIZE]; diff --git a/app/include/mbedtls/hkdf.h b/app/include/mbedtls/hkdf.h new file mode 100644 index 0000000000..bcafe42513 --- /dev/null +++ b/app/include/mbedtls/hkdf.h @@ -0,0 +1,141 @@ +/** + * \file hkdf.h + * + * \brief This file contains the HKDF interface. + * + * The HMAC-based Extract-and-Expand Key Derivation Function (HKDF) is + * specified by RFC 5869. + */ +/* + * Copyright (C) 2016-2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HKDF_H +#define MBEDTLS_HKDF_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +/** + * \name HKDF Error codes + * \{ + */ +#define MBEDTLS_ERR_HKDF_BAD_INPUT_DATA -0x5F80 /**< Bad input parameters to function. */ +/* \} name */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief This is the HMAC-based Extract-and-Expand Key Derivation Function + * (HKDF). + * + * \param md A hash function; md.size denotes the length of the hash + * function output in bytes. + * \param salt An optional salt value (a non-secret random value); + * if the salt is not provided, a string of all zeros of + * md.size length is used as the salt. + * \param salt_len The length in bytes of the optional \p salt. + * \param ikm The input keying material. + * \param ikm_len The length in bytes of \p ikm. + * \param info An optional context and application specific information + * string. This can be a zero-length string. + * \param info_len The length of \p info in bytes. + * \param okm The output keying material of \p okm_len bytes. + * \param okm_len The length of the output keying material in bytes. This + * must be less than or equal to 255 * md.size bytes. + * + * \return 0 on success. + * \return #MBEDTLS_ERR_HKDF_BAD_INPUT_DATA when the parameters are invalid. + * \return An MBEDTLS_ERR_MD_* error for errors returned from the underlying + * MD layer. + */ +int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt, + size_t salt_len, const unsigned char *ikm, size_t ikm_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len ); + +/** + * \brief Take the input keying material \p ikm and extract from it a + * fixed-length pseudorandom key \p prk. + * + * \warning This function should only be used if the security of it has been + * studied and established in that particular context (eg. TLS 1.3 + * key schedule). For standard HKDF security guarantees use + * \c mbedtls_hkdf instead. + * + * \param md A hash function; md.size denotes the length of the + * hash function output in bytes. + * \param salt An optional salt value (a non-secret random value); + * if the salt is not provided, a string of all zeros + * of md.size length is used as the salt. + * \param salt_len The length in bytes of the optional \p salt. + * \param ikm The input keying material. + * \param ikm_len The length in bytes of \p ikm. + * \param[out] prk A pseudorandom key of at least md.size bytes. + * + * \return 0 on success. + * \return #MBEDTLS_ERR_HKDF_BAD_INPUT_DATA when the parameters are invalid. + * \return An MBEDTLS_ERR_MD_* error for errors returned from the underlying + * MD layer. + */ +int mbedtls_hkdf_extract( const mbedtls_md_info_t *md, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk ); + +/** + * \brief Expand the supplied \p prk into several additional pseudorandom + * keys, which is the output of the HKDF. + * + * \warning This function should only be used if the security of it has been + * studied and established in that particular context (eg. TLS 1.3 + * key schedule). For standard HKDF security guarantees use + * \c mbedtls_hkdf instead. + * + * \param md A hash function; md.size denotes the length of the hash + * function output in bytes. + * \param prk A pseudorandom key of at least md.size bytes. \p prk is + * usually the output from the HKDF extract step. + * \param prk_len The length in bytes of \p prk. + * \param info An optional context and application specific information + * string. This can be a zero-length string. + * \param info_len The length of \p info in bytes. + * \param okm The output keying material of \p okm_len bytes. + * \param okm_len The length of the output keying material in bytes. This + * must be less than or equal to 255 * md.size bytes. + * + * \return 0 on success. + * \return #MBEDTLS_ERR_HKDF_BAD_INPUT_DATA when the parameters are invalid. + * \return An MBEDTLS_ERR_MD_* error for errors returned from the underlying + * MD layer. + */ +int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk, + size_t prk_len, const unsigned char *info, + size_t info_len, unsigned char *okm, size_t okm_len ); + +#ifdef __cplusplus +} +#endif + +#endif /* hkdf.h */ diff --git a/app/include/mbedtls/hmac_drbg.h b/app/include/mbedtls/hmac_drbg.h index f58b1e31d8..7931c2281c 100644 --- a/app/include/mbedtls/hmac_drbg.h +++ b/app/include/mbedtls/hmac_drbg.h @@ -1,10 +1,14 @@ /** * \file hmac_drbg.h * - * \brief HMAC_DRBG (NIST SP 800-90A) + * \brief The HMAC_DRBG pseudorandom generator. + * + * This module implements the HMAC_DRBG pseudorandom generator described + * in NIST SP 800-90A: Recommendation for Random Number Generation Using + * Deterministic Random Bit Generators. */ /* - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2019, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -80,9 +84,9 @@ extern "C" { /** * HMAC_DRBG context. */ -typedef struct +typedef struct mbedtls_hmac_drbg_context { - /* Working state: the key K is not stored explicitely, + /* Working state: the key K is not stored explicitly, * but is implied by the HMAC context */ mbedtls_md_context_t md_ctx; /*!< HMAC context (inc. K) */ unsigned char V[MBEDTLS_MD_MAX_SIZE]; /*!< V in the spec */ @@ -104,38 +108,72 @@ typedef struct } mbedtls_hmac_drbg_context; /** - * \brief HMAC_DRBG context initialization - * Makes the context ready for mbedtls_hmac_drbg_seed(), - * mbedtls_hmac_drbg_seed_buf() or - * mbedtls_hmac_drbg_free(). + * \brief HMAC_DRBG context initialization. + * + * This function makes the context ready for mbedtls_hmac_drbg_seed(), + * mbedtls_hmac_drbg_seed_buf() or mbedtls_hmac_drbg_free(). * - * \param ctx HMAC_DRBG context to be initialized + * \param ctx HMAC_DRBG context to be initialized. */ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ); /** - * \brief HMAC_DRBG initial seeding - * Seed and setup entropy source for future reseeds. - * - * \param ctx HMAC_DRBG context to be seeded - * \param md_info MD algorithm to use for HMAC_DRBG - * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer - * length) - * \param p_entropy Entropy context - * \param custom Personalization data (Device specific identifiers) - * (Can be NULL) - * \param len Length of personalization data - * - * \note The "security strength" as defined by NIST is set to: - * 128 bits if md_alg is SHA-1, - * 192 bits if md_alg is SHA-224, - * 256 bits if md_alg is SHA-256 or higher. - * Note that SHA-256 is just as efficient as SHA-224. + * \brief HMAC_DRBG initial seeding. + * + * Set the initial seed and set up the entropy source for future reseeds. + * + * A typical choice for the \p f_entropy and \p p_entropy parameters is + * to use the entropy module: + * - \p f_entropy is mbedtls_entropy_func(); + * - \p p_entropy is an instance of ::mbedtls_entropy_context initialized + * with mbedtls_entropy_init() (which registers the platform's default + * entropy sources). * - * \return 0 if successful, or - * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or - * MBEDTLS_ERR_MD_ALLOC_FAILED, or - * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED. + * You can provide a personalization string in addition to the + * entropy source, to make this instantiation as unique as possible. + * + * \note By default, the security strength as defined by NIST is: + * - 128 bits if \p md_info is SHA-1; + * - 192 bits if \p md_info is SHA-224; + * - 256 bits if \p md_info is SHA-256, SHA-384 or SHA-512. + * Note that SHA-256 is just as efficient as SHA-224. + * The security strength can be reduced if a smaller + * entropy length is set with + * mbedtls_hmac_drbg_set_entropy_len(). + * + * \note The default entropy length is the security strength + * (converted from bits to bytes). You can override + * it by calling mbedtls_hmac_drbg_set_entropy_len(). + * + * \note During the initial seeding, this function calls + * the entropy source to obtain a nonce + * whose length is half the entropy length. + * + * \param ctx HMAC_DRBG context to be seeded. + * \param md_info MD algorithm to use for HMAC_DRBG. + * \param f_entropy The entropy callback, taking as arguments the + * \p p_entropy context, the buffer to fill, and the + * length of the buffer. + * \p f_entropy is always called with a length that is + * less than or equal to the entropy length. + * \param p_entropy The entropy context to pass to \p f_entropy. + * \param custom The personalization string. + * This can be \c NULL, in which case the personalization + * string is empty regardless of the value of \p len. + * \param len The length of the personalization string. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_INPUT + * and also at most + * #MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT - \p entropy_len * 3 / 2 + * where \p entropy_len is the entropy length + * described above. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info is + * invalid. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED if there was not enough + * memory to allocate context data. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if the call to \p f_entropy failed. */ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, const mbedtls_md_info_t * md_info, @@ -146,115 +184,131 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, /** * \brief Initilisation of simpified HMAC_DRBG (never reseeds). - * (For use with deterministic ECDSA.) * - * \param ctx HMAC_DRBG context to be initialised - * \param md_info MD algorithm to use for HMAC_DRBG - * \param data Concatenation of entropy string and additional data - * \param data_len Length of data in bytes + * This function is meant for use in algorithms that need a pseudorandom + * input such as deterministic ECDSA. + * + * \param ctx HMAC_DRBG context to be initialised. + * \param md_info MD algorithm to use for HMAC_DRBG. + * \param data Concatenation of the initial entropy string and + * the additional data. + * \param data_len Length of \p data in bytes. * - * \return 0 if successful, or - * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or - * MBEDTLS_ERR_MD_ALLOC_FAILED. + * \return \c 0 if successful. or + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info is + * invalid. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED if there was not enough + * memory to allocate context data. */ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, const mbedtls_md_info_t * md_info, const unsigned char *data, size_t data_len ); /** - * \brief Enable / disable prediction resistance (Default: Off) + * \brief This function turns prediction resistance on or off. + * The default value is off. * - * Note: If enabled, entropy is used for ctx->entropy_len before each call! - * Only use this if you have ample supply of good entropy! + * \note If enabled, entropy is gathered at the beginning of + * every call to mbedtls_hmac_drbg_random_with_add() + * or mbedtls_hmac_drbg_random(). + * Only use this if your entropy source has sufficient + * throughput. * - * \param ctx HMAC_DRBG context - * \param resistance MBEDTLS_HMAC_DRBG_PR_ON or MBEDTLS_HMAC_DRBG_PR_OFF + * \param ctx The HMAC_DRBG context. + * \param resistance #MBEDTLS_HMAC_DRBG_PR_ON or #MBEDTLS_HMAC_DRBG_PR_OFF. */ void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx, int resistance ); /** - * \brief Set the amount of entropy grabbed on each reseed - * (Default: given by the security strength, which - * depends on the hash used, see \c mbedtls_hmac_drbg_init() ) + * \brief This function sets the amount of entropy grabbed on each + * seed or reseed. * - * \param ctx HMAC_DRBG context - * \param len Amount of entropy to grab, in bytes + * See the documentation of mbedtls_hmac_drbg_seed() for the default value. + * + * \param ctx The HMAC_DRBG context. + * \param len The amount of entropy to grab, in bytes. */ void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len ); /** - * \brief Set the reseed interval - * (Default: MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) + * \brief Set the reseed interval. + * + * The reseed interval is the number of calls to mbedtls_hmac_drbg_random() + * or mbedtls_hmac_drbg_random_with_add() after which the entropy function + * is called again. * - * \param ctx HMAC_DRBG context - * \param interval Reseed interval + * The default value is #MBEDTLS_HMAC_DRBG_RESEED_INTERVAL. + * + * \param ctx The HMAC_DRBG context. + * \param interval The reseed interval. */ void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, int interval ); /** - * \brief HMAC_DRBG update state + * \brief This function updates the state of the HMAC_DRBG context. * - * \param ctx HMAC_DRBG context - * \param additional Additional data to update state with, or NULL - * \param add_len Length of additional data, or 0 + * \param ctx The HMAC_DRBG context. + * \param additional The data to update the state with. + * If this is \c NULL, there is no additional data. + * \param add_len Length of \p additional in bytes. + * Unused if \p additional is \c NULL. * * \return \c 0 on success, or an error from the underlying * hash calculation. - * - * \note Additional data is optional, pass NULL and 0 as second - * third argument if no additional data is being used. */ int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t add_len ); /** - * \brief HMAC_DRBG update state - * - * \warning This function cannot report errors. You should use - * mbedtls_hmac_drbg_update_ret() instead. - * - * \param ctx HMAC_DRBG context - * \param additional Additional data to update state with, or NULL - * \param add_len Length of additional data, or 0 - * - * \note Additional data is optional, pass NULL and 0 as second - * third argument if no additional data is being used. - */ -void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, - const unsigned char *additional, - size_t add_len ); - -/** - * \brief HMAC_DRBG reseeding (extracts data from entropy source) - * - * \param ctx HMAC_DRBG context - * \param additional Additional data to add to state (Can be NULL) - * \param len Length of additional data - * - * \return 0 if successful, or - * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * \brief This function reseeds the HMAC_DRBG context, that is + * extracts data from the entropy source. + * + * \param ctx The HMAC_DRBG context. + * \param additional Additional data to add to the state. + * If this is \c NULL, there is no additional data + * and \p len should be \c 0. + * \param len The length of the additional data. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_INPUT + * and also at most + * #MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT - \p entropy_len + * where \p entropy_len is the entropy length + * (see mbedtls_hmac_drbg_set_entropy_len()). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if a call to the entropy function failed. */ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t len ); /** - * \brief HMAC_DRBG generate random with additional update input - * - * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. - * - * \param p_rng HMAC_DRBG context - * \param output Buffer to fill - * \param output_len Length of the buffer - * \param additional Additional data to update with (can be NULL) - * \param add_len Length of additional data (can be 0) - * - * \return 0 if successful, or - * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or - * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG, or - * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG. + * \brief This function updates an HMAC_DRBG instance with additional + * data and uses it to generate random data. + * + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. + * + * \param p_rng The HMAC_DRBG context. This must be a pointer to a + * #mbedtls_hmac_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer in bytes. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_REQUEST. + * \param additional Additional data to update with. + * If this is \c NULL, there is no additional data + * and \p add_len should be \c 0. + * \param add_len The length of the additional data. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_INPUT. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if a call to the entropy source failed. + * \return #MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG if + * \p output_len > #MBEDTLS_HMAC_DRBG_MAX_REQUEST. + * \return #MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG if + * \p add_len > #MBEDTLS_HMAC_DRBG_MAX_INPUT. */ int mbedtls_hmac_drbg_random_with_add( void *p_rng, unsigned char *output, size_t output_len, @@ -262,49 +316,83 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng, size_t add_len ); /** - * \brief HMAC_DRBG generate random - * - * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. - * - * \param p_rng HMAC_DRBG context - * \param output Buffer to fill - * \param out_len Length of the buffer - * - * \return 0 if successful, or - * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or - * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG + * \brief This function uses HMAC_DRBG to generate random data. + * + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. + * + * \param p_rng The HMAC_DRBG context. This must be a pointer to a + * #mbedtls_hmac_drbg_context structure. + * \param output The buffer to fill. + * \param out_len The length of the buffer in bytes. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_REQUEST. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if a call to the entropy source failed. + * \return #MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG if + * \p out_len > #MBEDTLS_HMAC_DRBG_MAX_REQUEST. */ int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len ); /** * \brief Free an HMAC_DRBG context * - * \param ctx HMAC_DRBG context to free. + * \param ctx The HMAC_DRBG context to free. */ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ); -#if defined(MBEDTLS_FS_IO) +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif /** - * \brief Write a seed file + * \brief This function updates the state of the HMAC_DRBG context. * - * \param ctx HMAC_DRBG context - * \param path Name of the file + * \deprecated Superseded by mbedtls_hmac_drbg_update_ret() + * in 2.16.0. * - * \return 0 if successful, 1 on file error, or - * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * \param ctx The HMAC_DRBG context. + * \param additional The data to update the state with. + * If this is \c NULL, there is no additional data. + * \param add_len Length of \p additional in bytes. + * Unused if \p additional is \c NULL. */ -int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); +MBEDTLS_DEPRECATED void mbedtls_hmac_drbg_update( + mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_FS_IO) /** - * \brief Read and update a seed file. Seed is added to this - * instance + * \brief This function writes a seed file. * - * \param ctx HMAC_DRBG context - * \param path Name of the file + * \param ctx The HMAC_DRBG context. + * \param path The name of the file. * - * \return 0 if successful, 1 on file error, - * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED or - * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG + * \return \c 0 on success. + * \return #MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED on reseed + * failure. + */ +int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); + +/** + * \brief This function reads and updates a seed file. The seed + * is added to this instance. + * + * \param ctx The HMAC_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED on + * reseed failure. + * \return #MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG if the existing + * seed file is too large. */ int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); #endif /* MBEDTLS_FS_IO */ @@ -312,9 +400,10 @@ int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const ch #if defined(MBEDTLS_SELF_TEST) /** - * \brief Checkup routine + * \brief The HMAC_DRBG Checkup routine. * - * \return 0 if successful, or 1 if the test failed + * \return \c 0 if successful. + * \return \c 1 if the test failed. */ int mbedtls_hmac_drbg_self_test( int verbose ); #endif diff --git a/app/include/mbedtls/md.h b/app/include/mbedtls/md.h index 06538c3827..8bcf766a6c 100644 --- a/app/include/mbedtls/md.h +++ b/app/include/mbedtls/md.h @@ -1,7 +1,7 @@ /** * \file md.h * - * \brief The generic message-digest wrapper. + * \brief This file contains the generic message-digest wrapper. * * \author Adriaan de Jong */ @@ -39,6 +39,8 @@ #define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ #define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ #define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ + +/* MBEDTLS_ERR_MD_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_MD_HW_ACCEL_FAILED -0x5280 /**< MD hardware accelerator failed. */ #ifdef __cplusplus @@ -46,7 +48,7 @@ extern "C" { #endif /** - * \brief Enumeration of supported message digests + * \brief Supported message digests. * * \warning MD2, MD4, MD5 and SHA-1 are considered weak message digests and * their use constitutes a security risk. We recommend considering @@ -54,16 +56,16 @@ extern "C" { * */ typedef enum { - MBEDTLS_MD_NONE=0, - MBEDTLS_MD_MD2, - MBEDTLS_MD_MD4, - MBEDTLS_MD_MD5, - MBEDTLS_MD_SHA1, - MBEDTLS_MD_SHA224, - MBEDTLS_MD_SHA256, - MBEDTLS_MD_SHA384, - MBEDTLS_MD_SHA512, - MBEDTLS_MD_RIPEMD160, + MBEDTLS_MD_NONE=0, /**< None. */ + MBEDTLS_MD_MD2, /**< The MD2 message digest. */ + MBEDTLS_MD_MD4, /**< The MD4 message digest. */ + MBEDTLS_MD_MD5, /**< The MD5 message digest. */ + MBEDTLS_MD_SHA1, /**< The SHA-1 message digest. */ + MBEDTLS_MD_SHA224, /**< The SHA-224 message digest. */ + MBEDTLS_MD_SHA256, /**< The SHA-256 message digest. */ + MBEDTLS_MD_SHA384, /**< The SHA-384 message digest. */ + MBEDTLS_MD_SHA512, /**< The SHA-512 message digest. */ + MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */ } mbedtls_md_type_t; #if defined(MBEDTLS_SHA512_C) @@ -80,7 +82,8 @@ typedef struct mbedtls_md_info_t mbedtls_md_info_t; /** * The generic message-digest context. */ -typedef struct { +typedef struct mbedtls_md_context_t +{ /** Information about the associated message digest. */ const mbedtls_md_info_t *md_info; @@ -108,8 +111,8 @@ const int *mbedtls_md_list( void ); * * \param md_name The name of the digest to search for. * - * \return The message-digest information associated with \p md_name, - * or NULL if not found. + * \return The message-digest information associated with \p md_name. + * \return NULL if the associated message-digest information is not found. */ const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); @@ -119,8 +122,8 @@ const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); * * \param md_type The type of digest to search for. * - * \return The message-digest information associated with \p md_type, - * or NULL if not found. + * \return The message-digest information associated with \p md_type. + * \return NULL if the associated message-digest information is not found. */ const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ); @@ -168,9 +171,10 @@ void mbedtls_md_free( mbedtls_md_context_t *ctx ); * \param md_info The information structure of the message-digest algorithm * to use. * - * \returns \c 0 on success, - * #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, - * #MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure. */ int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED; #undef MBEDTLS_DEPRECATED @@ -187,12 +191,13 @@ int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_ * \param ctx The context to set up. * \param md_info The information structure of the message-digest algorithm * to use. - * \param hmac
  • 0: HMAC is not used. Saves some memory.
  • - *
  • non-zero: HMAC is used with this context.
+ * \param hmac Defines if HMAC is used. 0: HMAC is not used (saves some memory), + * or non-zero: HMAC is used with this context. * - * \returns \c 0 on success, - * #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, or - * #MBEDTLS_ERR_MD_ALLOC_FAILED on memory allocation failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure. */ int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); @@ -212,8 +217,8 @@ int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_inf * \param dst The destination context. * \param src The context to be cloned. * - * \return \c 0 on success, - * #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. */ int mbedtls_md_clone( mbedtls_md_context_t *dst, const mbedtls_md_context_t *src ); @@ -260,8 +265,9 @@ const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ); * * \param ctx The generic message-digest context. * - * \returns \c 0 on success, #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_starts( mbedtls_md_context_t *ctx ); @@ -277,8 +283,9 @@ int mbedtls_md_starts( mbedtls_md_context_t *ctx ); * \param input The buffer holding the input data. * \param ilen The length of the input data. * - * \returns \c 0 on success, #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); @@ -296,8 +303,9 @@ int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, si * \param ctx The generic message-digest context. * \param output The buffer for the generic message-digest checksum result. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); @@ -315,8 +323,9 @@ int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); * \param ilen The length of the input data. * \param output The generic message-digest checksum result. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, unsigned char *output ); @@ -334,9 +343,10 @@ int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, si * \param path The input file name. * \param output The generic message-digest checksum result. * - * \return \c 0 on success, - * #MBEDTLS_ERR_MD_FILE_IO_ERROR if file input failed, or - * #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info was NULL. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_FILE_IO_ERROR on an I/O error accessing + * the file pointed by \p path. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info was NULL. */ int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output ); @@ -356,8 +366,9 @@ int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, * \param key The HMAC secret key. * \param keylen The length of the HMAC key in Bytes. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen ); @@ -377,8 +388,9 @@ int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, * \param input The buffer holding the input data. * \param ilen The length of the input data. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); @@ -397,8 +409,9 @@ int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *inpu * context. * \param output The generic HMAC checksum result. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); @@ -413,8 +426,9 @@ int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); * \param ctx The message digest context containing an embedded HMAC * context. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); @@ -436,8 +450,9 @@ int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); * \param ilen The length of the input data. * \param output The generic HMAC result. * - * \returns \c 0 on success, or #MBEDTLS_ERR_MD_BAD_INPUT_DATA if - * parameter verification fails. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. */ int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, const unsigned char *input, size_t ilen, diff --git a/app/include/mbedtls/md2.h b/app/include/mbedtls/md2.h index 0fd8b5afcc..fe97cf08d4 100644 --- a/app/include/mbedtls/md2.h +++ b/app/include/mbedtls/md2.h @@ -37,16 +37,17 @@ #include +/* MBEDTLS_ERR_MD2_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_MD2_HW_ACCEL_FAILED -0x002B /**< MD2 hardware accelerator failed */ -#if !defined(MBEDTLS_MD2_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_MD2_ALT) +// Regular implementation +// + /** * \brief MD2 context structure * @@ -55,7 +56,7 @@ extern "C" { * stronger message digests instead. * */ -typedef struct +typedef struct mbedtls_md2_context { unsigned char cksum[16]; /*!< checksum of the data block */ unsigned char state[48]; /*!< intermediate digest state */ @@ -64,6 +65,10 @@ typedef struct } mbedtls_md2_context; +#else /* MBEDTLS_MD2_ALT */ +#include "md2_alt.h" +#endif /* MBEDTLS_MD2_ALT */ + /** * \brief Initialize MD2 context * @@ -235,18 +240,6 @@ MBEDTLS_DEPRECATED void mbedtls_md2_process( mbedtls_md2_context *ctx ); #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_MD2_ALT */ -#include "md2_alt.h" -#endif /* MBEDTLS_MD2_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief Output = MD2( input buffer ) * @@ -290,6 +283,8 @@ MBEDTLS_DEPRECATED void mbedtls_md2( const unsigned char *input, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_SELF_TEST) + /** * \brief Checkup routine * @@ -302,6 +297,8 @@ MBEDTLS_DEPRECATED void mbedtls_md2( const unsigned char *input, */ int mbedtls_md2_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/md4.h b/app/include/mbedtls/md4.h index 23fa95e46a..ce703c0ba4 100644 --- a/app/include/mbedtls/md4.h +++ b/app/include/mbedtls/md4.h @@ -38,16 +38,17 @@ #include #include +/* MBEDTLS_ERR_MD4_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_MD4_HW_ACCEL_FAILED -0x002D /**< MD4 hardware accelerator failed */ -#if !defined(MBEDTLS_MD4_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_MD4_ALT) +// Regular implementation +// + /** * \brief MD4 context structure * @@ -56,7 +57,7 @@ extern "C" { * stronger message digests instead. * */ -typedef struct +typedef struct mbedtls_md4_context { uint32_t total[2]; /*!< number of bytes processed */ uint32_t state[4]; /*!< intermediate digest state */ @@ -64,6 +65,10 @@ typedef struct } mbedtls_md4_context; +#else /* MBEDTLS_MD4_ALT */ +#include "md4_alt.h" +#endif /* MBEDTLS_MD4_ALT */ + /** * \brief Initialize MD4 context * @@ -238,18 +243,6 @@ MBEDTLS_DEPRECATED void mbedtls_md4_process( mbedtls_md4_context *ctx, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_MD4_ALT */ -#include "md4_alt.h" -#endif /* MBEDTLS_MD4_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief Output = MD4( input buffer ) * @@ -295,6 +288,8 @@ MBEDTLS_DEPRECATED void mbedtls_md4( const unsigned char *input, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_SELF_TEST) + /** * \brief Checkup routine * @@ -307,6 +302,8 @@ MBEDTLS_DEPRECATED void mbedtls_md4( const unsigned char *input, */ int mbedtls_md4_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/md5.h b/app/include/mbedtls/md5.h index 06ea4c5d44..6eed6cc864 100644 --- a/app/include/mbedtls/md5.h +++ b/app/include/mbedtls/md5.h @@ -37,16 +37,17 @@ #include #include +/* MBEDTLS_ERR_MD5_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_MD5_HW_ACCEL_FAILED -0x002F /**< MD5 hardware accelerator failed */ -#if !defined(MBEDTLS_MD5_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_MD5_ALT) +// Regular implementation +// + /** * \brief MD5 context structure * @@ -55,7 +56,7 @@ extern "C" { * stronger message digests instead. * */ -typedef struct +typedef struct mbedtls_md5_context { uint32_t total[2]; /*!< number of bytes processed */ uint32_t state[4]; /*!< intermediate digest state */ @@ -63,6 +64,10 @@ typedef struct } mbedtls_md5_context; +#else /* MBEDTLS_MD5_ALT */ +#include "md5_alt.h" +#endif /* MBEDTLS_MD5_ALT */ + /** * \brief Initialize MD5 context * @@ -238,18 +243,6 @@ MBEDTLS_DEPRECATED void mbedtls_md5_process( mbedtls_md5_context *ctx, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_MD5_ALT */ -#include "md5_alt.h" -#endif /* MBEDTLS_MD5_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief Output = MD5( input buffer ) * @@ -295,6 +288,8 @@ MBEDTLS_DEPRECATED void mbedtls_md5( const unsigned char *input, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_SELF_TEST) + /** * \brief Checkup routine * @@ -307,6 +302,8 @@ MBEDTLS_DEPRECATED void mbedtls_md5( const unsigned char *input, */ int mbedtls_md5_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/net.h b/app/include/mbedtls/net.h index 6c13b53fb9..8cead58e5d 100644 --- a/app/include/mbedtls/net.h +++ b/app/include/mbedtls/net.h @@ -23,6 +23,11 @@ * * This file is part of mbed TLS (https://tls.mbed.org) */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif #if !defined(MBEDTLS_DEPRECATED_REMOVED) #include "net_sockets.h" diff --git a/app/include/mbedtls/net_sockets.h b/app/include/mbedtls/net_sockets.h index 52bb8de7c7..4c7ef00fe6 100644 --- a/app/include/mbedtls/net_sockets.h +++ b/app/include/mbedtls/net_sockets.h @@ -1,7 +1,23 @@ /** * \file net_sockets.h * - * \brief Network communication functions + * \brief Network sockets abstraction layer to integrate Mbed TLS into a + * BSD-style sockets API. + * + * The network sockets module provides an example integration of the + * Mbed TLS library into a BSD sockets implementation. The module is + * intended to be an example of how Mbed TLS can be integrated into a + * networking stack, as well as to be Mbed TLS's network integration + * for its supported platforms. + * + * The module is intended only to be used with the Mbed TLS library and + * is not intended to be used by third party application software + * directly. + * + * The supported platforms are as follows: + * * Microsoft Windows and Windows CE + * * POSIX/Unix platforms including Linux, OS X + * */ /* * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved @@ -46,12 +62,17 @@ #define MBEDTLS_ERR_NET_UNKNOWN_HOST -0x0052 /**< Failed to get an IP address for the given hostname. */ #define MBEDTLS_ERR_NET_BUFFER_TOO_SMALL -0x0043 /**< Buffer is too small to hold the data. */ #define MBEDTLS_ERR_NET_INVALID_CONTEXT -0x0045 /**< The context is invalid, eg because it was free()ed. */ +#define MBEDTLS_ERR_NET_POLL_FAILED -0x0047 /**< Polling the net context failed. */ +#define MBEDTLS_ERR_NET_BAD_INPUT_DATA -0x0049 /**< Input invalid. */ #define MBEDTLS_NET_LISTEN_BACKLOG 10 /**< The backlog that listen() should use. */ #define MBEDTLS_NET_PROTO_TCP 0 /**< The TCP transport protocol */ #define MBEDTLS_NET_PROTO_UDP 1 /**< The UDP transport protocol */ +#define MBEDTLS_NET_POLL_READ 1 /**< Used in \c mbedtls_net_poll to check for pending data */ +#define MBEDTLS_NET_POLL_WRITE 2 /**< Used in \c mbedtls_net_poll to check if write possible */ + #ifdef __cplusplus extern "C" { #endif @@ -63,7 +84,7 @@ extern "C" { * (eg two file descriptors for combined IPv4 + IPv6 support, or additional * structures for hand-made UDP demultiplexing). */ -typedef struct +typedef struct mbedtls_net_context { int fd; /**< The underlying file descriptor */ } @@ -133,6 +154,29 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, mbedtls_net_context *client_ctx, void *client_ip, size_t buf_size, size_t *ip_len ); +/** + * \brief Check and wait for the context to be ready for read/write + * + * \param ctx Socket to check + * \param rw Bitflag composed of MBEDTLS_NET_POLL_READ and + * MBEDTLS_NET_POLL_WRITE specifying the events + * to wait for: + * - If MBEDTLS_NET_POLL_READ is set, the function + * will return as soon as the net context is available + * for reading. + * - If MBEDTLS_NET_POLL_WRITE is set, the function + * will return as soon as the net context is available + * for writing. + * \param timeout Maximal amount of time to wait before returning, + * in milliseconds. If \c timeout is zero, the + * function returns immediately. If \c timeout is + * -1u, the function blocks potentially indefinitely. + * + * \return Bitmask composed of MBEDTLS_NET_POLL_READ/WRITE + * on success or timeout, or a negative return code otherwise. + */ +int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout ); + /** * \brief Set the socket blocking * diff --git a/app/include/mbedtls/nist_kw.h b/app/include/mbedtls/nist_kw.h new file mode 100644 index 0000000000..3b67b59cd2 --- /dev/null +++ b/app/include/mbedtls/nist_kw.h @@ -0,0 +1,184 @@ +/** + * \file nist_kw.h + * + * \brief This file provides an API for key wrapping (KW) and key wrapping with + * padding (KWP) as defined in NIST SP 800-38F. + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * + * Key wrapping specifies a deterministic authenticated-encryption mode + * of operation, according to NIST SP 800-38F: Recommendation for + * Block Cipher Modes of Operation: Methods for Key Wrapping. Its + * purpose is to protect cryptographic keys. + * + * Its equivalent is RFC 3394 for KW, and RFC 5649 for KWP. + * https://tools.ietf.org/html/rfc3394 + * https://tools.ietf.org/html/rfc5649 + * + */ +/* + * Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_NIST_KW_H +#define MBEDTLS_NIST_KW_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + MBEDTLS_KW_MODE_KW = 0, + MBEDTLS_KW_MODE_KWP = 1 +} mbedtls_nist_kw_mode_t; + +#if !defined(MBEDTLS_NIST_KW_ALT) +// Regular implementation +// + +/** + * \brief The key wrapping context-type definition. The key wrapping context is passed + * to the APIs called. + * + * \note The definition of this type may change in future library versions. + * Don't make any assumptions on this context! + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx; /*!< The cipher context used. */ +} mbedtls_nist_kw_context; + +#else /* MBEDTLS_NIST_key wrapping_ALT */ +#include "nist_kw_alt.h" +#endif /* MBEDTLS_NIST_KW_ALT */ + +/** + * \brief This function initializes the specified key wrapping context + * to make references valid and prepare the context + * for mbedtls_nist_kw_setkey() or mbedtls_nist_kw_free(). + * + * \param ctx The key wrapping context to initialize. + * + */ +void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx ); + +/** + * \brief This function initializes the key wrapping context set in the + * \p ctx parameter and sets the encryption key. + * + * \param ctx The key wrapping context. + * \param cipher The 128-bit block cipher to use. Only AES is supported. + * \param key The Key Encryption Key (KEK). + * \param keybits The KEK size in bits. This must be acceptable by the cipher. + * \param is_wrap Specify whether the operation within the context is wrapping or unwrapping + * + * \return \c 0 on success. + * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for any invalid input. + * \return \c MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE for 128-bit block ciphers + * which are not supported. + * \return cipher-specific error code on failure of the underlying cipher. + */ +int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits, + const int is_wrap ); + +/** + * \brief This function releases and clears the specified key wrapping context + * and underlying cipher sub-context. + * + * \param ctx The key wrapping context to clear. + */ +void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx ); + +/** + * \brief This function encrypts a buffer using key wrapping. + * + * \param ctx The key wrapping context to use for encryption. + * \param mode The key wrapping mode to use (MBEDTLS_KW_MODE_KW or MBEDTLS_KW_MODE_KWP) + * \param input The buffer holding the input data. + * \param in_len The length of the input data in Bytes. + * The input uses units of 8 Bytes called semiblocks. + *
  • For KW mode: a multiple of 8 bytes between 16 and 2^57-8 inclusive.
  • + *
  • For KWP mode: any length between 1 and 2^32-1 inclusive.
+ * \param[out] output The buffer holding the output data. + *
  • For KW mode: Must be at least 8 bytes larger than \p in_len.
  • + *
  • For KWP mode: Must be at least 8 bytes larger rounded up to a multiple of + * 8 bytes for KWP (15 bytes at most).
+ * \param[out] out_len The number of bytes written to the output buffer. \c 0 on failure. + * \param[in] out_size The capacity of the output buffer. + * + * \return \c 0 on success. + * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for invalid input length. + * \return cipher-specific error code on failure of the underlying cipher. + */ +int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx, mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t* out_len, size_t out_size ); + +/** + * \brief This function decrypts a buffer using key wrapping. + * + * \param ctx The key wrapping context to use for decryption. + * \param mode The key wrapping mode to use (MBEDTLS_KW_MODE_KW or MBEDTLS_KW_MODE_KWP) + * \param input The buffer holding the input data. + * \param in_len The length of the input data in Bytes. + * The input uses units of 8 Bytes called semiblocks. + * The input must be a multiple of semiblocks. + *
  • For KW mode: a multiple of 8 bytes between 24 and 2^57 inclusive.
  • + *
  • For KWP mode: a multiple of 8 bytes between 16 and 2^32 inclusive.
+ * \param[out] output The buffer holding the output data. + * The output buffer's minimal length is 8 bytes shorter than \p in_len. + * \param[out] out_len The number of bytes written to the output buffer. \c 0 on failure. + * For KWP mode, the length could be up to 15 bytes shorter than \p in_len, + * depending on how much padding was added to the data. + * \param[in] out_size The capacity of the output buffer. + * + * \return \c 0 on success. + * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for invalid input length. + * \return \c MBEDTLS_ERR_CIPHER_AUTH_FAILED for verification failure of the ciphertext. + * \return cipher-specific error code on failure of the underlying cipher. + */ +int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t* out_len, size_t out_size); + + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief The key wrapping checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_nist_kw_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_NIST_KW_H */ diff --git a/app/include/mbedtls/oid.h b/app/include/mbedtls/oid.h index 408645ece7..6fbd018aaa 100644 --- a/app/include/mbedtls/oid.h +++ b/app/include/mbedtls/oid.h @@ -97,6 +97,8 @@ /* ISO arc for standard certificate and CRL extensions */ #define MBEDTLS_OID_ID_CE MBEDTLS_OID_ISO_CCITT_DS "\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ +#define MBEDTLS_OID_NIST_ALG MBEDTLS_OID_GOV "\x03\x04" /** { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) */ + /** * Private Internet Extensions * { iso(1) identified-organization(3) dod(6) internet(1) @@ -219,12 +221,12 @@ #define MBEDTLS_OID_DIGEST_ALG_MD4 MBEDTLS_OID_RSA_COMPANY "\x02\x04" /**< id-mbedtls_md4 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 4 } */ #define MBEDTLS_OID_DIGEST_ALG_MD5 MBEDTLS_OID_RSA_COMPANY "\x02\x05" /**< id-mbedtls_md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } */ #define MBEDTLS_OID_DIGEST_ALG_SHA1 MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_SHA1 /**< id-mbedtls_sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */ -#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_GOV "\x03\x04\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */ -#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_GOV "\x03\x04\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_NIST_ALG "\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_NIST_ALG "\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */ -#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_GOV "\x03\x04\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_NIST_ALG "\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */ -#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_GOV "\x03\x04\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_NIST_ALG "\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */ #define MBEDTLS_OID_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */ @@ -241,7 +243,20 @@ */ #define MBEDTLS_OID_DES_CBC MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_ALG "\x07" /**< desCBC OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 7 } */ #define MBEDTLS_OID_DES_EDE3_CBC MBEDTLS_OID_RSA_COMPANY "\x03\x07" /**< des-ede3-cbc OBJECT IDENTIFIER ::= { iso(1) member-body(2) -- us(840) rsadsi(113549) encryptionAlgorithm(3) 7 } */ +#define MBEDTLS_OID_AES MBEDTLS_OID_NIST_ALG "\x01" /** aes OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) 1 } */ +/* + * Key Wrapping algorithms + */ +/* + * RFC 5649 + */ +#define MBEDTLS_OID_AES128_KW MBEDTLS_OID_AES "\x05" /** id-aes128-wrap OBJECT IDENTIFIER ::= { aes 5 } */ +#define MBEDTLS_OID_AES128_KWP MBEDTLS_OID_AES "\x08" /** id-aes128-wrap-pad OBJECT IDENTIFIER ::= { aes 8 } */ +#define MBEDTLS_OID_AES192_KW MBEDTLS_OID_AES "\x19" /** id-aes192-wrap OBJECT IDENTIFIER ::= { aes 25 } */ +#define MBEDTLS_OID_AES192_KWP MBEDTLS_OID_AES "\x1c" /** id-aes192-wrap-pad OBJECT IDENTIFIER ::= { aes 28 } */ +#define MBEDTLS_OID_AES256_KW MBEDTLS_OID_AES "\x2d" /** id-aes256-wrap OBJECT IDENTIFIER ::= { aes 45 } */ +#define MBEDTLS_OID_AES256_KWP MBEDTLS_OID_AES "\x30" /** id-aes256-wrap-pad OBJECT IDENTIFIER ::= { aes 48 } */ /* * PKCS#5 OIDs */ @@ -388,7 +403,8 @@ extern "C" { /** * \brief Base OID descriptor structure */ -typedef struct { +typedef struct mbedtls_oid_descriptor_t +{ const char *asn1; /*!< OID ASN.1 representation */ size_t asn1_len; /*!< length of asn1 */ const char *name; /*!< official name (e.g. from RFC) */ diff --git a/app/include/mbedtls/padlock.h b/app/include/mbedtls/padlock.h index 677936ebf8..721a5d4930 100644 --- a/app/include/mbedtls/padlock.h +++ b/app/include/mbedtls/padlock.h @@ -3,6 +3,9 @@ * * \brief VIA PadLock ACE for HW encryption/decryption supported by some * processors + * + * \warning These functions are only for internal use by other library + * functions; you must not call them directly. */ /* * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved @@ -25,6 +28,12 @@ #ifndef MBEDTLS_PADLOCK_H #define MBEDTLS_PADLOCK_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "aes.h" #define MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */ @@ -50,14 +59,17 @@ #define MBEDTLS_PADLOCK_PHE 0x0C00 #define MBEDTLS_PADLOCK_PMM 0x3000 -#define MBEDTLS_PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) x & ~15)) +#define MBEDTLS_PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) (x) & ~15)) #ifdef __cplusplus extern "C" { #endif /** - * \brief PadLock detection routine + * \brief Internal PadLock detection routine + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param feature The feature to detect * @@ -66,7 +78,10 @@ extern "C" { int mbedtls_padlock_has_support( int feature ); /** - * \brief PadLock AES-ECB block en(de)cryption + * \brief Internal PadLock AES-ECB block en(de)cryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param ctx AES context * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT @@ -76,12 +91,15 @@ int mbedtls_padlock_has_support( int feature ); * \return 0 if success, 1 if operation failed */ int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ); + int mode, + const unsigned char input[16], + unsigned char output[16] ); /** - * \brief PadLock AES-CBC buffer en(de)cryption + * \brief Internal PadLock AES-CBC buffer en(de)cryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. * * \param ctx AES context * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT @@ -93,11 +111,11 @@ int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, * \return 0 if success, 1 if operation failed */ int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); #ifdef __cplusplus } diff --git a/app/include/mbedtls/pem.h b/app/include/mbedtls/pem.h index 2cf4c0a709..a29e9ce300 100644 --- a/app/include/mbedtls/pem.h +++ b/app/include/mbedtls/pem.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_PEM_H #define MBEDTLS_PEM_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include /** @@ -51,7 +57,7 @@ extern "C" { /** * \brief PEM context structure */ -typedef struct +typedef struct mbedtls_pem_context { unsigned char *buf; /*!< buffer for decoded data */ size_t buflen; /*!< length of the buffer */ diff --git a/app/include/mbedtls/pk.h b/app/include/mbedtls/pk.h index ee06b2fd20..136427503a 100644 --- a/app/include/mbedtls/pk.h +++ b/app/include/mbedtls/pk.h @@ -64,6 +64,8 @@ #define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */ #define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */ #define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The buffer contains a valid signature followed by more data. */ + +/* MBEDTLS_ERR_PK_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_PK_HW_ACCEL_FAILED -0x3880 /**< PK hardware accelerator failed. */ #ifdef __cplusplus @@ -87,7 +89,7 @@ typedef enum { * \brief Options for RSASSA-PSS signature verification. * See \c mbedtls_rsa_rsassa_pss_verify_ext() */ -typedef struct +typedef struct mbedtls_pk_rsassa_pss_options { mbedtls_md_type_t mgf1_hash_id; int expected_salt_len; @@ -107,7 +109,7 @@ typedef enum /** * \brief Item to send to the debug module */ -typedef struct +typedef struct mbedtls_pk_debug_item { mbedtls_pk_debug_type type; const char *name; @@ -125,12 +127,26 @@ typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; /** * \brief Public key container */ -typedef struct +typedef struct mbedtls_pk_context { - const mbedtls_pk_info_t * pk_info; /**< Public key informations */ + const mbedtls_pk_info_t * pk_info; /**< Public key information */ void * pk_ctx; /**< Underlying public key context */ } mbedtls_pk_context; +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Context for resuming operations + */ +typedef struct +{ + const mbedtls_pk_info_t * pk_info; /**< Public key information */ + void * rs_ctx; /**< Underlying restart context */ +} mbedtls_pk_restart_ctx; +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ +/* Now we can declare functions that take a pointer to that */ +typedef void mbedtls_pk_restart_ctx; +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + #if defined(MBEDTLS_RSA_C) /** * Quick access to an RSA context inside a PK context. @@ -181,20 +197,45 @@ typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ); /** - * \brief Initialize a mbedtls_pk_context (as NONE) + * \brief Initialize a #mbedtls_pk_context (as NONE). + * + * \param ctx The context to initialize. + * This must not be \c NULL. */ void mbedtls_pk_init( mbedtls_pk_context *ctx ); /** - * \brief Free a mbedtls_pk_context + * \brief Free the components of a #mbedtls_pk_context. + * + * \param ctx The context to clear. It must have been initialized. + * If this is \c NULL, this function does nothing. */ void mbedtls_pk_free( mbedtls_pk_context *ctx ); +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context + * + * \param ctx The context to initialize. + * This must not be \c NULL. + */ +void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx ); + +/** + * \brief Free the components of a restart context + * + * \param ctx The context to clear. It must have been initialized. + * If this is \c NULL, this function does nothing. + */ +void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + /** * \brief Initialize a PK context with the information given * and allocates the type-specific PK subcontext. * - * \param ctx Context to initialize. Must be empty (type NONE). + * \param ctx Context to initialize. It must not have been set + * up yet (type #MBEDTLS_PK_NONE). * \param info Information to use * * \return 0 on success, @@ -210,7 +251,8 @@ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); /** * \brief Initialize an RSA-alt context * - * \param ctx Context to initialize. Must be empty (type NONE). + * \param ctx Context to initialize. It must not have been set + * up yet (type #MBEDTLS_PK_NONE). * \param key RSA key pointer * \param decrypt_func Decryption function * \param sign_func Signing function @@ -230,7 +272,7 @@ int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, /** * \brief Get the size in bits of the underlying key * - * \param ctx Context to use + * \param ctx The context to query. It must have been initialized. * * \return Key size in bits, or 0 on error */ @@ -238,7 +280,8 @@ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ); /** * \brief Get the length in bytes of the underlying key - * \param ctx Context to use + * + * \param ctx The context to query. It must have been initialized. * * \return Key length in bytes, or 0 on error */ @@ -250,18 +293,21 @@ static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) /** * \brief Tell if a context can do the operation given by type * - * \param ctx Context to test - * \param type Target type + * \param ctx The context to query. It must have been initialized. + * \param type The desired type. * - * \return 0 if context can't do the operations, - * 1 otherwise. + * \return 1 if the context can do operations on the given type. + * \return 0 if the context cannot do the operations on the given + * type. This is always the case for a context that has + * been initialized but not set up, or that has been + * cleared with mbedtls_pk_free(). */ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); /** * \brief Verify signature (including padding if relevant). * - * \param ctx PK context to use + * \param ctx The PK context to use. It must have been set up. * \param md_alg Hash algorithm used (see notes) * \param hash Hash of the message to sign * \param hash_len Hash length or 0 (see notes) @@ -286,13 +332,39 @@ int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len ); +/** + * \brief Restartable version of \c mbedtls_pk_verify() + * + * \note Performs the same job as \c mbedtls_pk_verify(), but can + * return early and restart according to the limit set with + * \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC + * operations. For RSA, same as \c mbedtls_pk_verify(). + * + * \param ctx The PK context to use. It must have been set up. + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * \param rs_ctx Restart context (NULL to disable restart) + * + * \return See \c mbedtls_pk_verify(), or + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + */ +int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + mbedtls_pk_restart_ctx *rs_ctx ); + /** * \brief Verify signature, with options. * (Includes verification of the padding depending on type.) * * \param type Signature type (inc. possible padding type) to verify * \param options Pointer to type-specific options, or NULL - * \param ctx PK context to use + * \param ctx The PK context to use. It must have been set up. * \param md_alg Hash algorithm used (see notes) * \param hash Hash of the message to sign * \param hash_len Hash length or 0 (see notes) @@ -323,7 +395,8 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, /** * \brief Make signature, including padding if relevant. * - * \param ctx PK context to use - must hold a private key + * \param ctx The PK context to use. It must have been set up + * with a private key. * \param md_alg Hash algorithm used (see notes) * \param hash Hash of the message to sign * \param hash_len Hash length or 0 (see notes) @@ -343,16 +416,55 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, * * \note For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0. * For ECDSA, md_alg may never be MBEDTLS_MD_NONE. + * + * \note In order to ensure enough space for the signature, the + * \p sig buffer size must be of at least + * `max(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE)` bytes. */ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t *sig_len, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +/** + * \brief Restartable version of \c mbedtls_pk_sign() + * + * \note Performs the same job as \c mbedtls_pk_sign(), but can + * return early and restart according to the limit set with + * \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC + * operations. For RSA, same as \c mbedtls_pk_sign(). + * + * \note In order to ensure enough space for the signature, the + * \p sig buffer size must be of at least + * `max(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE)` bytes. + * + * \param ctx The PK context to use. It must have been set up + * with a private key. + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Place to write the signature + * \param sig_len Number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param rs_ctx Restart context (NULL to disable restart) + * + * \return See \c mbedtls_pk_sign(), or + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + */ +int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_pk_restart_ctx *rs_ctx ); + /** * \brief Decrypt message (including padding if relevant). * - * \param ctx PK context to use - must hold a private key + * \param ctx The PK context to use. It must have been set up + * with a private key. * \param input Input to decrypt * \param ilen Input size * \param output Decrypted output @@ -373,7 +485,7 @@ int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, /** * \brief Encrypt message (including padding if relevant). * - * \param ctx PK context to use + * \param ctx The PK context to use. It must have been set up. * \param input Message to encrypt * \param ilen Message size * \param output Encrypted output @@ -404,7 +516,7 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte /** * \brief Export debug information * - * \param ctx Context to use + * \param ctx The PK context to use. It must have been initialized. * \param items Place to write debug items * * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA @@ -414,7 +526,7 @@ int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *item /** * \brief Access the type name * - * \param ctx Context to use + * \param ctx The PK context to use. It must have been initialized. * * \return Type name on success, or "invalid PK" */ @@ -423,9 +535,10 @@ const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); /** * \brief Get the key type * - * \param ctx Context to use + * \param ctx The PK context to use. It must have been initialized. * - * \return Type on success, or MBEDTLS_PK_NONE + * \return Type on success. + * \return #MBEDTLS_PK_NONE for a context that has not been set up. */ mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); @@ -434,12 +547,22 @@ mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); /** * \brief Parse a private key in PEM or DER format * - * \param ctx key to be initialized - * \param key input buffer - * \param keylen size of the buffer - * (including the terminating null byte for PEM data) - * \param pwd password for decryption (optional) - * \param pwdlen size of the password + * \param ctx The PK context to fill. It must have been initialized + * but not set up. + * \param key Input buffer to parse. + * The buffer must contain the input exactly, with no + * extra trailing material. For PEM, the buffer must + * contain a null-terminated string. + * \param keylen Size of \b key in bytes. + * For PEM data, this includes the terminating null byte, + * so \p keylen must be equal to `strlen(key) + 1`. + * \param pwd Optional password for decryption. + * Pass \c NULL if expecting a non-encrypted key. + * Pass a string of \p pwdlen bytes if expecting an encrypted + * key; a non-encrypted key will also be accepted. + * The empty password is not supported. + * \param pwdlen Size of the password in bytes. + * Ignored if \p pwd is \c NULL. * * \note On entry, ctx must be empty, either freshly initialised * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a @@ -457,10 +580,15 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *ctx, /** * \brief Parse a public key in PEM or DER format * - * \param ctx key to be initialized - * \param key input buffer - * \param keylen size of the buffer - * (including the terminating null byte for PEM data) + * \param ctx The PK context to fill. It must have been initialized + * but not set up. + * \param key Input buffer to parse. + * The buffer must contain the input exactly, with no + * extra trailing material. For PEM, the buffer must + * contain a null-terminated string. + * \param keylen Size of \b key in bytes. + * For PEM data, this includes the terminating null byte, + * so \p keylen must be equal to `strlen(key) + 1`. * * \note On entry, ctx must be empty, either freshly initialised * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a @@ -478,9 +606,14 @@ int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, /** * \brief Load and parse a private key * - * \param ctx key to be initialized + * \param ctx The PK context to fill. It must have been initialized + * but not set up. * \param path filename to read the private key from - * \param password password to decrypt the file (can be NULL) + * \param password Optional password to decrypt the file. + * Pass \c NULL if expecting a non-encrypted key. + * Pass a null-terminated string if expecting an encrypted + * key; a non-encrypted key will also be accepted. + * The empty password is not supported. * * \note On entry, ctx must be empty, either freshly initialised * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a @@ -497,7 +630,8 @@ int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, /** * \brief Load and parse a public key * - * \param ctx key to be initialized + * \param ctx The PK context to fill. It must have been initialized + * but not set up. * \param path filename to read the public key from * * \note On entry, ctx must be empty, either freshly initialised @@ -520,7 +654,7 @@ int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) * return value to determine where you should start * using the buffer * - * \param ctx private to write away + * \param ctx PK context which must contain a valid private key. * \param buf buffer to write to * \param size size of the buffer * @@ -535,7 +669,7 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_ * return value to determine where you should start * using the buffer * - * \param ctx public key to write away + * \param ctx PK context which must contain a valid public or private key. * \param buf buffer to write to * \param size size of the buffer * @@ -548,9 +682,10 @@ int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *ctx, unsigned char *buf, si /** * \brief Write a public key to a PEM string * - * \param ctx public key to write away - * \param buf buffer to write to - * \param size size of the buffer + * \param ctx PK context which must contain a valid public or private key. + * \param buf Buffer to write to. The output includes a + * terminating null byte. + * \param size Size of the buffer in bytes. * * \return 0 if successful, or a specific error code */ @@ -559,9 +694,10 @@ int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, si /** * \brief Write a private key to a PKCS#1 or SEC1 PEM string * - * \param ctx private to write away - * \param buf buffer to write to - * \param size size of the buffer + * \param ctx PK context which must contain a valid private key. + * \param buf Buffer to write to. The output includes a + * terminating null byte. + * \param size Size of the buffer in bytes. * * \return 0 if successful, or a specific error code */ @@ -580,7 +716,8 @@ int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_ * * \param p the position in the ASN.1 data * \param end end of the buffer - * \param pk the key to fill + * \param pk The PK context to fill. It must have been initialized + * but not set up. * * \return 0 if successful, or a specific PK error code */ @@ -595,7 +732,7 @@ int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, * * \param p reference to current position pointer * \param start start of the buffer (for bounds-checking) - * \param key public key to write away + * \param key PK context which must contain a valid public or private key. * * \return the length written or a negative error code */ diff --git a/app/include/mbedtls/pk_internal.h b/app/include/mbedtls/pk_internal.h index 3dae0fc5b2..48b7a5f7bf 100644 --- a/app/include/mbedtls/pk_internal.h +++ b/app/include/mbedtls/pk_internal.h @@ -59,6 +59,21 @@ struct mbedtls_pk_info_t int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /** Verify signature (restartable) */ + int (*verify_rs_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ); + + /** Make signature (restartable) */ + int (*sign_rs_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, void *rs_ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + /** Decrypt message */ int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, @@ -80,6 +95,14 @@ struct mbedtls_pk_info_t /** Free the given context */ void (*ctx_free_func)( void *ctx ); +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /** Allocate the restart context */ + void * (*rs_alloc_func)( void ); + + /** Free the restart context */ + void (*rs_free_func)( void *rs_ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + /** Interface with the debug module */ void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); diff --git a/app/include/mbedtls/pkcs11.h b/app/include/mbedtls/pkcs11.h index bf65c55a79..02427ddc1e 100644 --- a/app/include/mbedtls/pkcs11.h +++ b/app/include/mbedtls/pkcs11.h @@ -50,7 +50,8 @@ extern "C" { /** * Context for PKCS #11 private keys. */ -typedef struct { +typedef struct mbedtls_pkcs11_context +{ pkcs11h_certificate_t pkcs11h_cert; int len; } mbedtls_pkcs11_context; diff --git a/app/include/mbedtls/pkcs5.h b/app/include/mbedtls/pkcs5.h index f201250046..c92185f7a6 100644 --- a/app/include/mbedtls/pkcs5.h +++ b/app/include/mbedtls/pkcs5.h @@ -91,6 +91,8 @@ int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *p unsigned int iteration_count, uint32_t key_length, unsigned char *output ); +#if defined(MBEDTLS_SELF_TEST) + /** * \brief Checkup routine * @@ -98,6 +100,8 @@ int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *p */ int mbedtls_pkcs5_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/platform.h b/app/include/mbedtls/platform.h index a520e8f693..1f907d6fed 100644 --- a/app/include/mbedtls/platform.h +++ b/app/include/mbedtls/platform.h @@ -1,7 +1,16 @@ /** * \file platform.h * - * \brief The Mbed TLS platform abstraction layer. + * \brief This file contains the definitions and functions of the + * Mbed TLS platform abstraction layer. + * + * The platform abstraction layer removes the need for the library + * to directly link to standard C library functions or operating + * system services, making the library easier to port and embed. + * Application developers and users of the library can provide their own + * implementations of these functions, or implementations specific to + * their platform, which can be statically linked to the library or + * dynamically configured at runtime. */ /* * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved @@ -34,6 +43,9 @@ #include "platform_time.h" #endif +#define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED -0x0070 /**< Hardware accelerator failed */ +#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */ + #ifdef __cplusplus extern "C" { #endif @@ -102,7 +114,7 @@ extern "C" { /* \} name SECTION: Module settings */ /* - * The function pointers for calloc and free + * The function pointers for calloc and free. */ #if defined(MBEDTLS_PLATFORM_MEMORY) #if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \ @@ -112,11 +124,12 @@ extern "C" { #else /* For size_t */ #include -extern void * (*mbedtls_calloc)( size_t n, size_t size ); -extern void (*mbedtls_free)( void *ptr ); +extern void *mbedtls_calloc( size_t n, size_t size ); +extern void mbedtls_free( void *ptr ); /** - * \brief This function allows configuring custom memory-management functions. + * \brief This function dynamically sets the memory-management + * functions used by the library, during runtime. * * \param calloc_func The \c calloc function implementation. * \param free_func The \c free function implementation. @@ -140,7 +153,9 @@ int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... ); /** - * \brief This function allows configuring a custom \p fprintf function pointer. + * \brief This function dynamically configures the fprintf + * function that is called when the + * mbedtls_fprintf() function is invoked by the library. * * \param fprintf_func The \c fprintf function implementation. * @@ -163,8 +178,9 @@ int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char extern int (*mbedtls_printf)( const char *format, ... ); /** - * \brief This function allows configuring a custom \c printf function - * pointer. + * \brief This function dynamically configures the snprintf + * function that is called when the mbedtls_snprintf() + * function is invoked by the library. * * \param printf_func The \c printf function implementation. * @@ -197,12 +213,12 @@ int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ); extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... ); /** - * \brief This function allows configuring a custom \c snprintf function - * pointer. + * \brief This function allows configuring a custom + * \c snprintf function pointer. * * \param snprintf_func The \c snprintf function implementation. * - * \return \c 0 on success. + * \return \c 0 on success. */ int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, const char * format, ... ) ); @@ -211,8 +227,8 @@ int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, #define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO #define mbedtls_vsnprintf MBEDTLS_PLATFORM_VSNPRINTF_MACRO #else -#define mbedtls_snprintf snprintf #define mbedtls_vsnprintf vsnprintf +#define mbedtls_snprintf MBEDTLS_PLATFORM_STD_SNPRINTF #endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */ #endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ @@ -223,12 +239,13 @@ int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, extern void (*mbedtls_exit)( int status ); /** - * \brief This function allows configuring a custom \c exit function - * pointer. + * \brief This function dynamically configures the exit + * function that is called when the mbedtls_exit() + * function is invoked by the library. * * \param exit_func The \c exit function implementation. * - * \return \c 0 on success. + * \return \c 0 on success. */ int mbedtls_platform_set_exit( void (*exit_func)( int status ) ); #else @@ -303,8 +320,9 @@ int mbedtls_platform_set_nv_seed( * \note This structure may be used to assist platform-specific * setup or teardown operations. */ -typedef struct { - char dummy; /**< Placeholder member, as empty structs are not portable. */ +typedef struct mbedtls_platform_context +{ + char dummy; /**< A placeholder member, as empty structs are not portable. */ } mbedtls_platform_context; @@ -313,33 +331,34 @@ mbedtls_platform_context; #endif /* !MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */ /** - * \brief This function performs any platform initialization operations. + * \brief This function performs any platform-specific initialization + * operations. * - * \param ctx The Mbed TLS context. + * \note This function should be called before any other library functions. * - * \return \c 0 on success. - * - * \note This function is intended to allow platform-specific initialization, - * and should be called before any other library functions. Its - * implementation is platform-specific, and unless + * Its implementation is platform-specific, and unless * platform-specific code is provided, it does nothing. * - * Its use and whether it is necessary to call it is dependent on the - * platform. + * \note The usage and necessity of this function is dependent on the platform. + * + * \param ctx The platform context. + * + * \return \c 0 on success. */ int mbedtls_platform_setup( mbedtls_platform_context *ctx ); /** * \brief This function performs any platform teardown operations. * - * \param ctx The Mbed TLS context. - * * \note This function should be called after every other Mbed TLS module * has been correctly freed using the appropriate free function. + * * Its implementation is platform-specific, and unless * platform-specific code is provided, it does nothing. * - * Its use and whether it is necessary to call it is dependent on the - * platform. + * \note The usage and necessity of this function is dependent on the platform. + * + * \param ctx The platform context. + * */ void mbedtls_platform_teardown( mbedtls_platform_context *ctx ); diff --git a/app/include/mbedtls/platform_util.h b/app/include/mbedtls/platform_util.h new file mode 100644 index 0000000000..09d0965182 --- /dev/null +++ b/app/include/mbedtls/platform_util.h @@ -0,0 +1,196 @@ +/** + * \file platform_util.h + * + * \brief Common and shared functions used by multiple modules in the Mbed TLS + * library. + */ +/* + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_UTIL_H +#define MBEDTLS_PLATFORM_UTIL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#if defined(MBEDTLS_HAVE_TIME_DATE) +#include "platform_time.h" +#include +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_CHECK_PARAMS) + +#if defined(MBEDTLS_CHECK_PARAMS_ASSERT) +/* Allow the user to define MBEDTLS_PARAM_FAILED to something like assert + * (which is what our config.h suggests). */ +#include +#endif /* MBEDTLS_CHECK_PARAMS_ASSERT */ + +#if defined(MBEDTLS_PARAM_FAILED) +/** An alternative definition of MBEDTLS_PARAM_FAILED has been set in config.h. + * + * This flag can be used to check whether it is safe to assume that + * MBEDTLS_PARAM_FAILED() will expand to a call to mbedtls_param_failed(). + */ +#define MBEDTLS_PARAM_FAILED_ALT + +#elif defined(MBEDTLS_CHECK_PARAMS_ASSERT) +#define MBEDTLS_PARAM_FAILED( cond ) assert( cond ) +#define MBEDTLS_PARAM_FAILED_ALT + +#else /* MBEDTLS_PARAM_FAILED */ +#define MBEDTLS_PARAM_FAILED( cond ) \ + mbedtls_param_failed( #cond, __FILE__, __LINE__ ) + +/** + * \brief User supplied callback function for parameter validation failure. + * See #MBEDTLS_CHECK_PARAMS for context. + * + * This function will be called unless an alternative treatement + * is defined through the #MBEDTLS_PARAM_FAILED macro. + * + * This function can return, and the operation will be aborted, or + * alternatively, through use of setjmp()/longjmp() can resume + * execution in the application code. + * + * \param failure_condition The assertion that didn't hold. + * \param file The file where the assertion failed. + * \param line The line in the file where the assertion failed. + */ +void mbedtls_param_failed( const char *failure_condition, + const char *file, + int line ); +#endif /* MBEDTLS_PARAM_FAILED */ + +/* Internal macro meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) \ + do { \ + if( !(cond) ) \ + { \ + MBEDTLS_PARAM_FAILED( cond ); \ + return( ret ); \ + } \ + } while( 0 ) + +/* Internal macro meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE( cond ) \ + do { \ + if( !(cond) ) \ + { \ + MBEDTLS_PARAM_FAILED( cond ); \ + return; \ + } \ + } while( 0 ) + +#else /* MBEDTLS_CHECK_PARAMS */ + +/* Internal macros meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) do { } while( 0 ) +#define MBEDTLS_INTERNAL_VALIDATE( cond ) do { } while( 0 ) + +#endif /* MBEDTLS_CHECK_PARAMS */ + +/* Internal helper macros for deprecating API constants. */ +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +/* Deliberately don't (yet) export MBEDTLS_DEPRECATED here + * to avoid conflict with other headers which define and use + * it, too. We might want to move all these definitions here at + * some point for uniformity. */ +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +MBEDTLS_DEPRECATED typedef char const * mbedtls_deprecated_string_constant_t; +#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL ) \ + ( (mbedtls_deprecated_string_constant_t) ( VAL ) ) +MBEDTLS_DEPRECATED typedef int mbedtls_deprecated_numeric_constant_t; +#define MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( VAL ) \ + ( (mbedtls_deprecated_numeric_constant_t) ( VAL ) ) +#undef MBEDTLS_DEPRECATED +#else /* MBEDTLS_DEPRECATED_WARNING */ +#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL ) VAL +#define MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( VAL ) VAL +#endif /* MBEDTLS_DEPRECATED_WARNING */ +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Securely zeroize a buffer + * + * The function is meant to wipe the data contained in a buffer so + * that it can no longer be recovered even if the program memory + * is later compromised. Call this function on sensitive data + * stored on the stack before returning from a function, and on + * sensitive data stored on the heap before freeing the heap + * object. + * + * It is extremely difficult to guarantee that calls to + * mbedtls_platform_zeroize() are not removed by aggressive + * compiler optimizations in a portable way. For this reason, Mbed + * TLS provides the configuration option + * MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for + * their platform and needs + * + * \param buf Buffer to be zeroized + * \param len Length of the buffer in bytes + * + */ +void mbedtls_platform_zeroize( void *buf, size_t len ); + +#if defined(MBEDTLS_HAVE_TIME_DATE) +/** + * \brief Platform-specific implementation of gmtime_r() + * + * The function is a thread-safe abstraction that behaves + * similarly to the gmtime_r() function from Unix/POSIX. + * + * Mbed TLS will try to identify the underlying platform and + * make use of an appropriate underlying implementation (e.g. + * gmtime_r() for POSIX and gmtime_s() for Windows). If this is + * not possible, then gmtime() will be used. In this case, calls + * from the library to gmtime() will be guarded by the mutex + * mbedtls_threading_gmtime_mutex if MBEDTLS_THREADING_C is + * enabled. It is recommended that calls from outside the library + * are also guarded by this mutex. + * + * If MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, then Mbed TLS will + * unconditionally use the alternative implementation for + * mbedtls_platform_gmtime_r() supplied by the user at compile time. + * + * \param tt Pointer to an object containing time (in seconds) since the + * epoch to be converted + * \param tm_buf Pointer to an object where the results will be stored + * + * \return Pointer to an object of type struct tm on success, otherwise + * NULL + */ +struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt, + struct tm *tm_buf ); +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PLATFORM_UTIL_H */ diff --git a/app/include/mbedtls/poly1305.h b/app/include/mbedtls/poly1305.h new file mode 100644 index 0000000000..f0ec44c968 --- /dev/null +++ b/app/include/mbedtls/poly1305.h @@ -0,0 +1,192 @@ +/** + * \file poly1305.h + * + * \brief This file contains Poly1305 definitions and functions. + * + * Poly1305 is a one-time message authenticator that can be used to + * authenticate messages. Poly1305-AES was created by Daniel + * Bernstein https://cr.yp.to/mac/poly1305-20050329.pdf The generic + * Poly1305 algorithm (not tied to AES) was also standardized in RFC + * 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_POLY1305_H +#define MBEDTLS_POLY1305_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA -0x0057 /**< Invalid input parameter(s). */ + +/* MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ +#define MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE -0x0059 /**< Feature not available. For example, s part of the API is not implemented. */ + +/* MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED -0x005B /**< Poly1305 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_POLY1305_ALT) + +typedef struct mbedtls_poly1305_context +{ + uint32_t r[4]; /** The value for 'r' (low 128 bits of the key). */ + uint32_t s[4]; /** The value for 's' (high 128 bits of the key). */ + uint32_t acc[5]; /** The accumulator number. */ + uint8_t queue[16]; /** The current partial block of data. */ + size_t queue_len; /** The number of bytes stored in 'queue'. */ +} +mbedtls_poly1305_context; + +#else /* MBEDTLS_POLY1305_ALT */ +#include "poly1305_alt.h" +#endif /* MBEDTLS_POLY1305_ALT */ + +/** + * \brief This function initializes the specified Poly1305 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by a call to + * \c mbedtls_poly1305_starts(), then one or more calls to + * \c mbedtls_poly1305_update(), then one call to + * \c mbedtls_poly1305_finish(), then finally + * \c mbedtls_poly1305_free(). + * + * \param ctx The Poly1305 context to initialize. This must + * not be \c NULL. + */ +void mbedtls_poly1305_init( mbedtls_poly1305_context *ctx ); + +/** + * \brief This function releases and clears the specified + * Poly1305 context. + * + * \param ctx The Poly1305 context to clear. This may be \c NULL, in which + * case this function is a no-op. If it is not \c NULL, it must + * point to an initialized Poly1305 context. + */ +void mbedtls_poly1305_free( mbedtls_poly1305_context *ctx ); + +/** + * \brief This function sets the one-time authentication key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param ctx The Poly1305 context to which the key should be bound. + * This must be initialized. + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_starts( mbedtls_poly1305_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This functions feeds an input buffer into an ongoing + * Poly1305 computation. + * + * It is called between \c mbedtls_cipher_poly1305_starts() and + * \c mbedtls_cipher_poly1305_finish(). + * It can be called repeatedly to process a stream of data. + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_update( mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function generates the Poly1305 Message + * Authentication Code (MAC). + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param mac The buffer to where the MAC is written. This must + * be a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_finish( mbedtls_poly1305_context *ctx, + unsigned char mac[16] ); + +/** + * \brief This function calculates the Poly1305 MAC of the input + * buffer with the provided key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * \param mac The buffer to where the MAC is written. This must be + * a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_mac( const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16] ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_poly1305_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_POLY1305_H */ diff --git a/app/include/mbedtls/ripemd160.h b/app/include/mbedtls/ripemd160.h index 3a8b50a621..b42f6d2a95 100644 --- a/app/include/mbedtls/ripemd160.h +++ b/app/include/mbedtls/ripemd160.h @@ -33,20 +33,22 @@ #include #include +/* MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED is deprecated and should not be used. + */ #define MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED -0x0031 /**< RIPEMD160 hardware accelerator failed */ -#if !defined(MBEDTLS_RIPEMD160_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_RIPEMD160_ALT) +// Regular implementation +// + /** * \brief RIPEMD-160 context structure */ -typedef struct +typedef struct mbedtls_ripemd160_context { uint32_t total[2]; /*!< number of bytes processed */ uint32_t state[5]; /*!< intermediate digest state */ @@ -54,6 +56,10 @@ typedef struct } mbedtls_ripemd160_context; +#else /* MBEDTLS_RIPEMD160_ALT */ +#include "ripemd160.h" +#endif /* MBEDTLS_RIPEMD160_ALT */ + /** * \brief Initialize RIPEMD-160 context * @@ -178,18 +184,6 @@ MBEDTLS_DEPRECATED void mbedtls_ripemd160_process( #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_RIPEMD160_ALT */ -#include "ripemd160_alt.h" -#endif /* MBEDTLS_RIPEMD160_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief Output = RIPEMD-160( input buffer ) * @@ -225,6 +219,8 @@ MBEDTLS_DEPRECATED void mbedtls_ripemd160( const unsigned char *input, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_SELF_TEST) + /** * \brief Checkup routine * @@ -232,6 +228,8 @@ MBEDTLS_DEPRECATED void mbedtls_ripemd160( const unsigned char *input, */ int mbedtls_ripemd160_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/rsa.h b/app/include/mbedtls/rsa.h index 5548f3c127..35bacd8763 100644 --- a/app/include/mbedtls/rsa.h +++ b/app/include/mbedtls/rsa.h @@ -1,11 +1,12 @@ /** * \file rsa.h * - * \brief The RSA public-key cryptosystem. + * \brief This file provides an API for the RSA public-key cryptosystem. * - * For more information, see Public-Key Cryptography Standards (PKCS) - * #1 v1.5: RSA Encryption and Public-Key Cryptography Standards - * (PKCS) #1 v2.1: RSA Cryptography Specifications. + * The RSA public-key cryptosystem is defined in Public-Key + * Cryptography Standards (PKCS) #1 v1.5: RSA Encryption + * and Public-Key Cryptography Standards (PKCS) #1 v2.1: + * RSA Cryptography Specifications. * */ /* @@ -54,7 +55,12 @@ #define MBEDTLS_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ #define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ #define MBEDTLS_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ + +/* MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION is deprecated and should not be used. + */ #define MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION -0x4500 /**< The implementation does not offer the requested operation, for example, because of security violations or lack of functionality. */ + +/* MBEDTLS_ERR_RSA_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_RSA_HW_ACCEL_FAILED -0x4580 /**< RSA hardware accelerator failed. */ /* @@ -63,8 +69,8 @@ #define MBEDTLS_RSA_PUBLIC 0 /**< Request private key operation. */ #define MBEDTLS_RSA_PRIVATE 1 /**< Request public key operation. */ -#define MBEDTLS_RSA_PKCS_V15 0 /**< Use PKCS-1 v1.5 encoding. */ -#define MBEDTLS_RSA_PKCS_V21 1 /**< Use PKCS-1 v2.1 encoding. */ +#define MBEDTLS_RSA_PKCS_V15 0 /**< Use PKCS#1 v1.5 encoding. */ +#define MBEDTLS_RSA_PKCS_V21 1 /**< Use PKCS#1 v2.1 encoding. */ #define MBEDTLS_RSA_SIGN 1 /**< Identifier for RSA signature operations. */ #define MBEDTLS_RSA_CRYPT 2 /**< Identifier for RSA encryption and decryption operations. */ @@ -76,14 +82,14 @@ * eg for alternative (PKCS#11) RSA implemenations in the PK layers. */ -#if !defined(MBEDTLS_RSA_ALT) -// Regular implementation -// - #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_RSA_ALT) +// Regular implementation +// + /** * \brief The RSA context structure. * @@ -91,29 +97,29 @@ extern "C" { * is deprecated. All manipulation should instead be done through * the public interface functions. */ -typedef struct +typedef struct mbedtls_rsa_context { int ver; /*!< Always 0.*/ size_t len; /*!< The size of \p N in Bytes. */ - mbedtls_mpi N; /*!< The public modulus. */ - mbedtls_mpi E; /*!< The public exponent. */ + mbedtls_mpi N; /*!< The public modulus. */ + mbedtls_mpi E; /*!< The public exponent. */ - mbedtls_mpi D; /*!< The private exponent. */ - mbedtls_mpi P; /*!< The first prime factor. */ - mbedtls_mpi Q; /*!< The second prime factor. */ + mbedtls_mpi D; /*!< The private exponent. */ + mbedtls_mpi P; /*!< The first prime factor. */ + mbedtls_mpi Q; /*!< The second prime factor. */ - mbedtls_mpi DP; /*!< \p D % (P - 1) */ - mbedtls_mpi DQ; /*!< \p D % (Q - 1) */ - mbedtls_mpi QP; /*!< 1 / (Q % P) */ + mbedtls_mpi DP; /*!< D % (P - 1). */ + mbedtls_mpi DQ; /*!< D % (Q - 1). */ + mbedtls_mpi QP; /*!< 1 / (Q % P). */ - mbedtls_mpi RN; /*!< cached R^2 mod \p N */ + mbedtls_mpi RN; /*!< cached R^2 mod N. */ - mbedtls_mpi RP; /*!< cached R^2 mod \p P */ - mbedtls_mpi RQ; /*!< cached R^2 mod \p Q */ + mbedtls_mpi RP; /*!< cached R^2 mod P. */ + mbedtls_mpi RQ; /*!< cached R^2 mod Q. */ - mbedtls_mpi Vi; /*!< The cached blinding value. */ - mbedtls_mpi Vf; /*!< The cached un-blinding value. */ + mbedtls_mpi Vi; /*!< The cached blinding value. */ + mbedtls_mpi Vf; /*!< The cached un-blinding value. */ int padding; /*!< Selects padding mode: #MBEDTLS_RSA_PKCS_V15 for 1.5 padding and @@ -128,47 +134,45 @@ typedef struct } mbedtls_rsa_context; +#else /* MBEDTLS_RSA_ALT */ +#include "rsa_alt.h" +#endif /* MBEDTLS_RSA_ALT */ + /** * \brief This function initializes an RSA context. * * \note Set padding to #MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP * encryption scheme and the RSASSA-PSS signature scheme. * - * \param ctx The RSA context to initialize. - * \param padding Selects padding mode: #MBEDTLS_RSA_PKCS_V15 or - * #MBEDTLS_RSA_PKCS_V21. - * \param hash_id The hash identifier of #mbedtls_md_type_t type, if - * \p padding is #MBEDTLS_RSA_PKCS_V21. - * * \note The \p hash_id parameter is ignored when using * #MBEDTLS_RSA_PKCS_V15 padding. * * \note The choice of padding mode is strictly enforced for private key * operations, since there might be security concerns in * mixing padding modes. For public key operations it is - * a default value, which can be overriden by calling specific + * a default value, which can be overridden by calling specific * \c rsa_rsaes_xxx or \c rsa_rsassa_xxx functions. * * \note The hash selected in \p hash_id is always used for OEAP * encryption. For PSS signatures, it is always used for - * making signatures, but can be overriden for verifying them. - * If set to #MBEDTLS_MD_NONE, it is always overriden. + * making signatures, but can be overridden for verifying them. + * If set to #MBEDTLS_MD_NONE, it is always overridden. + * + * \param ctx The RSA context to initialize. This must not be \c NULL. + * \param padding The padding mode to use. This must be either + * #MBEDTLS_RSA_PKCS_V15 or #MBEDTLS_RSA_PKCS_V21. + * \param hash_id The hash identifier of ::mbedtls_md_type_t type, if + * \p padding is #MBEDTLS_RSA_PKCS_V21. It is unused + * otherwise. */ void mbedtls_rsa_init( mbedtls_rsa_context *ctx, int padding, - int hash_id); + int hash_id ); /** * \brief This function imports a set of core parameters into an * RSA context. * - * \param ctx The initialized RSA context to store the parameters in. - * \param N The RSA modulus, or NULL. - * \param P The first prime factor of \p N, or NULL. - * \param Q The second prime factor of \p N, or NULL. - * \param D The private exponent, or NULL. - * \param E The public exponent, or NULL. - * * \note This function can be called multiple times for successive * imports, if the parameters are not simultaneously present. * @@ -184,7 +188,15 @@ void mbedtls_rsa_init( mbedtls_rsa_context *ctx, * \note The imported parameters are copied and need not be preserved * for the lifetime of the RSA context being set up. * - * \return \c 0 on success, or a non-zero error code on failure. + * \param ctx The initialized RSA context to store the parameters in. + * \param N The RSA modulus. This may be \c NULL. + * \param P The first prime factor of \p N. This may be \c NULL. + * \param Q The second prime factor of \p N. This may be \c NULL. + * \param D The private exponent. This may be \c NULL. + * \param E The public exponent. This may be \c NULL. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. */ int mbedtls_rsa_import( mbedtls_rsa_context *ctx, const mbedtls_mpi *N, @@ -195,18 +207,6 @@ int mbedtls_rsa_import( mbedtls_rsa_context *ctx, * \brief This function imports core RSA parameters, in raw big-endian * binary format, into an RSA context. * - * \param ctx The initialized RSA context to store the parameters in. - * \param N The RSA modulus, or NULL. - * \param N_len The Byte length of \p N, ignored if \p N == NULL. - * \param P The first prime factor of \p N, or NULL. - * \param P_len The Byte length of \p P, ignored if \p P == NULL. - * \param Q The second prime factor of \p N, or NULL. - * \param Q_len The Byte length of \p Q, ignored if \p Q == NULL. - * \param D The private exponent, or NULL. - * \param D_len The Byte length of \p D, ignored if \p D == NULL. - * \param E The public exponent, or NULL. - * \param E_len The Byte length of \p E, ignored if \p E == NULL. - * * \note This function can be called multiple times for successive * imports, if the parameters are not simultaneously present. * @@ -222,7 +222,20 @@ int mbedtls_rsa_import( mbedtls_rsa_context *ctx, * \note The imported parameters are copied and need not be preserved * for the lifetime of the RSA context being set up. * - * \return \c 0 on success, or a non-zero error code on failure. + * \param ctx The initialized RSA context to store the parameters in. + * \param N The RSA modulus. This may be \c NULL. + * \param N_len The Byte length of \p N; it is ignored if \p N == NULL. + * \param P The first prime factor of \p N. This may be \c NULL. + * \param P_len The Byte length of \p P; it ns ignored if \p P == NULL. + * \param Q The second prime factor of \p N. This may be \c NULL. + * \param Q_len The Byte length of \p Q; it is ignored if \p Q == NULL. + * \param D The private exponent. This may be \c NULL. + * \param D_len The Byte length of \p D; it is ignored if \p D == NULL. + * \param E The public exponent. This may be \c NULL. + * \param E_len The Byte length of \p E; it is ignored if \p E == NULL. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. */ int mbedtls_rsa_import_raw( mbedtls_rsa_context *ctx, unsigned char const *N, size_t N_len, @@ -250,17 +263,18 @@ int mbedtls_rsa_import_raw( mbedtls_rsa_context *ctx, * the RSA context can be used for RSA operations without * the risk of failure or crash. * - * \param ctx The initialized RSA context holding imported parameters. - * - * \return \c 0 on success, or #MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the - * attempted derivations failed. - * * \warning This function need not perform consistency checks * for the imported parameters. In particular, parameters that * are not needed by the implementation might be silently * discarded and left unchecked. To check the consistency * of the key material, see mbedtls_rsa_check_privkey(). * + * \param ctx The initialized RSA context holding imported parameters. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the attempted derivations + * failed. + * */ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ); @@ -273,7 +287,7 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ); * zero Bytes. * * Possible reasons for returning - * #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION:
    + * #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED:
      *
    • An alternative RSA implementation is in use, which * stores the key externally, and either cannot or should * not export it into RAM.
    • @@ -286,17 +300,22 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ); * the RSA context stays intact and remains usable. * * \param ctx The initialized RSA context. - * \param N The MPI to hold the RSA modulus, or NULL. - * \param P The MPI to hold the first prime factor of \p N, or NULL. - * \param Q The MPI to hold the second prime factor of \p N, or NULL. - * \param D The MPI to hold the private exponent, or NULL. - * \param E The MPI to hold the public exponent, or NULL. - * - * \return \c 0 on success, - * #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION if exporting the + * \param N The MPI to hold the RSA modulus. + * This may be \c NULL if this field need not be exported. + * \param P The MPI to hold the first prime factor of \p N. + * This may be \c NULL if this field need not be exported. + * \param Q The MPI to hold the second prime factor of \p N. + * This may be \c NULL if this field need not be exported. + * \param D The MPI to hold the private exponent. + * This may be \c NULL if this field need not be exported. + * \param E The MPI to hold the public exponent. + * This may be \c NULL if this field need not be exported. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED if exporting the * requested parameters cannot be done due to missing - * functionality or because of security policies, - * or a non-zero return code on any other failure. + * functionality or because of security policies. + * \return A non-zero return code on any other failure. * */ int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, @@ -313,7 +332,7 @@ int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, * zero Bytes. * * Possible reasons for returning - * #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION:
        + * #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED:
          *
        • An alternative RSA implementation is in use, which * stores the key externally, and either cannot or should * not export it into RAM.
        • @@ -324,28 +343,31 @@ int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, * If the function fails due to an unsupported operation, * the RSA context stays intact and remains usable. * + * \note The length parameters are ignored if the corresponding + * buffer pointers are NULL. + * * \param ctx The initialized RSA context. - * \param N The Byte array to store the RSA modulus, or NULL. + * \param N The Byte array to store the RSA modulus, + * or \c NULL if this field need not be exported. * \param N_len The size of the buffer for the modulus. - * \param P The Byte array to hold the first prime factor of \p N, or - * NULL. + * \param P The Byte array to hold the first prime factor of \p N, + * or \c NULL if this field need not be exported. * \param P_len The size of the buffer for the first prime factor. - * \param Q The Byte array to hold the second prime factor of \p N, or - NULL. + * \param Q The Byte array to hold the second prime factor of \p N, + * or \c NULL if this field need not be exported. * \param Q_len The size of the buffer for the second prime factor. - * \param D The Byte array to hold the private exponent, or NULL. + * \param D The Byte array to hold the private exponent, + * or \c NULL if this field need not be exported. * \param D_len The size of the buffer for the private exponent. - * \param E The Byte array to hold the public exponent, or NULL. + * \param E The Byte array to hold the public exponent, + * or \c NULL if this field need not be exported. * \param E_len The size of the buffer for the public exponent. * - * \note The length fields are ignored if the corresponding - * buffer pointers are NULL. - * - * \return \c 0 on success, - * #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION if exporting the + * \return \c 0 on success. + * \return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED if exporting the * requested parameters cannot be done due to missing - * functionality or because of security policies, - * or a non-zero return code on any other failure. + * functionality or because of security policies. + * \return A non-zero return code on any other failure. */ int mbedtls_rsa_export_raw( const mbedtls_rsa_context *ctx, unsigned char *N, size_t N_len, @@ -357,17 +379,21 @@ int mbedtls_rsa_export_raw( const mbedtls_rsa_context *ctx, /** * \brief This function exports CRT parameters of a private RSA key. * - * \param ctx The initialized RSA context. - * \param DP The MPI to hold D modulo P-1, or NULL. - * \param DQ The MPI to hold D modulo Q-1, or NULL. - * \param QP The MPI to hold modular inverse of Q modulo P, or NULL. - * - * \return \c 0 on success, non-zero error code otherwise. - * * \note Alternative RSA implementations not using CRT-parameters * internally can implement this function based on * mbedtls_rsa_deduce_opt(). * + * \param ctx The initialized RSA context. + * \param DP The MPI to hold \c D modulo `P-1`, + * or \c NULL if it need not be exported. + * \param DQ The MPI to hold \c D modulo `Q-1`, + * or \c NULL if it need not be exported. + * \param QP The MPI to hold modular inverse of \c Q modulo \c P, + * or \c NULL if it need not be exported. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + * */ int mbedtls_rsa_export_crt( const mbedtls_rsa_context *ctx, mbedtls_mpi *DP, mbedtls_mpi *DQ, mbedtls_mpi *QP ); @@ -376,13 +402,13 @@ int mbedtls_rsa_export_crt( const mbedtls_rsa_context *ctx, * \brief This function sets padding for an already initialized RSA * context. See mbedtls_rsa_init() for details. * - * \param ctx The RSA context to be set. - * \param padding Selects padding mode: #MBEDTLS_RSA_PKCS_V15 or - * #MBEDTLS_RSA_PKCS_V21. + * \param ctx The initialized RSA context to be configured. + * \param padding The padding mode to use. This must be either + * #MBEDTLS_RSA_PKCS_V15 or #MBEDTLS_RSA_PKCS_V21. * \param hash_id The #MBEDTLS_RSA_PKCS_V21 hash identifier. */ void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, - int hash_id); + int hash_id ); /** * \brief This function retrieves the length of RSA modulus in Bytes. @@ -397,17 +423,20 @@ size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ); /** * \brief This function generates an RSA keypair. * - * \param ctx The RSA context used to hold the key. - * \param f_rng The RNG function. - * \param p_rng The RNG parameter. - * \param nbits The size of the public key in bits. - * \param exponent The public exponent. For example, 65537. - * * \note mbedtls_rsa_init() must be called before this function, * to set up the RSA context. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - on failure. + * \param ctx The initialized RSA context used to hold the key. + * \param f_rng The RNG function to be used for key generation. + * This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't need a context. + * \param nbits The size of the public key in bits. + * \param exponent The public exponent to use. For example, \c 65537. + * This must be odd and greater than \c 1. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -422,10 +451,10 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, * enough information is present to perform an RSA public key * operation using mbedtls_rsa_public(). * - * \param ctx The RSA context to check. + * \param ctx The initialized RSA context to check. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. * */ int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); @@ -434,11 +463,6 @@ int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); * \brief This function checks if a context contains an RSA private key * and perform basic consistency checks. * - * \param ctx The RSA context to check. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code on - * failure. - * * \note The consistency checks performed by this function not only * ensure that mbedtls_rsa_private() can be called successfully * on the given context, but that the various parameters are @@ -465,6 +489,11 @@ int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); * user to ensure the trustworthiness of the source of his RSA * parameters, which goes beyond what is effectively checkable * by the library.
        + * + * \param ctx The initialized RSA context to check. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ); @@ -473,11 +502,11 @@ int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ); * * It checks each of the contexts, and makes sure they match. * - * \param pub The RSA context holding the public key. - * \param prv The RSA context holding the private key. + * \param pub The initialized RSA context holding the public key. + * \param prv The initialized RSA context holding the private key. * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv ); @@ -485,20 +514,21 @@ int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, /** * \brief This function performs an RSA public key operation. * - * \param ctx The RSA context. - * \param input The input buffer. - * \param output The output buffer. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. + * \param ctx The initialized RSA context to use. + * \param input The input buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. * * \note This function does not handle message padding. * * \note Make sure to set \p input[0] = 0 or ensure that * input is smaller than \p N. * - * \note The input and output buffers must be large - * enough. For example, 128 Bytes if RSA-1024 is used. + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_public( mbedtls_rsa_context *ctx, const unsigned char *input, @@ -507,18 +537,6 @@ int mbedtls_rsa_public( mbedtls_rsa_context *ctx, /** * \brief This function performs an RSA private key operation. * - * \param ctx The RSA context. - * \param f_rng The RNG function. Needed for blinding. - * \param p_rng The RNG parameter. - * \param input The input buffer. - * \param output The output buffer. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The input and output buffers must be large - * enough. For example, 128 Bytes if RSA-1024 is used. - * * \note Blinding is used if and only if a PRNG is provided. * * \note If blinding is used, both the base of exponentation @@ -530,6 +548,22 @@ int mbedtls_rsa_public( mbedtls_rsa_context *ctx, * Future versions of the library may enforce the presence * of a PRNG. * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function, used for blinding. It is discouraged + * and deprecated to pass \c NULL here, in which case + * blinding will be omitted. + * \param p_rng The RNG context to pass to \p f_rng. This may be \c NULL + * if \p f_rng is \c NULL or if \p f_rng doesn't need a context. + * \param input The input buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * */ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -544,16 +578,6 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, * It is the generic wrapper for performing a PKCS#1 encryption * operation using the \p mode from the context. * - * - * \param ctx The RSA context. - * \param f_rng The RNG function. Needed for padding, PKCS#1 v2.1 - * encoding, and #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param ilen The length of the plaintext. - * \param input The buffer holding the data to encrypt. - * \param output The buffer used to hold the ciphertext. - * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library * are likely to remove the \p mode argument and have it @@ -561,13 +585,29 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PRIVATE and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The input and output buffers must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG to use. It is mandatory for PKCS#1 v2.1 padding + * encoding, and for PKCS#1 v1.5 padding encoding when used + * with \p mode set to #MBEDTLS_RSA_PUBLIC. For PKCS#1 v1.5 + * padding encoding and \p mode set to #MBEDTLS_RSA_PRIVATE, + * it is used for blinding and should be provided in this + * case; see mbedtls_rsa_private() for more. + * \param p_rng The RNG context to be passed to \p f_rng. May be + * \c NULL if \p f_rng is \c NULL or if \p f_rng doesn't + * need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param ilen The length of the plaintext in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. This must not be \c NULL. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -580,15 +620,6 @@ int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, * \brief This function performs a PKCS#1 v1.5 encryption operation * (RSAES-PKCS1-v1_5-ENCRYPT). * - * \param ctx The RSA context. - * \param f_rng The RNG function. Needed for padding and - * #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param ilen The length of the plaintext. - * \param input The buffer holding the data to encrypt. - * \param output The buffer used to hold the ciphertext. - * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library * are likely to remove the \p mode argument and have it @@ -596,13 +627,27 @@ int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PRIVATE and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The output buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function to use. It is needed for padding generation + * if \p mode is #MBEDTLS_RSA_PUBLIC. If \p mode is + * #MBEDTLS_RSA_PRIVATE (discouraged), it is used for + * blinding and should be provided; see mbedtls_rsa_private(). + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng is \c NULL or if \p f_rng + * doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param ilen The length of the plaintext in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. This must not be \c NULL. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -615,31 +660,38 @@ int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, * \brief This function performs a PKCS#1 v2.1 OAEP encryption * operation (RSAES-OAEP-ENCRYPT). * - * \param ctx The RSA context. - * \param f_rng The RNG function. Needed for padding and PKCS#1 v2.1 - * encoding and #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \note The output buffer must be as large as the size + * of ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initnialized RSA context to use. + * \param f_rng The RNG function to use. This is needed for padding + * generation and must be provided. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). * \param label The buffer holding the custom label to use. - * \param label_len The length of the label. - * \param ilen The length of the plaintext. - * \param input The buffer holding the data to encrypt. - * \param output The buffer used to hold the ciphertext. - * - * \deprecated It is deprecated and discouraged to call this function - * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library - * are likely to remove the \p mode argument and have it - * implicitly set to #MBEDTLS_RSA_PUBLIC. - * - * \note Alternative implementations of RSA need not support - * mode being set to #MBEDTLS_RSA_PRIVATE and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The output buffer must be as large as the size - * of ctx->N. For example, 128 Bytes if RSA-1024 is used. + * This must be a readable buffer of length \p label_len + * Bytes. It may be \c NULL if \p label_len is \c 0. + * \param label_len The length of the label in Bytes. + * \param ilen The length of the plaintext buffer \p input in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. This must not be \c NULL. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -657,14 +709,12 @@ int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, * It is the generic wrapper for performing a PKCS#1 decryption * operation using the \p mode from the context. * - * \param ctx The RSA context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param olen The length of the plaintext. - * \param input The buffer holding the encrypted data. - * \param output The buffer used to hold the plaintext. - * \param output_max_len The maximum length of the output buffer. + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N (for example, + * 128 Bytes if RSA-1024 is used) to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns \c MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library @@ -673,20 +723,28 @@ int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PUBLIC and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The output buffer length \c output_max_len should be - * as large as the size \p ctx->len of \p ctx->N (for example, - * 128 Bytes if RSA-1024 is used) to be able to hold an - * arbitrary decrypted message. If it is not large enough to - * hold the decryption of the particular ciphertext provided, - * the function returns \c MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. - * - * \note The input buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -700,14 +758,12 @@ int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, * \brief This function performs a PKCS#1 v1.5 decryption * operation (RSAES-PKCS1-v1_5-DECRYPT). * - * \param ctx The RSA context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param olen The length of the plaintext. - * \param input The buffer holding the encrypted data. - * \param output The buffer to hold the plaintext. - * \param output_max_len The maximum length of the output buffer. + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for example, + * 128 Bytes if RSA-1024 is used, to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library @@ -716,20 +772,29 @@ int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PUBLIC and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. * - * \note The output buffer length \c output_max_len should be - * as large as the size \p ctx->len of \p ctx->N, for example, - * 128 Bytes if RSA-1024 is used, to be able to hold an - * arbitrary decrypted message. If it is not large enough to - * hold the decryption of the particular ciphertext provided, - * the function returns #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. - * - * \note The input buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. */ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -740,42 +805,50 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, size_t output_max_len ); /** - * \brief This function performs a PKCS#1 v2.1 OAEP decryption - * operation (RSAES-OAEP-DECRYPT). - * - * \param ctx The RSA context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \brief This function performs a PKCS#1 v2.1 OAEP decryption + * operation (RSAES-OAEP-DECRYPT). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for + * example, 128 Bytes if RSA-1024 is used, to be able to + * hold an arbitrary decrypted message. If it is not + * large enough to hold the decryption of the particular + * ciphertext provided, the function returns + * #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). * \param label The buffer holding the custom label to use. - * \param label_len The length of the label. - * \param olen The length of the plaintext. - * \param input The buffer holding the encrypted data. - * \param output The buffer to hold the plaintext. - * \param output_max_len The maximum length of the output buffer. - * - * \deprecated It is deprecated and discouraged to call this function - * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library - * are likely to remove the \p mode argument and have it - * implicitly set to #MBEDTLS_RSA_PRIVATE. - * - * \note Alternative implementations of RSA need not support - * mode being set to #MBEDTLS_RSA_PUBLIC and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 on success, or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The output buffer length \c output_max_len should be - * as large as the size \p ctx->len of \p ctx->N, for - * example, 128 Bytes if RSA-1024 is used, to be able to - * hold an arbitrary decrypted message. If it is not - * large enough to hold the decryption of the particular - * ciphertext provided, the function returns - * #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. - * - * \note The input buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * This must be a readable buffer of length \p label_len + * Bytes. It may be \c NULL if \p label_len is \c 0. + * \param label_len The length of the label in Bytes. + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -794,16 +867,12 @@ int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, * It is the generic wrapper for performing a PKCS#1 * signature using the \p mode from the context. * - * \param ctx The RSA context. - * \param f_rng The RNG function. Needed for PKCS#1 v2.1 encoding and for - * #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param md_alg The message-digest algorithm used to hash the original data. - * Use #MBEDTLS_MD_NONE for signing raw data. - * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. - * \param hash The buffer holding the message digest. - * \param sig The buffer to hold the ciphertext. + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_sign() for details on + * \p md_alg and \p hash_id. * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library @@ -812,17 +881,34 @@ int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PUBLIC and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 if the signing operation was successful, - * or an \c MBEDTLS_ERR_RSA_XXX error code on failure. - * - * \note The \p sig buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. - * - * \note For PKCS#1 v2.1 encoding, see comments on - * mbedtls_rsa_rsassa_pss_sign() for details on - * \p md_alg and \p hash_id. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function to use. If the padding mode is PKCS#1 v2.1, + * this must be provided. If the padding mode is PKCS#1 v1.5 and + * \p mode is #MBEDTLS_RSA_PRIVATE, it is used for blinding + * and should be provided; see mbedtls_rsa_private() for more + * more. It is ignored otherwise. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng is \c NULL or doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * Ths is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. A buffer length of + * #MBEDTLS_MPI_MAX_SIZE is always safe. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -837,16 +923,6 @@ int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, * \brief This function performs a PKCS#1 v1.5 signature * operation (RSASSA-PKCS1-v1_5-SIGN). * - * \param ctx The RSA context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param md_alg The message-digest algorithm used to hash the original data. - * Use #MBEDTLS_MD_NONE for signing raw data. - * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. - * \param hash The buffer holding the message digest. - * \param sig The buffer to hold the ciphertext. - * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library * are likely to remove the \p mode argument and have it @@ -854,14 +930,33 @@ int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PUBLIC and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 if the signing operation was successful, - * or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The \p sig buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng is \c NULL or doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * Ths is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. A buffer length of + * #MBEDTLS_MPI_MAX_SIZE is always safe. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -876,16 +971,22 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, * \brief This function performs a PKCS#1 v2.1 PSS signature * operation (RSASSA-PSS-SIGN). * - * \param ctx The RSA context. - * \param f_rng The RNG function. Needed for PKCS#1 v2.1 encoding and for - * #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param md_alg The message-digest algorithm used to hash the original data. - * Use #MBEDTLS_MD_NONE for signing raw data. - * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. - * \param hash The buffer holding the message digest. - * \param sig The buffer to hold the ciphertext. + * \note The \p hash_id in the RSA context is the one used for the + * encoding. \p md_alg in the function call is the type of hash + * that is encoded. According to RFC-3447: Public-Key + * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography + * Specifications it is advised to keep both hashes the + * same. + * + * \note This function always uses the maximum possible salt size, + * up to the length of the payload hash. This choice of salt + * size complies with FIPS 186-4 §5.5 (e) and RFC 8017 (PKCS#1 + * v2.2) §9.1.1 step 3. Furthermore this function enforces a + * minimum salt size which is the hash size minus 2 bytes. If + * this minimum size is too large given the key size (the salt + * size, plus the hash size, plus 2 bytes must be no more than + * the key size in bytes), this function returns + * #MBEDTLS_ERR_RSA_BAD_INPUT_DATA. * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library @@ -894,21 +995,30 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PUBLIC and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 if the signing operation was successful, - * or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The \p sig buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. - * - * \note The \p hash_id in the RSA context is the one used for the - * encoding. \p md_alg in the function call is the type of hash - * that is encoded. According to RFC-3447: Public-Key - * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography - * Specifications it is advised to keep both hashes the - * same. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. It must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * Ths is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. A buffer length of + * #MBEDTLS_MPI_MAX_SIZE is always safe. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -926,15 +1036,9 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, * This is the generic wrapper for performing a PKCS#1 * verification using the mode from the context. * - * \param ctx The RSA public key context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param md_alg The message-digest algorithm used to hash the original data. - * Use #MBEDTLS_MD_NONE for signing raw data. - * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. - * \param hash The buffer holding the message digest. - * \param sig The buffer holding the ciphertext. + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_verify() about \p md_alg and + * \p hash_id. * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library @@ -943,18 +1047,31 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PRIVATE and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 if the verify operation was successful, - * or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The \p sig buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. - * - * \note For PKCS#1 v2.1 encoding, see comments on - * mbedtls_rsa_rsassa_pss_verify() about \p md_alg and - * \p hash_id. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -969,16 +1086,6 @@ int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, * \brief This function performs a PKCS#1 v1.5 verification * operation (RSASSA-PKCS1-v1_5-VERIFY). * - * \param ctx The RSA public key context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param md_alg The message-digest algorithm used to hash the original data. - * Use #MBEDTLS_MD_NONE for signing raw data. - * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. - * \param hash The buffer holding the message digest. - * \param sig The buffer holding the ciphertext. - * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library * are likely to remove the \p mode argument and have it @@ -986,14 +1093,31 @@ int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PRIVATE and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 if the verify operation was successful, - * or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The \p sig buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -1011,15 +1135,13 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, * The hash function for the MGF mask generating function * is that specified in the RSA context. * - * \param ctx The RSA public key context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param md_alg The message-digest algorithm used to hash the original data. - * Use #MBEDTLS_MD_NONE for signing raw data. - * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. - * \param hash The buffer holding the message digest. - * \param sig The buffer holding the ciphertext. + * \note The \p hash_id in the RSA context is the one used for the + * verification. \p md_alg in the function call is the type of + * hash that is verified. According to RFC-3447: Public-Key + * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography + * Specifications it is advised to keep both hashes the + * same. If \p hash_id in the RSA context is unset, + * the \p md_alg from the function call is used. * * \deprecated It is deprecated and discouraged to call this function * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library @@ -1028,22 +1150,31 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, * * \note Alternative implementations of RSA need not support * mode being set to #MBEDTLS_RSA_PRIVATE and might instead - * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. - * - * \return \c 0 if the verify operation was successful, - * or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * - * \note The \p sig buffer must be as large as the size - * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. - * - * \note The \p hash_id in the RSA context is the one used for the - * verification. \p md_alg in the function call is the type of - * hash that is verified. According to RFC-3447: Public-Key - * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography - * Specifications it is advised to keep both hashes the - * same. If \p hash_id in the RSA context is unset, - * the \p md_alg from the function call is used. + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -1061,27 +1192,37 @@ int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, * The hash function for the MGF mask generating function * is that specified in \p mgf1_hash_id. * - * \param ctx The RSA public key context. - * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. - * \param p_rng The RNG parameter. - * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. - * \param md_alg The message-digest algorithm used to hash the original data. - * Use #MBEDTLS_MD_NONE for signing raw data. - * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. - * \param hash The buffer holding the message digest. - * \param mgf1_hash_id The message digest used for mask generation. - * \param expected_salt_len The length of the salt used in padding. Use - * #MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length. - * \param sig The buffer holding the ciphertext. - * - * \return \c 0 if the verify operation was successful, - * or an \c MBEDTLS_ERR_RSA_XXX error code - * on failure. - * * \note The \p sig buffer must be as large as the size * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. * * \note The \p hash_id in the RSA context is ignored. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param mgf1_hash_id The message digest used for mask generation. + * \param expected_salt_len The length of the salt used in padding. Use + * #MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -1097,40 +1238,35 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, /** * \brief This function copies the components of an RSA context. * - * \param dst The destination context. - * \param src The source context. + * \param dst The destination context. This must be initialized. + * \param src The source context. This must be initialized. * - * \return \c 0 on success, - * #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure. + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure. */ int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ); /** * \brief This function frees the components of an RSA key. * - * \param ctx The RSA Context to free. + * \param ctx The RSA context to free. May be \c NULL, in which case + * this function is a no-op. If it is not \c NULL, it must + * point to an initialized RSA context. */ void mbedtls_rsa_free( mbedtls_rsa_context *ctx ); -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_RSA_ALT */ -#include "rsa_alt.h" -#endif /* MBEDTLS_RSA_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief The RSA checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_rsa_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/sha1.h b/app/include/mbedtls/sha1.h index 05540cde12..bb6ecf05a4 100644 --- a/app/include/mbedtls/sha1.h +++ b/app/include/mbedtls/sha1.h @@ -1,7 +1,10 @@ /** * \file sha1.h * - * \brief The SHA-1 cryptographic hash function. + * \brief This file contains SHA-1 definitions and functions. + * + * The Secure Hash Algorithm 1 (SHA-1) cryptographic hash function is defined in + * FIPS 180-4: Secure Hash Standard (SHS). * * \warning SHA-1 is considered a weak message digest and its use constitutes * a security risk. We recommend considering stronger message @@ -37,16 +40,18 @@ #include #include +/* MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED -0x0035 /**< SHA-1 hardware accelerator failed */ - -#if !defined(MBEDTLS_SHA1_ALT) -// Regular implementation -// +#define MBEDTLS_ERR_SHA1_BAD_INPUT_DATA -0x0073 /**< SHA-1 input data was malformed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_SHA1_ALT) +// Regular implementation +// + /** * \brief The SHA-1 context structure. * @@ -55,7 +60,7 @@ extern "C" { * stronger message digests instead. * */ -typedef struct +typedef struct mbedtls_sha1_context { uint32_t total[2]; /*!< The number of Bytes processed. */ uint32_t state[5]; /*!< The intermediate digest state. */ @@ -63,40 +68,48 @@ typedef struct } mbedtls_sha1_context; +#else /* MBEDTLS_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* MBEDTLS_SHA1_ALT */ + /** * \brief This function initializes a SHA-1 context. * - * \param ctx The SHA-1 context to initialize. - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param ctx The SHA-1 context to initialize. + * This must not be \c NULL. + * */ void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); /** * \brief This function clears a SHA-1 context. * - * \param ctx The SHA-1 context to clear. - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param ctx The SHA-1 context to clear. This may be \c NULL, + * in which case this function does nothing. If it is + * not \c NULL, it must point to an initialized + * SHA-1 context. + * */ void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); /** * \brief This function clones the state of a SHA-1 context. * - * \param dst The destination context. - * \param src The context to clone. - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param dst The SHA-1 context to clone to. This must be initialized. + * \param src The SHA-1 context to clone from. This must be initialized. + * */ void mbedtls_sha1_clone( mbedtls_sha1_context *dst, const mbedtls_sha1_context *src ); @@ -104,14 +117,15 @@ void mbedtls_sha1_clone( mbedtls_sha1_context *dst, /** * \brief This function starts a SHA-1 checksum calculation. * - * \param ctx The context to initialize. - * - * \return \c 0 if successful - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param ctx The SHA-1 context to initialize. This must be initialized. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * */ int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ); @@ -119,16 +133,18 @@ int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ); * \brief This function feeds an input buffer into an ongoing SHA-1 * checksum calculation. * - * \param ctx The SHA-1 context. - * \param input The buffer holding the input data. - * \param ilen The length of the input data. - * - * \return \c 0 if successful - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param ctx The SHA-1 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, const unsigned char *input, @@ -138,31 +154,35 @@ int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, * \brief This function finishes the SHA-1 operation, and writes * the result to the output buffer. * - * \param ctx The SHA-1 context. - * \param output The SHA-1 checksum result. - * - * \return \c 0 if successful - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param ctx The SHA-1 context to use. This must be initialized and + * have a hash operation started. + * \param output The SHA-1 checksum result. This must be a writable + * buffer of length \c 20 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, unsigned char output[20] ); /** - * \brief SHA-1 process data block (internal use only) - * - * \param ctx SHA-1 context - * \param data The data block being processed. - * - * \return \c 0 if successful + * \brief SHA-1 process data block (internal use only). * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param ctx The SHA-1 context to use. This must be initialized. + * \param data The data block being processed. This must be a + * readable buffer of length \c 64 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * */ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); @@ -174,65 +194,71 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, #define MBEDTLS_DEPRECATED #endif /** - * \brief SHA-1 context setup - * - * \deprecated Superseded by mbedtls_sha1_starts_ret() in 2.7.0 - * - * \param ctx The SHA-1 context to be initialized. + * \brief This function starts a SHA-1 checksum calculation. * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \deprecated Superseded by mbedtls_sha1_starts_ret() in 2.7.0. + * + * \param ctx The SHA-1 context to initialize. This must be initialized. + * */ MBEDTLS_DEPRECATED void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); /** - * \brief SHA-1 process buffer - * - * \deprecated Superseded by mbedtls_sha1_update_ret() in 2.7.0 - * - * \param ctx The SHA-1 context. - * \param input The buffer holding the input data. - * \param ilen The length of the input data. + * \brief This function feeds an input buffer into an ongoing SHA-1 + * checksum calculation. * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \deprecated Superseded by mbedtls_sha1_update_ret() in 2.7.0. + * + * \param ctx The SHA-1 context. This must be initialized and + * have a hash operation started. + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * */ MBEDTLS_DEPRECATED void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ); /** - * \brief SHA-1 final digest - * - * \deprecated Superseded by mbedtls_sha1_finish_ret() in 2.7.0 - * - * \param ctx The SHA-1 context. - * \param output The SHA-1 checksum result. + * \brief This function finishes the SHA-1 operation, and writes + * the result to the output buffer. * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \deprecated Superseded by mbedtls_sha1_finish_ret() in 2.7.0. + * + * \param ctx The SHA-1 context. This must be initialized and + * have a hash operation started. + * \param output The SHA-1 checksum result. + * This must be a writable buffer of length \c 20 Bytes. */ MBEDTLS_DEPRECATED void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ); /** - * \brief SHA-1 process data block (internal use only) - * - * \deprecated Superseded by mbedtls_internal_sha1_process() in 2.7.0 - * - * \param ctx The SHA-1 context. - * \param data The data block being processed. + * \brief SHA-1 process data block (internal use only). * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \deprecated Superseded by mbedtls_internal_sha1_process() in 2.7.0. + * + * \param ctx The SHA-1 context. This must be initialized. + * \param data The data block being processed. + * This must be a readable buffer of length \c 64 bytes. + * */ MBEDTLS_DEPRECATED void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); @@ -240,18 +266,6 @@ MBEDTLS_DEPRECATED void mbedtls_sha1_process( mbedtls_sha1_context *ctx, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_SHA1_ALT */ -#include "sha1_alt.h" -#endif /* MBEDTLS_SHA1_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief This function calculates the SHA-1 checksum of a buffer. * @@ -261,16 +275,19 @@ extern "C" { * The SHA-1 result is calculated as * output = SHA-1(input buffer). * - * \param input The buffer holding the input data. - * \param ilen The length of the input data. - * \param output The SHA-1 checksum result. - * - * \return \c 0 if successful - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * \param output The SHA-1 checksum result. + * This must be a writable buffer of length \c 20 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * */ int mbedtls_sha1_ret( const unsigned char *input, size_t ilen, @@ -283,18 +300,26 @@ int mbedtls_sha1_ret( const unsigned char *input, #define MBEDTLS_DEPRECATED #endif /** - * \brief Output = SHA-1( input buffer ) + * \brief This function calculates the SHA-1 checksum of a buffer. * - * \deprecated Superseded by mbedtls_sha1_ret() in 2.7.0 + * The function allocates the context, performs the + * calculation, and frees the context. * - * \param input The buffer holding the input data. - * \param ilen The length of the input data. - * \param output The SHA-1 checksum result. + * The SHA-1 result is calculated as + * output = SHA-1(input buffer). * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \deprecated Superseded by mbedtls_sha1_ret() in 2.7.0 + * + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * \param output The SHA-1 checksum result. This must be a writable + * buffer of size \c 20 Bytes. + * */ MBEDTLS_DEPRECATED void mbedtls_sha1( const unsigned char *input, size_t ilen, @@ -303,18 +328,23 @@ MBEDTLS_DEPRECATED void mbedtls_sha1( const unsigned char *input, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_SELF_TEST) + /** * \brief The SHA-1 checkup routine. * - * \return \c 0 on success, or \c 1 on failure. - * * \warning SHA-1 is considered a weak message digest and its use * constitutes a security risk. We recommend considering * stronger message digests instead. * + * \return \c 0 on success. + * \return \c 1 on failure. + * */ int mbedtls_sha1_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/sha256.h b/app/include/mbedtls/sha256.h index ffb16c277a..d64739820c 100644 --- a/app/include/mbedtls/sha256.h +++ b/app/include/mbedtls/sha256.h @@ -1,7 +1,10 @@ /** * \file sha256.h * - * \brief The SHA-224 and SHA-256 cryptographic hash function. + * \brief This file contains SHA-224 and SHA-256 definitions and functions. + * + * The Secure Hash Algorithms 224 and 256 (SHA-224 and SHA-256) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). */ /* * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved @@ -33,16 +36,18 @@ #include #include +/* MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED -0x0037 /**< SHA-256 hardware accelerator failed */ - -#if !defined(MBEDTLS_SHA256_ALT) -// Regular implementation -// +#define MBEDTLS_ERR_SHA256_BAD_INPUT_DATA -0x0074 /**< SHA-256 input data was malformed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_SHA256_ALT) +// Regular implementation +// + /** * \brief The SHA-256 context structure. * @@ -50,36 +55,41 @@ extern "C" { * checksum calculations. The choice between these two is * made in the call to mbedtls_sha256_starts_ret(). */ -typedef struct +typedef struct mbedtls_sha256_context { uint32_t total[2]; /*!< The number of Bytes processed. */ uint32_t state[8]; /*!< The intermediate digest state. */ unsigned char buffer[64]; /*!< The data block being processed. */ - int is224; /*!< Determines which function to use. -
        • 0: Use SHA-256.
        • -
        • 1: Use SHA-224.
        */ + int is224; /*!< Determines which function to use: + 0: Use SHA-256, or 1: Use SHA-224. */ } mbedtls_sha256_context; +#else /* MBEDTLS_SHA256_ALT */ +#include "sha256_alt.h" +#endif /* MBEDTLS_SHA256_ALT */ + /** * \brief This function initializes a SHA-256 context. * - * \param ctx The SHA-256 context to initialize. + * \param ctx The SHA-256 context to initialize. This must not be \c NULL. */ void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); /** * \brief This function clears a SHA-256 context. * - * \param ctx The SHA-256 context to clear. + * \param ctx The SHA-256 context to clear. This may be \c NULL, in which + * case this function returns immediately. If it is not \c NULL, + * it must point to an initialized SHA-256 context. */ void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); /** * \brief This function clones the state of a SHA-256 context. * - * \param dst The destination context. - * \param src The context to clone. + * \param dst The destination context. This must be initialized. + * \param src The context to clone. This must be initialized. */ void mbedtls_sha256_clone( mbedtls_sha256_context *dst, const mbedtls_sha256_context *src ); @@ -88,12 +98,12 @@ void mbedtls_sha256_clone( mbedtls_sha256_context *dst, * \brief This function starts a SHA-224 or SHA-256 checksum * calculation. * - * \param ctx The context to initialize. - * \param is224 Determines which function to use. - *
        • 0: Use SHA-256.
        • - *
        • 1: Use SHA-224.
        + * \param ctx The context to use. This must be initialized. + * \param is224 This determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ); @@ -101,11 +111,14 @@ int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ); * \brief This function feeds an input buffer into an ongoing * SHA-256 checksum calculation. * - * \param ctx SHA-256 context - * \param input buffer holding the data - * \param ilen length of the input data + * \param ctx The SHA-256 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, const unsigned char *input, @@ -115,10 +128,13 @@ int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, * \brief This function finishes the SHA-256 operation, and writes * the result to the output buffer. * - * \param ctx The SHA-256 context. + * \param ctx The SHA-256 context. This must be initialized + * and have a hash operation started. * \param output The SHA-224 or SHA-256 checksum result. + * This must be a writable buffer of length \c 32 Bytes. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, unsigned char output[32] ); @@ -128,10 +144,12 @@ int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, * the ongoing SHA-256 computation. This function is for * internal use only. * - * \param ctx The SHA-256 context. - * \param data The buffer holding one block of data. + * \param ctx The SHA-256 context. This must be initialized. + * \param data The buffer holding one block of data. This must + * be a readable buffer of length \c 64 Bytes. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); @@ -143,14 +161,14 @@ int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, #define MBEDTLS_DEPRECATED #endif /** - * \brief This function starts a SHA-256 checksum calculation. + * \brief This function starts a SHA-224 or SHA-256 checksum + * calculation. * * \deprecated Superseded by mbedtls_sha256_starts_ret() in 2.7.0. * - * \param ctx The SHA-256 context to initialize. - * \param is224 Determines which function to use. - *
        • 0: Use SHA-256.
        • - *
        • 1: Use SHA-224.
        + * \param ctx The context to use. This must be initialized. + * \param is224 Determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. */ MBEDTLS_DEPRECATED void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ); @@ -161,9 +179,11 @@ MBEDTLS_DEPRECATED void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, * * \deprecated Superseded by mbedtls_sha256_update_ret() in 2.7.0. * - * \param ctx The SHA-256 context to initialize. - * \param input The buffer holding the data. - * \param ilen The length of the input data. + * \param ctx The SHA-256 context to use. This must be + * initialized and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. */ MBEDTLS_DEPRECATED void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, @@ -175,8 +195,10 @@ MBEDTLS_DEPRECATED void mbedtls_sha256_update( mbedtls_sha256_context *ctx, * * \deprecated Superseded by mbedtls_sha256_finish_ret() in 2.7.0. * - * \param ctx The SHA-256 context. - * \param output The SHA-224or SHA-256 checksum result. + * \param ctx The SHA-256 context. This must be initialized and + * have a hash operation started. + * \param output The SHA-224 or SHA-256 checksum result. This must be + * a writable buffer of length \c 32 Bytes. */ MBEDTLS_DEPRECATED void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ); @@ -188,25 +210,15 @@ MBEDTLS_DEPRECATED void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, * * \deprecated Superseded by mbedtls_internal_sha256_process() in 2.7.0. * - * \param ctx The SHA-256 context. - * \param data The buffer holding one block of data. + * \param ctx The SHA-256 context. This must be initialized. + * \param data The buffer holding one block of data. This must be + * a readable buffer of size \c 64 Bytes. */ MBEDTLS_DEPRECATED void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_SHA256_ALT */ -#include "sha256_alt.h" -#endif /* MBEDTLS_SHA256_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif /** * \brief This function calculates the SHA-224 or SHA-256 @@ -218,12 +230,13 @@ extern "C" { * The SHA-256 result is calculated as * output = SHA-256(input buffer). * - * \param input The buffer holding the input data. - * \param ilen The length of the input data. - * \param output The SHA-224 or SHA-256 checksum result. - * \param is224 Determines which function to use. - *
        • 0: Use SHA-256.
        • - *
        • 1: Use SHA-224.
        + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-224 or SHA-256 checksum result. This must + * be a writable buffer of length \c 32 Bytes. + * \param is224 Determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. */ int mbedtls_sha256_ret( const unsigned char *input, size_t ilen, @@ -249,12 +262,13 @@ int mbedtls_sha256_ret( const unsigned char *input, * * \deprecated Superseded by mbedtls_sha256_ret() in 2.7.0. * - * \param input The buffer holding the data. - * \param ilen The length of the input data. - * \param output The SHA-224 or SHA-256 checksum result. - * \param is224 Determines which function to use. - *
        • 0: Use SHA-256.
        • - *
        • 1: Use SHA-224.
        + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-224 or SHA-256 checksum result. This must be + * a writable buffer of length \c 32 Bytes. + * \param is224 Determines which function to use. This must be either + * \c 0 for SHA-256, or \c 1 for SHA-224. */ MBEDTLS_DEPRECATED void mbedtls_sha256( const unsigned char *input, size_t ilen, @@ -264,13 +278,18 @@ MBEDTLS_DEPRECATED void mbedtls_sha256( const unsigned char *input, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_SELF_TEST) + /** * \brief The SHA-224 and SHA-256 checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_sha256_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/mbedtls/sha512.h b/app/include/mbedtls/sha512.h index 8404a2d599..c06ceed1d1 100644 --- a/app/include/mbedtls/sha512.h +++ b/app/include/mbedtls/sha512.h @@ -1,7 +1,9 @@ /** * \file sha512.h + * \brief This file contains SHA-384 and SHA-512 definitions and functions. * - * \brief The SHA-384 and SHA-512 cryptographic hash function. + * The Secure Hash Algorithms 384 and 512 (SHA-384 and SHA-512) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). */ /* * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved @@ -33,16 +35,18 @@ #include #include +/* MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED is deprecated and should not be used. */ #define MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED -0x0039 /**< SHA-512 hardware accelerator failed */ - -#if !defined(MBEDTLS_SHA512_ALT) -// Regular implementation -// +#define MBEDTLS_ERR_SHA512_BAD_INPUT_DATA -0x0075 /**< SHA-512 input data was malformed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_SHA512_ALT) +// Regular implementation +// + /** * \brief The SHA-512 context structure. * @@ -50,36 +54,43 @@ extern "C" { * checksum calculations. The choice between these two is * made in the call to mbedtls_sha512_starts_ret(). */ -typedef struct +typedef struct mbedtls_sha512_context { uint64_t total[2]; /*!< The number of Bytes processed. */ uint64_t state[8]; /*!< The intermediate digest state. */ unsigned char buffer[128]; /*!< The data block being processed. */ - int is384; /*!< Determines which function to use. - *
        • 0: Use SHA-512.
        • - *
        • 1: Use SHA-384.
        */ + int is384; /*!< Determines which function to use: + 0: Use SHA-512, or 1: Use SHA-384. */ } mbedtls_sha512_context; +#else /* MBEDTLS_SHA512_ALT */ +#include "sha512_alt.h" +#endif /* MBEDTLS_SHA512_ALT */ + /** * \brief This function initializes a SHA-512 context. * - * \param ctx The SHA-512 context to initialize. + * \param ctx The SHA-512 context to initialize. This must + * not be \c NULL. */ void mbedtls_sha512_init( mbedtls_sha512_context *ctx ); /** * \brief This function clears a SHA-512 context. * - * \param ctx The SHA-512 context to clear. + * \param ctx The SHA-512 context to clear. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must point to an initialized + * SHA-512 context. */ void mbedtls_sha512_free( mbedtls_sha512_context *ctx ); /** * \brief This function clones the state of a SHA-512 context. * - * \param dst The destination context. - * \param src The context to clone. + * \param dst The destination context. This must be initialized. + * \param src The context to clone. This must be initialized. */ void mbedtls_sha512_clone( mbedtls_sha512_context *dst, const mbedtls_sha512_context *src ); @@ -88,12 +99,12 @@ void mbedtls_sha512_clone( mbedtls_sha512_context *dst, * \brief This function starts a SHA-384 or SHA-512 checksum * calculation. * - * \param ctx The SHA-512 context to initialize. - * \param is384 Determines which function to use. - *
        • 0: Use SHA-512.
        • - *
        • 1: Use SHA-384.
        + * \param ctx The SHA-512 context to use. This must be initialized. + * \param is384 Determines which function to use. This must be + * either \c for SHA-512, or \c 1 for SHA-384. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ); @@ -101,11 +112,14 @@ int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ); * \brief This function feeds an input buffer into an ongoing * SHA-512 checksum calculation. * - * \param ctx The SHA-512 context. - * \param input The buffer holding the input data. - * \param ilen The length of the input data. + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, const unsigned char *input, @@ -116,10 +130,13 @@ int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, * the result to the output buffer. This function is for * internal use only. * - * \param ctx The SHA-512 context. + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. * \param output The SHA-384 or SHA-512 checksum result. + * This must be a writable buffer of length \c 64 Bytes. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, unsigned char output[64] ); @@ -128,10 +145,12 @@ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, * \brief This function processes a single data block within * the ongoing SHA-512 computation. * - * \param ctx The SHA-512 context. - * \param data The buffer holding one block of data. + * \param ctx The SHA-512 context. This must be initialized. + * \param data The buffer holding one block of data. This + * must be a readable buffer of length \c 128 Bytes. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] ); @@ -147,10 +166,9 @@ int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, * * \deprecated Superseded by mbedtls_sha512_starts_ret() in 2.7.0 * - * \param ctx The SHA-512 context to initialize. - * \param is384 Determines which function to use. - *
        • 0: Use SHA-512.
        • - *
        • 1: Use SHA-384.
        + * \param ctx The SHA-512 context to use. This must be initialized. + * \param is384 Determines which function to use. This must be either + * \c 0 for SHA-512 or \c 1 for SHA-384. */ MBEDTLS_DEPRECATED void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, int is384 ); @@ -159,11 +177,13 @@ MBEDTLS_DEPRECATED void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, * \brief This function feeds an input buffer into an ongoing * SHA-512 checksum calculation. * - * \deprecated Superseded by mbedtls_sha512_update_ret() in 2.7.0 + * \deprecated Superseded by mbedtls_sha512_update_ret() in 2.7.0. * - * \param ctx The SHA-512 context. - * \param input The buffer holding the data. - * \param ilen The length of the input data. + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. */ MBEDTLS_DEPRECATED void mbedtls_sha512_update( mbedtls_sha512_context *ctx, const unsigned char *input, @@ -173,10 +193,12 @@ MBEDTLS_DEPRECATED void mbedtls_sha512_update( mbedtls_sha512_context *ctx, * \brief This function finishes the SHA-512 operation, and writes * the result to the output buffer. * - * \deprecated Superseded by mbedtls_sha512_finish_ret() in 2.7.0 + * \deprecated Superseded by mbedtls_sha512_finish_ret() in 2.7.0. * - * \param ctx The SHA-512 context. - * \param output The SHA-384 or SHA-512 checksum result. + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param output The SHA-384 or SHA-512 checksum result. This must + * be a writable buffer of size \c 64 Bytes. */ MBEDTLS_DEPRECATED void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, unsigned char output[64] ); @@ -186,10 +208,11 @@ MBEDTLS_DEPRECATED void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, * the ongoing SHA-512 computation. This function is for * internal use only. * - * \deprecated Superseded by mbedtls_internal_sha512_process() in 2.7.0 + * \deprecated Superseded by mbedtls_internal_sha512_process() in 2.7.0. * - * \param ctx The SHA-512 context. - * \param data The buffer holding one block of data. + * \param ctx The SHA-512 context. This must be initialized. + * \param data The buffer holding one block of data. This must be + * a readable buffer of length \c 128 Bytes. */ MBEDTLS_DEPRECATED void mbedtls_sha512_process( mbedtls_sha512_context *ctx, @@ -198,18 +221,6 @@ MBEDTLS_DEPRECATED void mbedtls_sha512_process( #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_SHA512_ALT */ -#include "sha512_alt.h" -#endif /* MBEDTLS_SHA512_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief This function calculates the SHA-512 or SHA-384 * checksum of a buffer. @@ -220,14 +231,16 @@ extern "C" { * The SHA-512 result is calculated as * output = SHA-512(input buffer). * - * \param input The buffer holding the input data. - * \param ilen The length of the input data. + * \param input The buffer holding the input data. This must be + * a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. * \param output The SHA-384 or SHA-512 checksum result. - * \param is384 Determines which function to use. - *
        • 0: Use SHA-512.
        • - *
        • 1: Use SHA-384.
        + * This must be a writable buffer of length \c 64 Bytes. + * \param is384 Determines which function to use. This must be either + * \c 0 for SHA-512, or \c 1 for SHA-384. * * \return \c 0 on success. + * \return A negative error code on failure. */ int mbedtls_sha512_ret( const unsigned char *input, size_t ilen, @@ -240,6 +253,7 @@ int mbedtls_sha512_ret( const unsigned char *input, #else #define MBEDTLS_DEPRECATED #endif + /** * \brief This function calculates the SHA-512 or SHA-384 * checksum of a buffer. @@ -252,12 +266,13 @@ int mbedtls_sha512_ret( const unsigned char *input, * * \deprecated Superseded by mbedtls_sha512_ret() in 2.7.0 * - * \param input The buffer holding the data. - * \param ilen The length of the input data. - * \param output The SHA-384 or SHA-512 checksum result. - * \param is384 Determines which function to use. - *
        • 0: Use SHA-512.
        • - *
        • 1: Use SHA-384.
        + * \param input The buffer holding the data. This must be a + * readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-384 or SHA-512 checksum result. This must + * be a writable buffer of length \c 64 Bytes. + * \param is384 Determines which function to use. This must be either + * \c 0 for SHA-512, or \c 1 for SHA-384. */ MBEDTLS_DEPRECATED void mbedtls_sha512( const unsigned char *input, size_t ilen, @@ -266,12 +281,17 @@ MBEDTLS_DEPRECATED void mbedtls_sha512( const unsigned char *input, #undef MBEDTLS_DEPRECATED #endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + /** * \brief The SHA-384 or SHA-512 checkup routine. * - * \return \c 0 on success, or \c 1 on failure. + * \return \c 0 on success. + * \return \c 1 on failure. */ int mbedtls_sha512_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ #ifdef __cplusplus } diff --git a/app/include/mbedtls/ssl.h b/app/include/mbedtls/ssl.h index 5593a5282a..1adf9608cc 100644 --- a/app/include/mbedtls/ssl.h +++ b/app/include/mbedtls/ssl.h @@ -49,6 +49,15 @@ #endif #if defined(MBEDTLS_ZLIB_SUPPORT) + +#if defined(MBEDTLS_DEPRECATED_WARNING) +#warning "Record compression support via MBEDTLS_ZLIB_SUPPORT is deprecated and will be removed in the next major revision of the library" +#endif + +#if defined(MBEDTLS_DEPRECATED_REMOVED) +#error "Record compression support via MBEDTLS_ZLIB_SUPPORT is deprecated and cannot be used if MBEDTLS_DEPRECATED_REMOVED is set" +#endif + #include "zlib.h" #endif @@ -103,13 +112,17 @@ #define MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED -0x6A80 /**< DTLS client must retry for hello verification */ #define MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL -0x6A00 /**< A buffer is too small to receive or write a message */ #define MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE -0x6980 /**< None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). */ -#define MBEDTLS_ERR_SSL_WANT_READ -0x6900 /**< Connection requires a read call. */ +#define MBEDTLS_ERR_SSL_WANT_READ -0x6900 /**< No data of requested type currently available on underlying transport. */ #define MBEDTLS_ERR_SSL_WANT_WRITE -0x6880 /**< Connection requires a write call. */ #define MBEDTLS_ERR_SSL_TIMEOUT -0x6800 /**< The operation timed out. */ #define MBEDTLS_ERR_SSL_CLIENT_RECONNECT -0x6780 /**< The client initiated a reconnect from the same port. */ #define MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700 /**< Record header looks valid but is not expected. */ #define MBEDTLS_ERR_SSL_NON_FATAL -0x6680 /**< The alert message received indicates a non-fatal error. */ #define MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH -0x6600 /**< Couldn't set the hash for verifying CertificateVerify */ +#define MBEDTLS_ERR_SSL_CONTINUE_PROCESSING -0x6580 /**< Internal-only message signaling that further message-processing should be done */ +#define MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -0x6500 /**< The asynchronous operation is not completed yet. */ +#define MBEDTLS_ERR_SSL_EARLY_MESSAGE -0x6480 /**< Internal-only message signaling that a message arrived early. */ +#define MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000 /**< A cryptographic operation is in progress. Try again later. */ /* * Various constants @@ -209,7 +222,7 @@ #endif /* - * Maxium fragment length in bytes, + * Maximum fragment length in bytes, * determines the size of each of the two internal I/O buffers. * * Note: the RFC defines the default size of SSL / TLS messages. If you @@ -223,6 +236,22 @@ #define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ #endif +#if !defined(MBEDTLS_SSL_IN_CONTENT_LEN) +#define MBEDTLS_SSL_IN_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#endif + +#if !defined(MBEDTLS_SSL_OUT_CONTENT_LEN) +#define MBEDTLS_SSL_OUT_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#endif + +/* + * Maximum number of heap-allocated bytes for the purpose of + * DTLS handshake message reassembly and future message buffering. + */ +#if !defined(MBEDTLS_SSL_DTLS_MAX_BUFFERING) +#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 +#endif + /* \} name SECTION: Module settings */ /* @@ -526,7 +555,6 @@ typedef void mbedtls_ssl_set_timer_t( void * ctx, */ typedef int mbedtls_ssl_get_timer_t( void * ctx ); - /* Defined below */ typedef struct mbedtls_ssl_session mbedtls_ssl_session; typedef struct mbedtls_ssl_context mbedtls_ssl_context; @@ -543,6 +571,218 @@ typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; #endif +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Callback type: start external signature operation. + * + * This callback is called during an SSL handshake to start + * a signature decryption operation using an + * external processor. The parameter \p cert contains + * the public key; it is up to the callback function to + * determine how to access the associated private key. + * + * This function typically sends or enqueues a request, and + * does not wait for the operation to complete. This allows + * the handshake step to be non-blocking. + * + * The parameters \p ssl and \p cert are guaranteed to remain + * valid throughout the handshake. On the other hand, this + * function must save the contents of \p hash if the value + * is needed for later processing, because the \p hash buffer + * is no longer valid after this function returns. + * + * This function may call mbedtls_ssl_set_async_operation_data() + * to store an operation context for later retrieval + * by the resume or cancel callback. + * + * \note For RSA signatures, this function must produce output + * that is consistent with PKCS#1 v1.5 in the same way as + * mbedtls_rsa_pkcs1_sign(). Before the private key operation, + * apply the padding steps described in RFC 8017, section 9.2 + * "EMSA-PKCS1-v1_5" as follows. + * - If \p md_alg is #MBEDTLS_MD_NONE, apply the PKCS#1 v1.5 + * encoding, treating \p hash as the DigestInfo to be + * padded. In other words, apply EMSA-PKCS1-v1_5 starting + * from step 3, with `T = hash` and `tLen = hash_len`. + * - If `md_alg != MBEDTLS_MD_NONE`, apply the PKCS#1 v1.5 + * encoding, treating \p hash as the hash to be encoded and + * padded. In other words, apply EMSA-PKCS1-v1_5 starting + * from step 2, with `digestAlgorithm` obtained by calling + * mbedtls_oid_get_oid_by_md() on \p md_alg. + * + * \note For ECDSA signatures, the output format is the DER encoding + * `Ecdsa-Sig-Value` defined in + * [RFC 4492 section 5.4](https://tools.ietf.org/html/rfc4492#section-5.4). + * + * \param ssl The SSL connection instance. It should not be + * modified other than via + * mbedtls_ssl_set_async_operation_data(). + * \param cert Certificate containing the public key. + * In simple cases, this is one of the pointers passed to + * mbedtls_ssl_conf_own_cert() when configuring the SSL + * connection. However, if other callbacks are used, this + * property may not hold. For example, if an SNI callback + * is registered with mbedtls_ssl_conf_sni(), then + * this callback determines what certificate is used. + * \param md_alg Hash algorithm. + * \param hash Buffer containing the hash. This buffer is + * no longer valid when the function returns. + * \param hash_len Size of the \c hash buffer in bytes. + * + * \return 0 if the operation was started successfully and the SSL + * stack should call the resume callback immediately. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation + * was started successfully and the SSL stack should return + * immediately without calling the resume callback yet. + * \return #MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external + * processor does not support this key. The SSL stack will + * use the private key object instead. + * \return Any other error indicates a fatal failure and is + * propagated up the call chain. The callback should + * use \c MBEDTLS_ERR_PK_xxx error codes, and must not + * use \c MBEDTLS_ERR_SSL_xxx error codes except as + * directed in the documentation of this callback. + */ +typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *cert, + mbedtls_md_type_t md_alg, + const unsigned char *hash, + size_t hash_len ); + +/** + * \brief Callback type: start external decryption operation. + * + * This callback is called during an SSL handshake to start + * an RSA decryption operation using an + * external processor. The parameter \p cert contains + * the public key; it is up to the callback function to + * determine how to access the associated private key. + * + * This function typically sends or enqueues a request, and + * does not wait for the operation to complete. This allows + * the handshake step to be non-blocking. + * + * The parameters \p ssl and \p cert are guaranteed to remain + * valid throughout the handshake. On the other hand, this + * function must save the contents of \p input if the value + * is needed for later processing, because the \p input buffer + * is no longer valid after this function returns. + * + * This function may call mbedtls_ssl_set_async_operation_data() + * to store an operation context for later retrieval + * by the resume or cancel callback. + * + * \warning RSA decryption as used in TLS is subject to a potential + * timing side channel attack first discovered by Bleichenbacher + * in 1998. This attack can be remotely exploitable + * in practice. To avoid this attack, you must ensure that + * if the callback performs an RSA decryption, the time it + * takes to execute and return the result does not depend + * on whether the RSA decryption succeeded or reported + * invalid padding. + * + * \param ssl The SSL connection instance. It should not be + * modified other than via + * mbedtls_ssl_set_async_operation_data(). + * \param cert Certificate containing the public key. + * In simple cases, this is one of the pointers passed to + * mbedtls_ssl_conf_own_cert() when configuring the SSL + * connection. However, if other callbacks are used, this + * property may not hold. For example, if an SNI callback + * is registered with mbedtls_ssl_conf_sni(), then + * this callback determines what certificate is used. + * \param input Buffer containing the input ciphertext. This buffer + * is no longer valid when the function returns. + * \param input_len Size of the \p input buffer in bytes. + * + * \return 0 if the operation was started successfully and the SSL + * stack should call the resume callback immediately. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation + * was started successfully and the SSL stack should return + * immediately without calling the resume callback yet. + * \return #MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external + * processor does not support this key. The SSL stack will + * use the private key object instead. + * \return Any other error indicates a fatal failure and is + * propagated up the call chain. The callback should + * use \c MBEDTLS_ERR_PK_xxx error codes, and must not + * use \c MBEDTLS_ERR_SSL_xxx error codes except as + * directed in the documentation of this callback. + */ +typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *cert, + const unsigned char *input, + size_t input_len ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/** + * \brief Callback type: resume external operation. + * + * This callback is called during an SSL handshake to resume + * an external operation started by the + * ::mbedtls_ssl_async_sign_t or + * ::mbedtls_ssl_async_decrypt_t callback. + * + * This function typically checks the status of a pending + * request or causes the request queue to make progress, and + * does not wait for the operation to complete. This allows + * the handshake step to be non-blocking. + * + * This function may call mbedtls_ssl_get_async_operation_data() + * to retrieve an operation context set by the start callback. + * It may call mbedtls_ssl_set_async_operation_data() to modify + * this context. + * + * Note that when this function returns a status other than + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, it must free any + * resources associated with the operation. + * + * \param ssl The SSL connection instance. It should not be + * modified other than via + * mbedtls_ssl_set_async_operation_data(). + * \param output Buffer containing the output (signature or decrypted + * data) on success. + * \param output_len On success, number of bytes written to \p output. + * \param output_size Size of the \p output buffer in bytes. + * + * \return 0 if output of the operation is available in the + * \p output buffer. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation + * is still in progress. Subsequent requests for progress + * on the SSL connection will call the resume callback + * again. + * \return Any other error means that the operation is aborted. + * The SSL handshake is aborted. The callback should + * use \c MBEDTLS_ERR_PK_xxx error codes, and must not + * use \c MBEDTLS_ERR_SSL_xxx error codes except as + * directed in the documentation of this callback. + */ +typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, + unsigned char *output, + size_t *output_len, + size_t output_size ); + +/** + * \brief Callback type: cancel external operation. + * + * This callback is called if an SSL connection is closed + * while an asynchronous operation is in progress. Note that + * this callback is not called if the + * ::mbedtls_ssl_async_resume_t callback has run and has + * returned a value other than + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, since in that case + * the asynchronous operation has already completed. + * + * This function may call mbedtls_ssl_get_async_operation_data() + * to retrieve an operation context set by the start callback. + * + * \param ssl The SSL connection instance. It should not be + * modified. + */ +typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + /* * This structure is used for storing current session data. */ @@ -659,6 +899,16 @@ struct mbedtls_ssl_config mbedtls_x509_crl *ca_crl; /*!< trusted CAs CRLs */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_ssl_async_sign_t *f_async_sign_start; /*!< start asynchronous signature operation */ + mbedtls_ssl_async_decrypt_t *f_async_decrypt_start; /*!< start asynchronous decryption operation */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + mbedtls_ssl_async_resume_t *f_async_resume; /*!< resume asynchronous operation */ + mbedtls_ssl_async_cancel_t *f_async_cancel; /*!< cancel asynchronous operation */ + void *p_async_config_data; /*!< Configuration data set by mbedtls_ssl_conf_async_private_cb(). */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) const int *sig_hashes; /*!< allowed signature hashes */ #endif @@ -673,10 +923,18 @@ struct mbedtls_ssl_config #endif #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) - unsigned char *psk; /*!< pre-shared key */ - size_t psk_len; /*!< length of the pre-shared key */ - unsigned char *psk_identity; /*!< identity for PSK negotiation */ - size_t psk_identity_len;/*!< length of identity */ + unsigned char *psk; /*!< pre-shared key. This field should + only be set via + mbedtls_ssl_conf_psk() */ + size_t psk_len; /*!< length of the pre-shared key. This + field should only be set via + mbedtls_ssl_conf_psk() */ + unsigned char *psk_identity; /*!< identity for PSK negotiation. This + field should only be set via + mbedtls_ssl_conf_psk() */ + size_t psk_identity_len;/*!< length of identity. This field should + only be set via + mbedtls_ssl_conf_psk() */ #endif #if defined(MBEDTLS_SSL_ALPN) @@ -774,14 +1032,14 @@ struct mbedtls_ssl_context int renego_records_seen; /*!< Records since renego request, or with DTLS, number of retransmissions of request if renego_max_records is < 0 */ -#endif +#endif /* MBEDTLS_SSL_RENEGOTIATION */ int major_ver; /*!< equal to MBEDTLS_SSL_MAJOR_VERSION_3 */ int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ #if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) unsigned badmac_seen; /*!< records with a bad MAC received */ -#endif +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ mbedtls_ssl_send_t *f_send; /*!< Callback for network send */ mbedtls_ssl_recv_t *f_recv; /*!< Callback for network receive */ @@ -837,11 +1095,11 @@ struct mbedtls_ssl_context uint16_t in_epoch; /*!< DTLS epoch for incoming records */ size_t next_record_offset; /*!< offset of the next record in datagram (equal to in_left if none) */ -#endif +#endif /* MBEDTLS_SSL_PROTO_DTLS */ #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) uint64_t in_window_top; /*!< last validated record seq_num */ uint64_t in_window; /*!< bitmask for replay detection */ -#endif +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ size_t in_hslen; /*!< current handshake message length, including the handshake header */ @@ -850,6 +1108,11 @@ struct mbedtls_ssl_context int keep_current_message; /*!< drop or reuse current message on next call to record layer? */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint8_t disable_datagram_packing; /*!< Disable packing multiple records + * within a single datagram. */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + /* * Record layer (outgoing data) */ @@ -864,12 +1127,18 @@ struct mbedtls_ssl_context size_t out_msglen; /*!< record header: message length */ size_t out_left; /*!< amount of data not yet written */ + unsigned char cur_out_ctr[8]; /*!< Outgoing record sequence number. */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint16_t mtu; /*!< path mtu, used to fragment outgoing messages */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + #if defined(MBEDTLS_ZLIB_SUPPORT) unsigned char *compress_buf; /*!< zlib data buffer */ -#endif +#endif /* MBEDTLS_ZLIB_SUPPORT */ #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) signed char split_done; /*!< current record already splitted? */ -#endif +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ /* * PKI layer @@ -882,11 +1151,11 @@ struct mbedtls_ssl_context #if defined(MBEDTLS_X509_CRT_PARSE_C) char *hostname; /*!< expected peer CN for verification (and SNI if available) */ -#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_ALPN) const char *alpn_chosen; /*!< negotiated protocol */ -#endif +#endif /* MBEDTLS_SSL_ALPN */ /* * Information for DTLS hello verify @@ -894,7 +1163,7 @@ struct mbedtls_ssl_context #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) unsigned char *cli_id; /*!< transport-level ID of the client */ size_t cli_id_len; /*!< length of cli_id */ -#endif +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ /* * Secure renegotiation @@ -906,7 +1175,7 @@ struct mbedtls_ssl_context size_t verify_data_len; /*!< length of verify data stored */ char own_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ char peer_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ -#endif +#endif /* MBEDTLS_SSL_RENEGOTIATION */ }; #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) @@ -1126,6 +1395,52 @@ void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, mbedtls_ssl_recv_t *f_recv, mbedtls_ssl_recv_timeout_t *f_recv_timeout ); +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/** + * \brief Set the Maximum Tranport Unit (MTU). + * Special value: 0 means unset (no limit). + * This represents the maximum size of a datagram payload + * handled by the transport layer (usually UDP) as determined + * by the network link and stack. In practice, this controls + * the maximum size datagram the DTLS layer will pass to the + * \c f_send() callback set using \c mbedtls_ssl_set_bio(). + * + * \note The limit on datagram size is converted to a limit on + * record payload by subtracting the current overhead of + * encapsulation and encryption/authentication if any. + * + * \note This can be called at any point during the connection, for + * example when a Path Maximum Transfer Unit (PMTU) + * estimate becomes available from other sources, + * such as lower (or higher) protocol layers. + * + * \note This setting only controls the size of the packets we send, + * and does not restrict the size of the datagrams we're + * willing to receive. Client-side, you can request the + * server to use smaller records with \c + * mbedtls_ssl_conf_max_frag_len(). + * + * \note If both a MTU and a maximum fragment length have been + * configured (or negotiated with the peer), the resulting + * lower limit on record payload (see first note) is used. + * + * \note This can only be used to decrease the maximum size + * of datagrams (hence records, see first note) sent. It + * cannot be used to increase the maximum size of records over + * the limit set by #MBEDTLS_SSL_OUT_CONTENT_LEN. + * + * \note Values lower than the current record layer expansion will + * result in an error when trying to send data. + * + * \note Using record compression together with a non-zero MTU value + * will result in an error when trying to send data. + * + * \param ssl SSL context + * \param mtu Value of the path MTU in bytes + */ +void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + /** * \brief Set the timeout period for mbedtls_ssl_read() * (Default: no timeout.) @@ -1289,6 +1604,85 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, void *p_export_keys ); #endif /* MBEDTLS_SSL_EXPORT_KEYS */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +/** + * \brief Configure asynchronous private key operation callbacks. + * + * \param conf SSL configuration context + * \param f_async_sign Callback to start a signature operation. See + * the description of ::mbedtls_ssl_async_sign_t + * for more information. This may be \c NULL if the + * external processor does not support any signature + * operation; in this case the private key object + * associated with the certificate will be used. + * \param f_async_decrypt Callback to start a decryption operation. See + * the description of ::mbedtls_ssl_async_decrypt_t + * for more information. This may be \c NULL if the + * external processor does not support any decryption + * operation; in this case the private key object + * associated with the certificate will be used. + * \param f_async_resume Callback to resume an asynchronous operation. See + * the description of ::mbedtls_ssl_async_resume_t + * for more information. This may not be \c NULL unless + * \p f_async_sign and \p f_async_decrypt are both + * \c NULL. + * \param f_async_cancel Callback to cancel an asynchronous operation. See + * the description of ::mbedtls_ssl_async_cancel_t + * for more information. This may be \c NULL if + * no cleanup is needed. + * \param config_data A pointer to configuration data which can be + * retrieved with + * mbedtls_ssl_conf_get_async_config_data(). The + * library stores this value without dereferencing it. + */ +void mbedtls_ssl_conf_async_private_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_async_sign_t *f_async_sign, + mbedtls_ssl_async_decrypt_t *f_async_decrypt, + mbedtls_ssl_async_resume_t *f_async_resume, + mbedtls_ssl_async_cancel_t *f_async_cancel, + void *config_data ); + +/** + * \brief Retrieve the configuration data set by + * mbedtls_ssl_conf_async_private_cb(). + * + * \param conf SSL configuration context + * \return The configuration data set by + * mbedtls_ssl_conf_async_private_cb(). + */ +void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ); + +/** + * \brief Retrieve the asynchronous operation user context. + * + * \note This function may only be called while a handshake + * is in progress. + * + * \param ssl The SSL context to access. + * + * \return The asynchronous operation user context that was last + * set during the current handshake. If + * mbedtls_ssl_set_async_operation_data() has not yet been + * called during the current handshake, this function returns + * \c NULL. + */ +void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl ); + +/** + * \brief Retrieve the asynchronous operation user context. + * + * \note This function may only be called while a handshake + * is in progress. + * + * \param ssl The SSL context to access. + * \param ctx The new value of the asynchronous operation user context. + * Call mbedtls_ssl_get_async_operation_data() later during the + * same handshake to retrieve this value. + */ +void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl, + void *ctx ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + /** * \brief Callback type: generate a cookie * @@ -1430,6 +1824,38 @@ void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limi #endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ #if defined(MBEDTLS_SSL_PROTO_DTLS) + +/** + * \brief Allow or disallow packing of multiple handshake records + * within a single datagram. + * + * \param ssl The SSL context to configure. + * \param allow_packing This determines whether datagram packing may + * be used or not. A value of \c 0 means that every + * record will be sent in a separate datagram; a + * value of \c 1 means that, if space permits, + * multiple handshake messages (including CCS) belonging to + * a single flight may be packed within a single datagram. + * + * \note This is enabled by default and should only be disabled + * for test purposes, or if datagram packing causes + * interoperability issues with peers that don't support it. + * + * \note Allowing datagram packing reduces the network load since + * there's less overhead if multiple messages share the same + * datagram. Also, it increases the handshake efficiency + * since messages belonging to a single datagram will not + * be reordered in transit, and so future message buffering + * or flight retransmission (if no buffering is used) as + * means to deal with reordering are needed less frequently. + * + * \note Application records are not affected by this option and + * are currently always sent in separate datagrams. + * + */ +void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl, + unsigned allow_packing ); + /** * \brief Set retransmit timeout values for the DTLS handshake. * (DTLS only, no effect on TLS.) @@ -1607,7 +2033,7 @@ void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, * provision more than one cert/key pair (eg one ECDSA, one * RSA with SHA-256, one RSA with SHA-1). An adequate * certificate will be selected according to the client's - * advertised capabilities. In case mutliple certificates are + * advertised capabilities. In case multiple certificates are * adequate, preference is given to the one set by the first * call to this function, then second, etc. * @@ -1842,7 +2268,7 @@ void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, * * \param ssl SSL context * \param hostname the server hostname, may be NULL to clear hostname - * + * \note Maximum hostname length MBEDTLS_SSL_MAX_HOST_NAME_LEN. * * \return 0 if successful, MBEDTLS_ERR_SSL_ALLOC_FAILED on @@ -2106,12 +2532,31 @@ void mbedtls_ssl_conf_cert_req_ca_list( mbedtls_ssl_config *conf, #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) /** - * \brief Set the maximum fragment length to emit and/or negotiate - * (Default: MBEDTLS_SSL_MAX_CONTENT_LEN, usually 2^14 bytes) + * \brief Set the maximum fragment length to emit and/or negotiate. + * (Typical: the smaller of #MBEDTLS_SSL_IN_CONTENT_LEN and + * #MBEDTLS_SSL_OUT_CONTENT_LEN, usually `2^14` bytes) * (Server: set maximum fragment length to emit, - * usually negotiated by the client during handshake + * usually negotiated by the client during handshake) * (Client: set maximum fragment length to emit *and* * negotiate with the server during handshake) + * (Default: #MBEDTLS_SSL_MAX_FRAG_LEN_NONE) + * + * \note On the client side, the maximum fragment length extension + * *will not* be used, unless the maximum fragment length has + * been set via this function to a value different than + * #MBEDTLS_SSL_MAX_FRAG_LEN_NONE. + * + * \note This sets the maximum length for a record's payload, + * excluding record overhead that will be added to it, see + * \c mbedtls_ssl_get_record_expansion(). + * + * \note With TLS, this currently only affects ApplicationData (sent + * with \c mbedtls_ssl_read()), not handshake messages. + * With DTLS, this affects both ApplicationData and handshake. + * + * \note For DTLS, it is also possible to set a limit for the total + * size of daragrams passed to the transport layer, including + * record overhead, see \c mbedtls_ssl_set_mtu(). * * \param conf SSL configuration * \param mfl_code Code for maximum fragment length (allowed values: @@ -2284,11 +2729,59 @@ void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, #endif /* MBEDTLS_SSL_RENEGOTIATION */ /** - * \brief Return the number of data bytes available to read + * \brief Check if there is data already read from the + * underlying transport but not yet processed. + * + * \param ssl SSL context + * + * \return 0 if nothing's pending, 1 otherwise. + * + * \note This is different in purpose and behaviour from + * \c mbedtls_ssl_get_bytes_avail in that it considers + * any kind of unprocessed data, not only unread + * application data. If \c mbedtls_ssl_get_bytes + * returns a non-zero value, this function will + * also signal pending data, but the converse does + * not hold. For example, in DTLS there might be + * further records waiting to be processed from + * the current underlying transport's datagram. + * + * \note If this function returns 1 (data pending), this + * does not imply that a subsequent call to + * \c mbedtls_ssl_read will provide any data; + * e.g., the unprocessed data might turn out + * to be an alert or a handshake message. + * + * \note This function is useful in the following situation: + * If the SSL/TLS module successfully returns from an + * operation - e.g. a handshake or an application record + * read - and you're awaiting incoming data next, you + * must not immediately idle on the underlying transport + * to have data ready, but you need to check the value + * of this function first. The reason is that the desired + * data might already be read but not yet processed. + * If, in contrast, a previous call to the SSL/TLS module + * returned MBEDTLS_ERR_SSL_WANT_READ, it is not necessary + * to call this function, as the latter error code entails + * that all internal data has been processed. + * + */ +int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the number of application data bytes + * remaining to be read from the current record. * * \param ssl SSL context * - * \return how many bytes are available in the read buffer + * \return How many bytes are available in the application + * data record read buffer. + * + * \note When working over a datagram transport, this is + * useful to detect the current datagram's boundary + * in case \c mbedtls_ssl_read has written the maximal + * amount of data fitting into the input buffer. + * */ size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ); @@ -2328,6 +2821,9 @@ const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ); * \brief Return the (maximum) number of bytes added by the record * layer: header + encryption/MAC overhead (inc. padding) * + * \note This function is not available (always returns an error) + * when record compression is enabled. + * * \param ssl SSL context * * \return Current maximum record expansion in bytes, or @@ -2342,6 +2838,23 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); * This is the value negotiated with peer if any, * or the locally configured value. * + * \sa mbedtls_ssl_conf_max_frag_len() + * \sa mbedtls_ssl_get_max_record_payload() + * + * \param ssl SSL context + * + * \return Current maximum fragment length. + */ +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +/** + * \brief Return the current maximum outgoing record payload in bytes. + * This takes into account the config.h setting \c + * MBEDTLS_SSL_OUT_CONTENT_LEN, the configured and negotiated + * max fragment length extension if used, and for DTLS the + * path MTU as configured and current record expansion. + * * \note With DTLS, \c mbedtls_ssl_write() will return an error if * called with a larger length value. * With TLS, \c mbedtls_ssl_write() will fragment the input if @@ -2349,12 +2862,19 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); * to the caller to call \c mbedtls_ssl_write() again in * order to send the remaining bytes if any. * + * \note This function is not available (always returns an error) + * when record compression is enabled. + * + * \sa mbedtls_ssl_set_mtu() + * \sa mbedtls_ssl_get_max_frag_len() + * \sa mbedtls_ssl_get_record_expansion() + * * \param ssl SSL context * - * \return Current maximum fragment length. + * \return Current maximum payload for an outgoing record, + * or a negative error code. */ -size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); -#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ); #if defined(MBEDTLS_X509_CRT_PARSE_C) /** @@ -2409,21 +2929,50 @@ int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session * * \param ssl SSL context * - * \return 0 if successful, or - * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or - * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED (see below), or - * a specific SSL error code. - * - * \note If this function returns something other than 0 or - * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context - * becomes unusable, and you should either free it or call - * \c mbedtls_ssl_session_reset() on it before re-using it for - * a new connection; the current connection must be closed. + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE + * if the handshake is incomplete and waiting for data to + * be available for reading from or writing to the underlying + * transport - in this case you must call this function again + * when the underlying transport is ready for the operation. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous + * operation is in progress (see + * mbedtls_ssl_conf_async_private_cb()) - in this case you + * must call this function again when the operation is ready. + * \return #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic + * operation is in progress (see mbedtls_ecp_set_max_ops()) - + * in this case you must call this function again to complete + * the handshake when you're done attending other tasks. + * \return #MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED if DTLS is in use + * and the client did not demonstrate reachability yet - in + * this case you must stop using the context (see below). + * \return Another SSL error code - in this case you must stop using + * the context (see below). + * + * \warning If this function returns something other than + * \c 0, + * #MBEDTLS_ERR_SSL_WANT_READ, + * #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, + * you must stop using the SSL context for reading or writing, + * and either free it or call \c mbedtls_ssl_session_reset() + * on it before re-using it for a new connection; the current + * connection must be closed. * * \note If DTLS is in use, then you may choose to handle - * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging + * #MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging * purposes, as it is an expected return value rather than an * actual error, but you still need to reset/free the context. + * + * \note Remarks regarding event-driven DTLS: + * If the function returns #MBEDTLS_ERR_SSL_WANT_READ, no datagram + * from the underlying transport layer is currently being processed, + * and it is safe to idle until the timer or the underlying transport + * signal a new event. This is not true for a successful handshake, + * in which case the datagram of the underlying transport that is + * currently being processed might or might not contain further + * DTLS records. */ int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ); @@ -2431,20 +2980,21 @@ int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ); * \brief Perform a single step of the SSL handshake * * \note The state of the context (ssl->state) will be at - * the next state after execution of this function. Do not + * the next state after this function returns \c 0. Do not * call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER. * - * \note If this function returns something other than 0 or - * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context - * becomes unusable, and you should either free it or call - * \c mbedtls_ssl_session_reset() on it before re-using it for - * a new connection; the current connection must be closed. - * * \param ssl SSL context * - * \return 0 if successful, or - * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or - * a specific SSL error code. + * \return See mbedtls_ssl_handshake(). + * + * \warning If this function returns something other than \c 0, + * #MBEDTLS_ERR_SSL_WANT_READ, #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, you must stop using + * the SSL context for reading or writing, and either free it + * or call \c mbedtls_ssl_session_reset() on it before + * re-using it for a new connection; the current connection + * must be closed. */ int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ); @@ -2459,13 +3009,18 @@ int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ); * \param ssl SSL context * * \return 0 if successful, or any mbedtls_ssl_handshake() return - * value. + * value except #MBEDTLS_ERR_SSL_CLIENT_RECONNECT that can't + * happen during a renegotiation. + * + * \warning If this function returns something other than \c 0, + * #MBEDTLS_ERR_SSL_WANT_READ, #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, you must stop using + * the SSL context for reading or writing, and either free it + * or call \c mbedtls_ssl_session_reset() on it before + * re-using it for a new connection; the current connection + * must be closed. * - * \note If this function returns something other than 0 or - * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context - * becomes unusable, and you should either free it or call - * \c mbedtls_ssl_session_reset() on it before re-using it for - * a new connection; the current connection must be closed. */ int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_RENEGOTIATION */ @@ -2477,32 +3032,68 @@ int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ); * \param buf buffer that will hold the data * \param len maximum number of bytes to read * - * \return the number of bytes read, or - * 0 for EOF, or - * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or - * MBEDTLS_ERR_SSL_CLIENT_RECONNECT (see below), or - * another negative error code. - * - * \note If this function returns something other than a positive - * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE or - * MBEDTLS_ERR_SSL_CLIENT_RECONNECT, then the ssl context - * becomes unusable, and you should either free it or call - * \c mbedtls_ssl_session_reset() on it before re-using it for - * a new connection; the current connection must be closed. - * - * \note When this function return MBEDTLS_ERR_SSL_CLIENT_RECONNECT + * \return The (positive) number of bytes read if successful. + * \return \c 0 if the read end of the underlying transport was closed + * - in this case you must stop using the context (see below). + * \return #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE + * if the handshake is incomplete and waiting for data to + * be available for reading from or writing to the underlying + * transport - in this case you must call this function again + * when the underlying transport is ready for the operation. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous + * operation is in progress (see + * mbedtls_ssl_conf_async_private_cb()) - in this case you + * must call this function again when the operation is ready. + * \return #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic + * operation is in progress (see mbedtls_ecp_set_max_ops()) - + * in this case you must call this function again to complete + * the handshake when you're done attending other tasks. + * \return #MBEDTLS_ERR_SSL_CLIENT_RECONNECT if we're at the server + * side of a DTLS connection and the client is initiating a + * new connection using the same source port. See below. + * \return Another SSL error code - in this case you must stop using + * the context (see below). + * + * \warning If this function returns something other than + * a positive value, + * #MBEDTLS_ERR_SSL_WANT_READ, + * #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CLIENT_RECONNECT, + * you must stop using the SSL context for reading or writing, + * and either free it or call \c mbedtls_ssl_session_reset() + * on it before re-using it for a new connection; the current + * connection must be closed. + * + * \note When this function returns #MBEDTLS_ERR_SSL_CLIENT_RECONNECT * (which can only happen server-side), it means that a client * is initiating a new connection using the same source port. * You can either treat that as a connection close and wait * for the client to resend a ClientHello, or directly * continue with \c mbedtls_ssl_handshake() with the same - * context (as it has beeen reset internally). Either way, you - * should make sure this is seen by the application as a new + * context (as it has been reset internally). Either way, you + * must make sure this is seen by the application as a new * connection: application state, if any, should be reset, and * most importantly the identity of the client must be checked * again. WARNING: not validating the identity of the client * again, or not transmitting the new identity to the * application layer, would allow authentication bypass! + * + * \note Remarks regarding event-driven DTLS: + * - If the function returns #MBEDTLS_ERR_SSL_WANT_READ, no datagram + * from the underlying transport layer is currently being processed, + * and it is safe to idle until the timer or the underlying transport + * signal a new event. + * - This function may return MBEDTLS_ERR_SSL_WANT_READ even if data was + * initially available on the underlying transport, as this data may have + * been only e.g. duplicated messages or a renegotiation request. + * Therefore, you must be prepared to receive MBEDTLS_ERR_SSL_WANT_READ even + * when reacting to an incoming-data event from the underlying transport. + * - On success, the datagram of the underlying transport that is currently + * being processed may contain further DTLS records. You should call + * \c mbedtls_ssl_check_pending to check for remaining records. + * */ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ); @@ -2519,21 +3110,39 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) * \param buf buffer holding the data * \param len how many bytes must be written * - * \return the number of bytes actually written (may be less than len), - * or MBEDTLS_ERR_SSL_WANT_WRITE or MBEDTLS_ERR_SSL_WANT_READ, - * or another negative error code. - * - * \note If this function returns something other than 0, a positive - * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop - * using the SSL context for reading or writing, and either - * free it or call \c mbedtls_ssl_session_reset() on it before - * re-using it for a new connection; the current connection - * must be closed. - * - * \note When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ, + * \return The (non-negative) number of bytes actually written if + * successful (may be less than \p len). + * \return #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE + * if the handshake is incomplete and waiting for data to + * be available for reading from or writing to the underlying + * transport - in this case you must call this function again + * when the underlying transport is ready for the operation. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous + * operation is in progress (see + * mbedtls_ssl_conf_async_private_cb()) - in this case you + * must call this function again when the operation is ready. + * \return #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic + * operation is in progress (see mbedtls_ecp_set_max_ops()) - + * in this case you must call this function again to complete + * the handshake when you're done attending other tasks. + * \return Another SSL error code - in this case you must stop using + * the context (see below). + * + * \warning If this function returns something other than + * a non-negative value, + * #MBEDTLS_ERR_SSL_WANT_READ, + * #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, + * you must stop using the SSL context for reading or writing, + * and either free it or call \c mbedtls_ssl_session_reset() + * on it before re-using it for a new connection; the current + * connection must be closed. + * + * \note When this function returns #MBEDTLS_ERR_SSL_WANT_WRITE/READ, * it must be called later with the *same* arguments, * until it returns a value greater that or equal to 0. When - * the function returns MBEDTLS_ERR_SSL_WANT_WRITE there may be + * the function returns #MBEDTLS_ERR_SSL_WANT_WRITE there may be * some partial data in the output buffer, however this is not * yet sent. * @@ -2561,10 +3170,10 @@ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_ * \return 0 if successful, or a specific SSL error code. * * \note If this function returns something other than 0 or - * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context - * becomes unusable, and you should either free it or call - * \c mbedtls_ssl_session_reset() on it before re-using it for - * a new connection; the current connection must be closed. + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop using + * the SSL context for reading or writing, and either free it or + * call \c mbedtls_ssl_session_reset() on it before re-using it + * for a new connection; the current connection must be closed. */ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, unsigned char level, @@ -2577,10 +3186,10 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, * \return 0 if successful, or a specific SSL error code. * * \note If this function returns something other than 0 or - * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context - * becomes unusable, and you should either free it or call - * \c mbedtls_ssl_session_reset() on it before re-using it for - * a new connection; the current connection must be closed. + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop using + * the SSL context for reading or writing, and either free it or + * call \c mbedtls_ssl_session_reset() on it before re-using it + * for a new connection; the current connection must be closed. */ int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ); @@ -2597,7 +3206,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ); * mbedtls_ssl_config_defaults() or mbedtls_ssl_config_free(). * * \note You need to call mbedtls_ssl_config_defaults() unless you - * manually set all of the relevent fields yourself. + * manually set all of the relevant fields yourself. * * \param conf SSL configuration context */ diff --git a/app/include/mbedtls/ssl_cache.h b/app/include/mbedtls/ssl_cache.h index ec081e6d24..52ba0948c5 100644 --- a/app/include/mbedtls/ssl_cache.h +++ b/app/include/mbedtls/ssl_cache.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_SSL_CACHE_H #define MBEDTLS_SSL_CACHE_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "ssl.h" #if defined(MBEDTLS_THREADING_C) diff --git a/app/include/mbedtls/ssl_ciphersuites.h b/app/include/mbedtls/ssl_ciphersuites.h index 1d2aabc372..71053e5ba7 100644 --- a/app/include/mbedtls/ssl_ciphersuites.h +++ b/app/include/mbedtls/ssl_ciphersuites.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_SSL_CIPHERSUITES_H #define MBEDTLS_SSL_CIPHERSUITES_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "pk.h" #include "cipher.h" #include "md.h" @@ -169,6 +175,45 @@ extern "C" { #define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 0xC03A /**< Weak! No SSL3! */ #define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 0xC03B /**< Weak! No SSL3! */ +#define MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256 0xC03C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384 0xC03D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 0xC044 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 0xC045 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 0xC048 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 0xC049 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 0xC04A /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 0xC04B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 0xC04C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 0xC04D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 0xC04E /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 0xC04F /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256 0xC050 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384 0xC051 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 0xC052 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 0xC053 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 0xC05C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 0xC05D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 0xC05E /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 0xC05F /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 0xC060 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 0xC061 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 0xC062 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 0xC063 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256 0xC064 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384 0xC065 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 0xC066 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 0xC067 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 0xC068 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 0xC069 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256 0xC06A /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384 0xC06B /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 0xC06C /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 0xC06D /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 0xC06E /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 0xC06F /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 0xC070 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 0xC071 /**< TLS 1.2 */ + #define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC072 /**< Not in SSL3! */ #define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC073 /**< Not in SSL3! */ #define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC074 /**< Not in SSL3! */ @@ -232,6 +277,15 @@ extern "C" { #define MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 0xC0FF /**< experimental */ +/* RFC 7905 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAB /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAC /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE /**< TLS 1.2 */ + /* Reminder: update mbedtls_ssl_premaster_secret when adding a new key exchange. * Reminder: update MBEDTLS_KEY_EXCHANGE__xxx below */ diff --git a/app/include/mbedtls/ssl_cookie.h b/app/include/mbedtls/ssl_cookie.h index 80b65bbbb9..e34760ae85 100644 --- a/app/include/mbedtls/ssl_cookie.h +++ b/app/include/mbedtls/ssl_cookie.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_SSL_COOKIE_H #define MBEDTLS_SSL_COOKIE_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "ssl.h" #if defined(MBEDTLS_THREADING_C) @@ -50,7 +56,7 @@ extern "C" { /** * \brief Context for the default cookie functions. */ -typedef struct +typedef struct mbedtls_ssl_cookie_ctx { mbedtls_md_context_t hmac_ctx; /*!< context for the HMAC portion */ #if !defined(MBEDTLS_HAVE_TIME) diff --git a/app/include/mbedtls/ssl_internal.h b/app/include/mbedtls/ssl_internal.h index 2b5a61637b..bd5ad94dbf 100644 --- a/app/include/mbedtls/ssl_internal.h +++ b/app/include/mbedtls/ssl_internal.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_SSL_INTERNAL_H #define MBEDTLS_SSL_INTERNAL_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + #include "ssl.h" #include "cipher.h" @@ -93,6 +99,14 @@ #endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +/* Shorthand for restartable ECC */ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_SSL_CLI_C) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +#define MBEDTLS_SSL__ECP_RESTARTABLE +#endif + #define MBEDTLS_SSL_INITIAL_HANDSHAKE 0 #define MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS 1 /* In progress */ #define MBEDTLS_SSL_RENEGOTIATION_DONE 2 /* Done or aborted */ @@ -143,32 +157,76 @@ #define MBEDTLS_SSL_PADDING_ADD 0 #endif -#define MBEDTLS_SSL_PAYLOAD_LEN ( MBEDTLS_SSL_MAX_CONTENT_LEN \ - + MBEDTLS_SSL_COMPRESSION_ADD \ - + MBEDTLS_MAX_IV_LENGTH \ - + MBEDTLS_SSL_MAC_ADD \ - + MBEDTLS_SSL_PADDING_ADD \ - ) +#define MBEDTLS_SSL_PAYLOAD_OVERHEAD ( MBEDTLS_SSL_COMPRESSION_ADD + \ + MBEDTLS_MAX_IV_LENGTH + \ + MBEDTLS_SSL_MAC_ADD + \ + MBEDTLS_SSL_PADDING_ADD \ + ) + +#define MBEDTLS_SSL_IN_PAYLOAD_LEN ( MBEDTLS_SSL_PAYLOAD_OVERHEAD + \ + ( MBEDTLS_SSL_IN_CONTENT_LEN ) ) + +#define MBEDTLS_SSL_OUT_PAYLOAD_LEN ( MBEDTLS_SSL_PAYLOAD_OVERHEAD + \ + ( MBEDTLS_SSL_OUT_CONTENT_LEN ) ) + +/* The maximum number of buffered handshake messages. */ +#define MBEDTLS_SSL_MAX_BUFFERED_HS 4 + +/* Maximum length we can advertise as our max content length for + RFC 6066 max_fragment_length extension negotiation purposes + (the lesser of both sizes, if they are unequal.) + */ +#define MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ( \ + (MBEDTLS_SSL_IN_CONTENT_LEN > MBEDTLS_SSL_OUT_CONTENT_LEN) \ + ? ( MBEDTLS_SSL_OUT_CONTENT_LEN ) \ + : ( MBEDTLS_SSL_IN_CONTENT_LEN ) \ + ) /* * Check that we obey the standard's message size bounds */ #if MBEDTLS_SSL_MAX_CONTENT_LEN > 16384 -#error Bad configuration - record content too large. +#error "Bad configuration - record content too large." +#endif + +#if MBEDTLS_SSL_IN_CONTENT_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN +#error "Bad configuration - incoming record content should not be larger than MBEDTLS_SSL_MAX_CONTENT_LEN." +#endif + +#if MBEDTLS_SSL_OUT_CONTENT_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN +#error "Bad configuration - outgoing record content should not be larger than MBEDTLS_SSL_MAX_CONTENT_LEN." #endif -#if MBEDTLS_SSL_PAYLOAD_LEN > 16384 + 2048 -#error Bad configuration - protected record payload too large. +#if MBEDTLS_SSL_IN_PAYLOAD_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN + 2048 +#error "Bad configuration - incoming protected record payload too large." #endif +#if MBEDTLS_SSL_OUT_PAYLOAD_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN + 2048 +#error "Bad configuration - outgoing protected record payload too large." +#endif + +/* Calculate buffer sizes */ + /* Note: Even though the TLS record header is only 5 bytes long, we're internally using 8 bytes to store the implicit sequence number. */ #define MBEDTLS_SSL_HEADER_LEN 13 -#define MBEDTLS_SSL_BUFFER_LEN \ - ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_PAYLOAD_LEN ) ) +#define MBEDTLS_SSL_IN_BUFFER_LEN \ + ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_IN_PAYLOAD_LEN ) ) + +#define MBEDTLS_SSL_OUT_BUFFER_LEN \ + ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_OUT_PAYLOAD_LEN ) ) + +#ifdef MBEDTLS_ZLIB_SUPPORT +/* Compression buffer holds both IN and OUT buffers, so should be size of the larger */ +#define MBEDTLS_SSL_COMPRESS_BUFFER_LEN ( \ + ( MBEDTLS_SSL_IN_BUFFER_LEN > MBEDTLS_SSL_OUT_BUFFER_LEN ) \ + ? MBEDTLS_SSL_IN_BUFFER_LEN \ + : MBEDTLS_SSL_OUT_BUFFER_LEN \ + ) +#endif /* * TLS extension flags (for extensions with outgoing ServerHello content @@ -243,6 +301,18 @@ struct mbedtls_ssl_handshake_params mbedtls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + int ecrs_enabled; /*!< Handshake supports EC restart? */ + mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ + enum { /* this complements ssl->state with info on intra-state operations */ + ssl_ecrs_none = 0, /*!< nothing going on (yet) */ + ssl_ecrs_crt_verify, /*!< Certificate: crt_verify() */ + ssl_ecrs_ske_start_processing, /*!< ServerKeyExchange: pk_verify() */ + ssl_ecrs_cke_ecdh_calc_secret, /*!< ClientKeyExchange: ECDH step 2 */ + ssl_ecrs_crt_vrfy_sign, /*!< CertificateVerify: pk_sign() */ + } ecrs_state; /*!< current (or last) operation */ + size_t ecrs_n; /*!< place for saving a length */ +#endif #if defined(MBEDTLS_SSL_PROTO_DTLS) unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ @@ -252,18 +322,45 @@ struct mbedtls_ssl_handshake_params unsigned char verify_cookie_len; /*!< Cli: cookie length Srv: flag for sending a cookie */ - unsigned char *hs_msg; /*!< Reassembled handshake message */ - uint32_t retransmit_timeout; /*!< Current value of timeout */ unsigned char retransmit_state; /*!< Retransmission state */ - mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */ - mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */ + mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */ + mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */ + unsigned char *cur_msg_p; /*!< Position in current message */ unsigned int in_flight_start_seq; /*!< Minimum message sequence in the flight being received */ mbedtls_ssl_transform *alt_transform_out; /*!< Alternative transform for resending messages */ unsigned char alt_out_ctr[8]; /*!< Alternative record epoch/counter for resending messages */ + + struct + { + size_t total_bytes_buffered; /*!< Cumulative size of heap allocated + * buffers used for message buffering. */ + + uint8_t seen_ccs; /*!< Indicates if a CCS message has + * been seen in the current flight. */ + + struct mbedtls_ssl_hs_buffer + { + unsigned is_valid : 1; + unsigned is_fragmented : 1; + unsigned is_complete : 1; + unsigned char *data; + size_t data_len; + } hs[MBEDTLS_SSL_MAX_BUFFERED_HS]; + + struct + { + unsigned char *data; + size_t len; + unsigned epoch; + } future_record; + + } buffering; + + uint16_t mtu; /*!< Handshake mtu, used to fragment outgoing messages */ #endif /* MBEDTLS_SSL_PROTO_DTLS */ /* @@ -307,8 +404,23 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) int extended_ms; /*!< use Extended Master Secret? */ #endif + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + unsigned int async_in_progress : 1; /*!< an asynchronous operation is in progress */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + /** Asynchronous operation context. This field is meant for use by the + * asynchronous operation callbacks (mbedtls_ssl_config::f_async_sign_start, + * mbedtls_ssl_config::f_async_decrypt_start, + * mbedtls_ssl_config::f_async_resume, mbedtls_ssl_config::f_async_cancel). + * The library does not use it internally. */ + void *user_async_ctx; +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ }; +typedef struct mbedtls_ssl_hs_buffer mbedtls_ssl_hs_buffer; + /* * This structure contains a full set of runtime transform parameters * either in negotiation or active. @@ -410,9 +522,9 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); * \brief Free referenced items in an SSL handshake context and clear * memory * - * \param handshake SSL handshake context + * \param ssl SSL context */ -void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ); +void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ); int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ); int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ); @@ -423,7 +535,6 @@ int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ); void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ); int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ); -int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ); int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ); int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ); void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ); @@ -435,7 +546,10 @@ void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ); * of the logic of (D)TLS from the implementation * of the secure transport. * - * \param ssl SSL context to use + * \param ssl The SSL context to use. + * \param update_hs_digest This indicates if the handshake digest + * should be automatically updated in case + * a handshake message is found. * * \return 0 or non-zero error code. * @@ -501,10 +615,12 @@ void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ); * following the above definition. * */ -int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, + unsigned update_hs_digest ); int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ); -int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ); int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ); int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ); @@ -613,6 +729,7 @@ static inline size_t mbedtls_ssl_hs_hdr_len( const mbedtls_ssl_context *ssl ) void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ); void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ); int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ); #endif /* Visible for testing purposes only */ @@ -652,9 +769,9 @@ int mbedtls_ssl_get_key_exchange_md_ssl_tls( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_2) int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, - unsigned char *output, - unsigned char *data, size_t data_len, - mbedtls_md_type_t md_alg ); + unsigned char *hash, size_t *hashlen, + unsigned char *data, size_t data_len, + mbedtls_md_type_t md_alg ); #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ MBEDTLS_SSL_PROTO_TLS1_2 */ diff --git a/app/include/mbedtls/ssl_ticket.h b/app/include/mbedtls/ssl_ticket.h index 93ad46ac9c..774a007a9f 100644 --- a/app/include/mbedtls/ssl_ticket.h +++ b/app/include/mbedtls/ssl_ticket.h @@ -24,6 +24,12 @@ #ifndef MBEDTLS_SSL_TICKET_H #define MBEDTLS_SSL_TICKET_H +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + /* * This implementation of the session ticket callbacks includes key * management, rotating the keys periodically in order to preserve forward @@ -44,7 +50,7 @@ extern "C" { /** * \brief Information for session ticket protection */ -typedef struct +typedef struct mbedtls_ssl_ticket_key { unsigned char name[4]; /*!< random key identifier */ uint32_t generation_time; /*!< key generation timestamp (seconds) */ @@ -55,7 +61,7 @@ mbedtls_ssl_ticket_key; /** * \brief Context for session ticket handling functions */ -typedef struct +typedef struct mbedtls_ssl_ticket_context { mbedtls_ssl_ticket_key keys[2]; /*!< ticket protection keys */ unsigned char active; /*!< index of the currently active key */ @@ -111,14 +117,14 @@ int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, /** * \brief Implementation of the ticket write callback * - * \note See \c mbedlts_ssl_ticket_write_t for description + * \note See \c mbedtls_ssl_ticket_write_t for description */ mbedtls_ssl_ticket_write_t mbedtls_ssl_ticket_write; /** * \brief Implementation of the ticket parse callback * - * \note See \c mbedlts_ssl_ticket_parse_t for description + * \note See \c mbedtls_ssl_ticket_parse_t for description */ mbedtls_ssl_ticket_parse_t mbedtls_ssl_ticket_parse; diff --git a/app/include/mbedtls/threading.h b/app/include/mbedtls/threading.h index aeea5d0e1a..92e6e6b987 100644 --- a/app/include/mbedtls/threading.h +++ b/app/include/mbedtls/threading.h @@ -36,13 +36,16 @@ extern "C" { #endif +/* MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ #define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE -0x001A /**< The selected feature is not available. */ + #define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA -0x001C /**< Bad input parameters to function. */ #define MBEDTLS_ERR_THREADING_MUTEX_ERROR -0x001E /**< Locking / unlocking / free failed with error code. */ #if defined(MBEDTLS_THREADING_PTHREAD) #include -typedef struct +typedef struct mbedtls_threading_mutex_t { pthread_mutex_t mutex; char is_valid; @@ -99,9 +102,17 @@ extern int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t *mutex ); #if defined(MBEDTLS_FS_IO) extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex; #endif -#if defined(MBEDTLS_HAVE_TIME_DATE) + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) +/* This mutex may or may not be used in the default definition of + * mbedtls_platform_gmtime_r(), but in order to determine that, + * we need to check POSIX features, hence modify _POSIX_C_SOURCE. + * With the current approach, this declaration is orphaned, lacking + * an accompanying definition, in case mbedtls_platform_gmtime_r() + * doesn't need it, but that's not a problem. */ extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex; -#endif +#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */ + #endif /* MBEDTLS_THREADING_C */ #ifdef __cplusplus diff --git a/app/include/mbedtls/timing.h b/app/include/mbedtls/timing.h index 2c497bf4eb..a965fe0d35 100644 --- a/app/include/mbedtls/timing.h +++ b/app/include/mbedtls/timing.h @@ -30,16 +30,16 @@ #include MBEDTLS_CONFIG_FILE #endif -#if !defined(MBEDTLS_TIMING_ALT) -// Regular implementation -// - #include #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_TIMING_ALT) +// Regular implementation +// + /** * \brief timer structure */ @@ -51,13 +51,17 @@ struct mbedtls_timing_hr_time /** * \brief Context for mbedtls_timing_set/get_delay() */ -typedef struct +typedef struct mbedtls_timing_delay_context { struct mbedtls_timing_hr_time timer; uint32_t int_ms; uint32_t fin_ms; } mbedtls_timing_delay_context; +#else /* MBEDTLS_TIMING_ALT */ +#include "timing_alt.h" +#endif /* MBEDTLS_TIMING_ALT */ + extern volatile int mbedtls_timing_alarmed; /** @@ -133,18 +137,6 @@ void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ); */ int mbedtls_timing_get_delay( void *data ); -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_TIMING_ALT */ -#include "timing_alt.h" -#endif /* MBEDTLS_TIMING_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - #if defined(MBEDTLS_SELF_TEST) /** * \brief Checkup routine diff --git a/app/include/mbedtls/version.h b/app/include/mbedtls/version.h index 36feff0d82..b4eef71e50 100644 --- a/app/include/mbedtls/version.h +++ b/app/include/mbedtls/version.h @@ -39,17 +39,17 @@ * Major, Minor, Patchlevel */ #define MBEDTLS_VERSION_MAJOR 2 -#define MBEDTLS_VERSION_MINOR 7 -#define MBEDTLS_VERSION_PATCH 9 +#define MBEDTLS_VERSION_MINOR 16 +#define MBEDTLS_VERSION_PATCH 3 /** * The single version number has the following structure: * MMNNPP00 * Major version | Minor version | Patch version */ -#define MBEDTLS_VERSION_NUMBER 0x02070900 -#define MBEDTLS_VERSION_STRING "2.7.9" -#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.7.9" +#define MBEDTLS_VERSION_NUMBER 0x02100300 +#define MBEDTLS_VERSION_STRING "2.16.3" +#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.16.3" #if defined(MBEDTLS_VERSION_C) diff --git a/app/include/mbedtls/x509.h b/app/include/mbedtls/x509.h index d6db9c6e37..63aae32d87 100644 --- a/app/include/mbedtls/x509.h +++ b/app/include/mbedtls/x509.h @@ -77,7 +77,7 @@ #define MBEDTLS_ERR_X509_ALLOC_FAILED -0x2880 /**< Allocation of memory failed. */ #define MBEDTLS_ERR_X509_FILE_IO_ERROR -0x2900 /**< Read/write of file failed. */ #define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL -0x2980 /**< Destination buffer is too small. */ -#define MBEDTLS_ERR_X509_FATAL_ERROR -0x3000 /**< A fatal error occured, eg the chain is too long or the vrfy callback failed. */ +#define MBEDTLS_ERR_X509_FATAL_ERROR -0x3000 /**< A fatal error occurred, eg the chain is too long or the vrfy callback failed. */ /* \} name */ /** @@ -250,7 +250,7 @@ int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *se * * \param to mbedtls_x509_time to check * - * \return 1 if the given time is in the past or an error occured, + * \return 1 if the given time is in the past or an error occurred, * 0 otherwise. */ int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ); @@ -264,11 +264,13 @@ int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ); * * \param from mbedtls_x509_time to check * - * \return 1 if the given time is in the future or an error occured, + * \return 1 if the given time is in the future or an error occurred, * 0 otherwise. */ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ); +#if defined(MBEDTLS_SELF_TEST) + /** * \brief Checkup routine * @@ -276,6 +278,8 @@ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ); */ int mbedtls_x509_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + /* * Internal module functions. You probably do not want to use these unless you * know you do. diff --git a/app/include/mbedtls/x509_crl.h b/app/include/mbedtls/x509_crl.h index 08a4283a67..fa838d68cb 100644 --- a/app/include/mbedtls/x509_crl.h +++ b/app/include/mbedtls/x509_crl.h @@ -111,7 +111,7 @@ int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, /** * \brief Parse one or more CRLs and append them to the chained list * - * \note Mutliple CRLs are accepted only if using PEM format + * \note Multiple CRLs are accepted only if using PEM format * * \param chain points to the start of the chain * \param buf buffer holding the CRL data in PEM or DER format @@ -126,7 +126,7 @@ int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, s /** * \brief Load one or more CRLs and append them to the chained list * - * \note Mutliple CRLs are accepted only if using PEM format + * \note Multiple CRLs are accepted only if using PEM format * * \param chain points to the start of the chain * \param path filename to read the CRLs from (in PEM or DER encoding) diff --git a/app/include/mbedtls/x509_crt.h b/app/include/mbedtls/x509_crt.h index 2c3c758e9e..670bd10d89 100644 --- a/app/include/mbedtls/x509_crt.h +++ b/app/include/mbedtls/x509_crt.h @@ -98,14 +98,14 @@ mbedtls_x509_crt; * Build flag from an algorithm/curve identifier (pk, md, ecp) * Since 0 is always XXX_NONE, ignore it. */ -#define MBEDTLS_X509_ID_FLAG( id ) ( 1 << ( id - 1 ) ) +#define MBEDTLS_X509_ID_FLAG( id ) ( 1 << ( (id) - 1 ) ) /** * Security profile for certificate verification. * * All lists are bitfields, built by ORing flags from MBEDTLS_X509_ID_FLAG(). */ -typedef struct +typedef struct mbedtls_x509_crt_profile { uint32_t allowed_mds; /**< MDs for signatures */ uint32_t allowed_pks; /**< PK algs for signatures */ @@ -143,6 +143,63 @@ typedef struct mbedtls_x509write_cert } mbedtls_x509write_cert; +/** + * Item in a verification chain: cert and flags for it + */ +typedef struct { + mbedtls_x509_crt *crt; + uint32_t flags; +} mbedtls_x509_crt_verify_chain_item; + +/** + * Max size of verification chain: end-entity + intermediates + trusted root + */ +#define MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 ) + +/** + * Verification chain as built by \c mbedtls_crt_verify_chain() + */ +typedef struct +{ + mbedtls_x509_crt_verify_chain_item items[MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE]; + unsigned len; +} mbedtls_x509_crt_verify_chain; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Context for resuming X.509 verify operations + */ +typedef struct +{ + /* for check_signature() */ + mbedtls_pk_restart_ctx pk; + + /* for find_parent_in() */ + mbedtls_x509_crt *parent; /* non-null iff parent_in in progress */ + mbedtls_x509_crt *fallback_parent; + int fallback_signature_is_good; + + /* for find_parent() */ + int parent_is_trusted; /* -1 if find_parent is not in progress */ + + /* for verify_chain() */ + enum { + x509_crt_rs_none, + x509_crt_rs_find_parent, + } in_progress; /* none if no operation is in progress */ + int self_cnt; + mbedtls_x509_crt_verify_chain ver_chain; + +} mbedtls_x509_crt_restart_ctx; + +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +/* Now we can declare functions that take a pointer to that */ +typedef void mbedtls_x509_crt_restart_ctx; + +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) /** * Default security profile. Should provide a good balance between security @@ -368,6 +425,37 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), void *p_vrfy ); +/** + * \brief Restartable version of \c mbedtls_crt_verify_with_profile() + * + * \note Performs the same job as \c mbedtls_crt_verify_with_profile() + * but can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param crt a certificate (chain) to be verified + * \param trust_ca the list of trusted CAs + * \param ca_crl the list of CRLs for trusted CAs + * \param profile security profile for verification + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * \param rs_ctx restart context (NULL to disable restart) + * + * \return See \c mbedtls_crt_verify_with_profile(), or + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + */ +int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy, + mbedtls_x509_crt_restart_ctx *rs_ctx ); + #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) /** * \brief Check usage of certificate against keyUsage extension. @@ -439,6 +527,18 @@ void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ); * \param crt Certificate chain to free */ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context + */ +void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ); + +/** + * \brief Free the components of a restart context + */ +void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ /* \} name */ diff --git a/app/include/mbedtls/x509_csr.h b/app/include/mbedtls/x509_csr.h index 0c6ccad78d..a3c28048e0 100644 --- a/app/include/mbedtls/x509_csr.h +++ b/app/include/mbedtls/x509_csr.h @@ -205,6 +205,14 @@ void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_ty * \param key_usage key usage flags to set * * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + * + * \note The decipherOnly flag from the Key Usage + * extension is represented by bit 8 (i.e. + * 0x8000), which cannot typically be represented + * in an unsigned char. Therefore, the flag + * decipherOnly (i.e. + * #MBEDTLS_X509_KU_DECIPHER_ONLY) cannot be set using this + * function. */ int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ); diff --git a/app/include/mbedtls/xtea.h b/app/include/mbedtls/xtea.h index 34ccee3c22..b47f553508 100644 --- a/app/include/mbedtls/xtea.h +++ b/app/include/mbedtls/xtea.h @@ -37,25 +37,31 @@ #define MBEDTLS_XTEA_DECRYPT 0 #define MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH -0x0028 /**< The data input has an invalid length. */ -#define MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED -0x0029 /**< XTEA hardware accelerator failed. */ -#if !defined(MBEDTLS_XTEA_ALT) -// Regular implementation -// +/* MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED -0x0029 /**< XTEA hardware accelerator failed. */ #ifdef __cplusplus extern "C" { #endif +#if !defined(MBEDTLS_XTEA_ALT) +// Regular implementation +// + /** * \brief XTEA context structure */ -typedef struct +typedef struct mbedtls_xtea_context { uint32_t k[4]; /*!< key */ } mbedtls_xtea_context; +#else /* MBEDTLS_XTEA_ALT */ +#include "xtea_alt.h" +#endif /* MBEDTLS_XTEA_ALT */ + /** * \brief Initialize XTEA context * @@ -115,17 +121,7 @@ int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, unsigned char *output); #endif /* MBEDTLS_CIPHER_MODE_CBC */ -#ifdef __cplusplus -} -#endif - -#else /* MBEDTLS_XTEA_ALT */ -#include "xtea_alt.h" -#endif /* MBEDTLS_XTEA_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif +#if defined(MBEDTLS_SELF_TEST) /** * \brief Checkup routine @@ -134,6 +130,8 @@ extern "C" { */ int mbedtls_xtea_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + #ifdef __cplusplus } #endif diff --git a/app/include/sys/Espconn_mem.h b/app/include/sys/Espconn_mem.h deleted file mode 100644 index aa6713f703..0000000000 --- a/app/include/sys/Espconn_mem.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * ESPRSSIF MIT License - * - * Copyright (c) 2016 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ESPCONN_MEM_H_ -#define ESPCONN_MEM_H_ - -void *espconn_memzalloc(size_t size); -void espconn_memfree(void *fp); -void *espconn_memcpy(void *dst, const void *src, size_t size); - -#endif - diff --git a/app/include/sys/espconn_mbedtls.h b/app/include/sys/espconn_mbedtls.h index 0d48af8d03..79e4c92fa3 100644 --- a/app/include/sys/espconn_mbedtls.h +++ b/app/include/sys/espconn_mbedtls.h @@ -38,16 +38,6 @@ #include "mbedtls/ctr_drbg.h" typedef struct espconn *pmbedtls_espconn; typedef struct espconn mbedtls_espconn; -typedef struct{ - int record_len; -}mbedtls_record; - -#if defined(ESP8266_PLATFORM) -typedef struct{ - uint8* finished_buf; - int finished_len; -}mbedtls_finished, *pmbedtls_finished; -#endif typedef struct{ // mbedtls_entropy_context entropy; @@ -58,10 +48,7 @@ typedef struct{ typedef struct{ bool quiet; - mbedtls_record record; -#if defined(ESP8266_PLATFORM) - pmbedtls_finished pfinished; -#endif + int record_len; pmbedtls_session psession; mbedtls_net_context fd; mbedtls_net_context listen_fd; diff --git a/app/include/sys/socket.h b/app/include/sys/socket.h index 5f2d0c1334..a57378dc3e 100644 --- a/app/include/sys/socket.h +++ b/app/include/sys/socket.h @@ -102,20 +102,10 @@ typedef enum{ }\ }while(0) -#define lwIP_EVENT_PARSE(s, error) \ - do { \ - mbedtls_parse_internal(s, error); \ - } while (0) - -#define lwIP_EVENT_THREAD(s, event, error) \ - do { \ - mbedtls_parse_thread(s, event, error); \ - }while(0) - typedef enum{ - ENTCONN_EVENT_NONE = 0, + NETCONN_EVENT_NONE = 0, NETCONN_EVENT_ESTABLISHED = 1, - ENTCONN_EVENT_RECV = 2, + NETCONN_EVENT_RECV = 2, NETCONN_EVENT_SEND = 3, NETCONN_EVENT_ERROR = 4, NETCONN_EVENT_CLOSE = 5, diff --git a/app/include/user_config.h b/app/include/user_config.h index 5734f3be29..0f988d6db2 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -94,7 +94,6 @@ // are by firmware code, and can be enabled if you need this functionality. //#define CLIENT_SSL_ENABLE -//#define MD2_ENABLE #define SHA2_ENABLE #define SSL_BUFFER_SIZE 4096 #define SSL_MAX_FRAGMENT_LENGTH_CODE MBEDTLS_SSL_MAX_FRAG_LEN_4096 diff --git a/app/include/user_mbedtls.h b/app/include/user_mbedtls.h index dcfe4c8e3f..ea9cfaf8bd 100644 --- a/app/include/user_mbedtls.h +++ b/app/include/user_mbedtls.h @@ -151,7 +151,7 @@ #undef MBEDTLS_SSL_PROTO_SSL3 #undef MBEDTLS_SSL_PROTO_TLS1 -#define MBEDTLS_SSL_PROTO_TLS1_1 +#undef MBEDTLS_SSL_PROTO_TLS1_1 #define MBEDTLS_SSL_PROTO_TLS1_2 #undef MBEDTLS_SSL_PROTO_DTLS @@ -214,7 +214,7 @@ #define MBEDTLS_MD_C #undef MBEDTLS_MD2_C #undef MBEDTLS_MD4_C -#define MBEDTLS_MD5_C /* Remove when we drop support for TLS 1.1 */ +#undef MBEDTLS_MD5_C #undef MBEDTLS_MEMORY_BUFFER_ALLOC_C #define MBEDTLS_NET_C #define MBEDTLS_OID_C diff --git a/app/mbedtls/app/Espconn_mem.c b/app/mbedtls/app/Espconn_mem.c deleted file mode 100644 index 5620b1b9eb..0000000000 --- a/app/mbedtls/app/Espconn_mem.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include "mem.h" -#include "user_interface.h" - -void *espconn_memzalloc(size_t size, char* file, int line) -{ - void *mp = NULL; - if ((mp = (void*)os_malloc(size)) == NULL){ - - } else{ - //os_printf("%s %d %p %d\n",file, line, mp, size); - os_memset(mp, 0, size); - } - return mp; -} - -void espconn_memfree(void *fp, char* file, int line) -{ - //os_printf("%s %d %p\n",file, line, fp); - os_free(fp); - fp = NULL; -} - -void *espconn_memcpy(void *dst, const void *src, size_t size, char *file, int line) -{ - char *psrc = NULL; - char *pdst = NULL; - - if(NULL == dst || NULL == src) - { - return NULL; - } - //os_printf("%s %d %p %p %d\n",file, line, dst, src, size); - if((src < dst) && (char *)src + size > (char *)dst) - { - psrc = (char *)src + size - 1; - pdst = (char *)dst + size - 1; - while(size--) - { - *pdst-- = *psrc--; - } - } - else - { - psrc = (char *)src; - pdst = (char *)dst; - while(size--) - { - *pdst++ = *psrc++; - } - } - - return dst; - -} - -void *espconn_memcalloc(size_t count, size_t size) -{ - void *cp = NULL; - cp = espconn_memzalloc(count * size, __FILE__, __LINE__); - return cp; -} - -void espconn_memFree(void *fp) -{ - espconn_memfree(fp, __FILE__, __LINE__); -} - -void *espconn_memCpy(void *dst, const void *src, size_t size) -{ - return espconn_memcpy(dst, src, size, __FILE__, __LINE__); -} - diff --git a/app/mbedtls/app/espconn_mbedtls.c b/app/mbedtls/app/espconn_mbedtls.c index f4047fb741..cced9a27dc 100644 --- a/app/mbedtls/app/espconn_mbedtls.c +++ b/app/mbedtls/app/espconn_mbedtls.c @@ -48,29 +48,21 @@ static espconn_msg *plink_server = NULL; static pmbedtls_parame def_certificate = NULL; static pmbedtls_parame def_private_key = NULL; -#if defined(ESP8266_PLATFORM) -#define MBEDTLS_SSL_OUTBUFFER_LEN ( MBEDTLS_SSL_PLAIN_ADD \ - + MBEDTLS_SSL_COMPRESSION_ADD \ - + 29 /* counter + header + IV */ \ - + MBEDTLS_SSL_MAC_ADD \ - + MBEDTLS_SSL_PADDING_ADD \ - ) -#endif - /* Implementation that should never be optimized out by the compiler */ static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; + volatile unsigned char *p = v; + while( n-- ) *p++ = 0; } static pmbedtls_parame mbedtls_parame_new(size_t capacity) { pmbedtls_parame rb = (pmbedtls_parame)os_zalloc(sizeof(mbedtls_parame)); - if (rb && capacity != 0){ + if (rb && capacity != 0) { rb->parame_datalen = capacity; rb->parame_data = (uint8*)os_zalloc(rb->parame_datalen + 1); - if (rb->parame_data){ + if (rb->parame_data) { - } else{ + } else { os_free(rb); rb = NULL; } @@ -94,44 +86,44 @@ bool mbedtls_load_default_obj(uint32 flash_sector, int obj_type, const unsigned uint32 mbedtls_head = 0; bool mbedtls_load_flag = false; - if (flash_sector != 0){ + if (flash_sector != 0) { spi_flash_read(flash_sector * FLASH_SECTOR_SIZE, (uint32*)&mbedtls_head, 4); - if (mbedtls_head != ESPCONN_INVALID_TYPE){ + if (mbedtls_head != ESPCONN_INVALID_TYPE) { mbedtls_write = mbedtls_parame_new(0); mbedtls_write->parame_datalen = length; } - } else{ + } else { const char* const begin = "-----BEGIN"; int format_type = ESPCONN_FORMAT_INIT; /* - * Determine data content. data contains either one DER certificate or - * one or more PEM certificates. - */ - if ((char*)os_strstr(load_buf, begin) != NULL){ + * Determine data content. data contains either one DER certificate or + * one or more PEM certificates. + */ + if ((char*)os_strstr(load_buf, begin) != NULL) { format_type = ESPCONN_FORMAT_PEM; - }else{ + } else { format_type = ESPCONN_FORMAT_DER; } - if (format_type == ESPCONN_FORMAT_PEM){ + if (format_type == ESPCONN_FORMAT_PEM) { length += 1; } mbedtls_write = mbedtls_parame_new(length); - if (mbedtls_write){ + if (mbedtls_write) { os_memcpy(mbedtls_write->parame_data, load_buf, length); if (format_type == ESPCONN_FORMAT_PEM) mbedtls_write->parame_data[length - 1] = '\0'; } } - if (mbedtls_write){ + if (mbedtls_write) { mbedtls_load_flag = true; mbedtls_write->parame_type = obj_type; mbedtls_write->parame_sec = flash_sector; - if (obj_type == ESPCONN_PK){ + if (obj_type == ESPCONN_PK) { def_private_key = mbedtls_write; - } else{ + } else { def_certificate = mbedtls_write; } } @@ -144,29 +136,29 @@ static unsigned char* mbedtls_get_default_obj(uint32 *sec, uint32 type, uint32 * unsigned char *parame_data = NULL; pmbedtls_parame mbedtls_obj = NULL; - if (type == ESPCONN_PK){ + if (type == ESPCONN_PK) { mbedtls_obj = def_private_key; - } else{ + } else { mbedtls_obj = def_certificate; } - if (mbedtls_obj->parame_sec != 0){ - #define DATA_OFFSET 4 + if (mbedtls_obj->parame_sec != 0) { +#define DATA_OFFSET 4 uint32 data_len = mbedtls_obj->parame_datalen; parame_data = (unsigned char *)os_zalloc(data_len + DATA_OFFSET); - if (parame_data){ + if (parame_data) { spi_flash_read(mbedtls_obj->parame_sec * FLASH_SECTOR_SIZE, (uint32*)parame_data, data_len); /* - * Determine buffer content. Buffer contains either one DER certificate or - * one or more PEM certificates. - */ - if ((char*)os_strstr(parame_data, begin) != NULL){ + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ + if ((char*)os_strstr(parame_data, begin) != NULL) { data_len ++; parame_data[data_len - 1] = '\0'; } } *len = data_len; - } else{ + } else { parame_data = mbedtls_obj->parame_data; *len = mbedtls_obj->parame_datalen; } @@ -201,43 +193,13 @@ static int mbedtls_keep_alive(int sock_id, int onoff, int idle, int intvl, int c return ret; } -#if defined(ESP8266_PLATFORM) -static pmbedtls_finished mbedtls_finished_new(int len) -{ - pmbedtls_finished finished = (pmbedtls_finished)os_zalloc(sizeof(mbedtls_finished)); - if (finished) - { - finished->finished_len = len; - finished->finished_buf = (uint8*)os_zalloc(finished->finished_len + 1); - if (finished->finished_buf) - { - - } - else - { - os_free(finished); - finished = NULL; - } - } - return finished; -} - -static void mbedtls_finished_free(pmbedtls_finished *pfinished) -{ - lwIP_ASSERT(pfinished); - lwIP_ASSERT(*pfinished); - os_free((*pfinished)->finished_buf); - os_free(*pfinished); - *pfinished = NULL; -} -#endif static pmbedtls_espconn mbedtls_espconn_new(void) { pmbedtls_espconn mbedtls_conn = NULL; mbedtls_conn = (pmbedtls_espconn)os_zalloc(sizeof(mbedtls_espconn)); - if (mbedtls_conn){ + if (mbedtls_conn) { mbedtls_conn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); - if (mbedtls_conn->proto.tcp == NULL){ + if (mbedtls_conn->proto.tcp == NULL) { os_free(mbedtls_conn); mbedtls_conn = NULL; } @@ -261,7 +223,7 @@ static void mbedtls_espconn_free(pmbedtls_espconn *mbedtlsconn) static pmbedtls_session mbedtls_session_new(void) { pmbedtls_session session = (pmbedtls_session)os_zalloc(sizeof(mbedtls_session)); - if (session){ + if (session) { mbedtls_x509_crt_init(&session->cacert); mbedtls_x509_crt_init(&session->clicert); mbedtls_pk_init(&session->pkey); @@ -289,7 +251,7 @@ static pmbedtls_msg mbedtls_msg_new(void) if (msg) { os_bzero(msg, sizeof(mbedtls_msg)); msg->psession = mbedtls_session_new(); - if (msg->psession){ + if (msg->psession) { mbedtls_net_init(&msg->listen_fd); mbedtls_net_init(&msg->fd); mbedtls_ssl_init(&msg->ssl); @@ -299,7 +261,7 @@ static pmbedtls_msg mbedtls_msg_new(void) #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && defined(SSL_MAX_FRAGMENT_LENGTH_CODE) mbedtls_ssl_conf_max_frag_len(&msg->conf, SSL_MAX_FRAGMENT_LENGTH_CODE); #endif - } else{ + } else { os_free(msg); msg = NULL; } @@ -312,17 +274,9 @@ static void mbedtls_msg_server_step(pmbedtls_msg msg) lwIP_ASSERT(msg); /*to prevent memory leaks, ensure that each allocated is deleted at every handshake*/ - if (msg->psession){ + if (msg->psession) { mbedtls_session_free(&msg->psession); } -#if defined(ESP8266_PLATFORM) - if (msg->quiet && msg->ssl.out_buf) - { - mbedtls_zeroize(msg->ssl.out_buf, MBEDTLS_SSL_OUTBUFFER_LEN); - os_free(msg->ssl.out_buf); - msg->ssl.out_buf = NULL; - } -#endif mbedtls_entropy_free(&msg->entropy); mbedtls_ssl_free(&msg->ssl); mbedtls_ssl_config_free(&msg->conf); @@ -331,7 +285,7 @@ static void mbedtls_msg_server_step(pmbedtls_msg msg) /*New connection ensure that each initial for next handshake */ os_bzero(msg, sizeof(mbedtls_msg)); msg->psession = mbedtls_session_new(); - if (msg->psession){ + if (msg->psession) { mbedtls_net_init(&msg->fd); mbedtls_ssl_init(&msg->ssl); mbedtls_ssl_config_init(&msg->conf); @@ -346,19 +300,9 @@ static void mbedtls_msg_free(pmbedtls_msg *msg) lwIP_ASSERT(*msg); /*to prevent memory leaks, ensure that each allocated is deleted at every handshake*/ - if ((*msg)->psession){ + if ((*msg)->psession) { mbedtls_session_free(&((*msg)->psession)); } -#if defined(ESP8266_PLATFORM) - if ((*msg)->quiet && (*msg)->ssl.out_buf) - { - mbedtls_zeroize((*msg)->ssl.out_buf, MBEDTLS_SSL_OUTBUFFER_LEN); - os_free((*msg)->ssl.out_buf); - (*msg)->ssl.out_buf = NULL; - } - if((*msg)->pfinished != NULL) - mbedtls_finished_free(&(*msg)->pfinished); -#endif mbedtls_entropy_free(&(*msg)->entropy); mbedtls_ssl_free(&(*msg)->ssl); mbedtls_ssl_config_free(&(*msg)->conf); @@ -374,15 +318,15 @@ static espconn_msg* mbedtls_msg_find(int sock) pmbedtls_msg msg = NULL; for (plist = plink_active; plist != NULL; plist = plist->pnext) { - if(plist->pssl != NULL){ + if(plist->pssl != NULL) { msg = plist->pssl; if (msg->fd.fd == sock) return plist; } } - for (plist = plink_server; plist != NULL; plist = plist->pnext){ - if(plist->pssl != NULL){ + for (plist = plink_server; plist != NULL; plist = plist->pnext) { + if(plist->pssl != NULL) { msg = plist->pssl; if (msg->listen_fd.fd == sock) return plist; @@ -408,7 +352,7 @@ static bool mbedtls_handshake_result(const pmbedtls_msg Threadmsg) else ret = ssl_option.server.cert_ca_sector.flag; - if (ret == 1){ + if (ret == 1) { ret = mbedtls_ssl_get_verify_result(&Threadmsg->ssl); if (ret != 0) { char vrfy_buf[512]; @@ -421,7 +365,7 @@ static bool mbedtls_handshake_result(const pmbedtls_msg Threadmsg) return true; } else return true; - }else + } else return false; } @@ -436,14 +380,14 @@ static void mbedtls_fail_info(espconn_msg *pinfo, int ret) * up. That's entirely normal and not worthy of the confusion it sows! */ if (ret != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - if (TLSmsg->quiet){ + if (TLSmsg->quiet) { if (pinfo->preverse != NULL) { os_printf("server's data invalid protocol\n"); } else { os_printf("client's data invalid protocol\n"); } mbedtls_ssl_close_notify(&TLSmsg->ssl); - } else{ + } else { if (pinfo->preverse != NULL) { os_printf("server handshake failed!\n"); } else { @@ -455,9 +399,9 @@ static void mbedtls_fail_info(espconn_msg *pinfo, int ret) os_printf("Reason:[-0x%2x]\n",-ret); /*Error code convert*/ ret = -ret; - if ((ret & 0xFF) != 0){ + if ((ret & 0xFF) != 0) { ret = ((ret >> 8) + ret); - } else{ + } else { ret >>= 8; } pinfo->hs_status = -ret; @@ -469,82 +413,37 @@ static void mbedtls_fail_info(espconn_msg *pinfo, int ret) return; } -#if defined(ESP8266_PLATFORM) -int mbedtls_write_finished(mbedtls_ssl_context *ssl) -{ - lwIP_ASSERT(ssl); - lwIP_ASSERT(ssl->p_bio); - int ret = ERR_OK; - int fd = ((mbedtls_net_context *) ssl->p_bio)->fd; - espconn_msg *Threadmsg = mbedtls_msg_find(fd); - lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM); - pmbedtls_msg TLSmsg = Threadmsg->pssl; - lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM); - TLSmsg->pfinished = mbedtls_finished_new(ssl->out_msglen + 29); - lwIP_REQUIRE_ACTION(TLSmsg->pfinished, exit, ret = ERR_MEM); - os_memcpy(TLSmsg->pfinished->finished_buf, ssl->out_ctr, TLSmsg->pfinished->finished_len); -exit: - return ret; -} - -static int mbedtls_hanshake_finished(mbedtls_msg *msg) -{ - lwIP_ASSERT(msg); - int ret = ERR_OK; - const size_t len = MBEDTLS_SSL_OUTBUFFER_LEN; - - mbedtls_ssl_context *ssl = &msg->ssl; - lwIP_REQUIRE_ACTION(ssl, exit, ret = ERR_MEM); - - pmbedtls_finished finished = msg->pfinished; - lwIP_REQUIRE_ACTION(finished, exit, ret = ERR_MEM); - - ssl->out_buf = (unsigned char*)os_zalloc(len); - lwIP_REQUIRE_ACTION(ssl->out_buf, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED); - - ssl->out_ctr = ssl->out_buf; - ssl->out_hdr = ssl->out_buf + 8; - ssl->out_len = ssl->out_buf + 11; - ssl->out_iv = ssl->out_buf + 13; - ssl->out_msg = ssl->out_buf + 29; - os_memcpy(ssl->out_ctr, finished->finished_buf, finished->finished_len); - mbedtls_finished_free(&msg->pfinished); - -exit: - return ret; -} -#endif static void mbedtls_handshake_succ(mbedtls_ssl_context *ssl) { lwIP_ASSERT(ssl); if( ssl->handshake ) - { - mbedtls_ssl_handshake_free( ssl->handshake ); - mbedtls_ssl_transform_free( ssl->transform_negotiate ); - mbedtls_ssl_session_free( ssl->session_negotiate ); - - os_free( ssl->handshake ); - os_free( ssl->transform_negotiate ); - os_free( ssl->session_negotiate ); + { + mbedtls_ssl_handshake_free( ssl ); + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + mbedtls_ssl_session_free( ssl->session_negotiate ); + + os_free( ssl->handshake ); + os_free( ssl->transform_negotiate ); + os_free( ssl->session_negotiate ); ssl->handshake = NULL; ssl->transform_negotiate = NULL; ssl->session_negotiate = NULL; - } + } - if( ssl->session ) - { - mbedtls_ssl_session_free( ssl->session ); - os_free( ssl->session ); + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + os_free( ssl->session ); ssl->session = NULL; - } + } #if defined(MBEDTLS_X509_CRT_PARSE_C) - if( ssl->hostname != NULL ) - { - mbedtls_zeroize( ssl->hostname, os_strlen( ssl->hostname ) ); - os_free( ssl->hostname ); + if( ssl->hostname != NULL ) + { + mbedtls_zeroize( ssl->hostname, os_strlen( ssl->hostname ) ); + os_free( ssl->hostname ); ssl->hostname = NULL; - } + } #endif } @@ -557,10 +456,10 @@ static void mbedtls_handshake_succ(mbedtls_ssl_context *ssl) static void espconn_close_internal(void *arg, netconn_event event_type) { espconn_msg *pssl_recon = arg; - struct espconn *espconn = NULL; - sint8 ssl_reerr = 0; - sint16 hs_status = 0; - lwIP_ASSERT(pssl_recon); + struct espconn *espconn = NULL; + sint8 ssl_reerr = 0; + sint16 hs_status = 0; + lwIP_ASSERT(pssl_recon); espconn = pssl_recon->preverse; ssl_reerr = pssl_recon->pcommon.err; @@ -579,21 +478,21 @@ static void espconn_close_internal(void *arg, netconn_event event_type) } espconn_kill_oldest_pcb(); - switch (event_type){ - case NETCONN_EVENT_ERROR: - if (hs_status == ESPCONN_OK) - ESPCONN_EVENT_ERROR(espconn, ssl_reerr); - else - ESPCONN_EVENT_ERROR(espconn, hs_status); - break; - case NETCONN_EVENT_CLOSE: - if (hs_status == ESPCONN_OK) - ESPCONN_EVENT_CLOSED(espconn); - else - ESPCONN_EVENT_ERROR(espconn, hs_status); - break; - default: - break; + switch (event_type) { + case NETCONN_EVENT_ERROR: + if (hs_status == ESPCONN_OK) + ESPCONN_EVENT_ERROR(espconn, ssl_reerr); + else + ESPCONN_EVENT_ERROR(espconn, hs_status); + break; + case NETCONN_EVENT_CLOSE: + if (hs_status == ESPCONN_OK) + ESPCONN_EVENT_CLOSED(espconn); + else + ESPCONN_EVENT_ERROR(espconn, hs_status); + break; + default: + break; } } @@ -611,35 +510,35 @@ static bool espconn_ssl_read_param_from_flash(void *param, uint16 len, int32 off uint32 FILE_PARAM_START_SEC = 0x3B; switch (auth_info->auth_level) { - case ESPCONN_CLIENT: - switch (auth_info->auth_type) { - case ESPCONN_CERT_AUTH: - FILE_PARAM_START_SEC = ssl_option.client.cert_ca_sector.sector; - break; - case ESPCONN_CERT_OWN: - case ESPCONN_PK: - FILE_PARAM_START_SEC = ssl_option.client.cert_req_sector.sector; - break; - default: - return false; - } + case ESPCONN_CLIENT: + switch (auth_info->auth_type) { + case ESPCONN_CERT_AUTH: + FILE_PARAM_START_SEC = ssl_option.client.cert_ca_sector.sector; break; - case ESPCONN_SERVER: - switch (auth_info->auth_type) { - case ESPCONN_CERT_AUTH: - FILE_PARAM_START_SEC = ssl_option.server.cert_ca_sector.sector; - break; - case ESPCONN_CERT_OWN: - case ESPCONN_PK: - FILE_PARAM_START_SEC = ssl_option.server.cert_req_sector.sector; - break; - default: - return false; - } + case ESPCONN_CERT_OWN: + case ESPCONN_PK: + FILE_PARAM_START_SEC = ssl_option.client.cert_req_sector.sector; break; default: return false; + } + break; + case ESPCONN_SERVER: + switch (auth_info->auth_type) { + case ESPCONN_CERT_AUTH: + FILE_PARAM_START_SEC = ssl_option.server.cert_ca_sector.sector; + break; + case ESPCONN_CERT_OWN: + case ESPCONN_PK: + FILE_PARAM_START_SEC = ssl_option.server.cert_req_sector.sector; break; + default: + return false; + } + break; + default: + return false; + break; } spi_flash_read(FILE_PARAM_START_SEC * 4096 + offset, param, len); @@ -651,53 +550,50 @@ static bool mbedtls_msg_info_load(mbedtls_msg *msg, mbedtls_auth_info *auth_info { const char* const begin = "-----BEGIN"; const char* const type_name = "private_key"; - #define FILE_OFFSET 4 +#define FILE_OFFSET 4 int ret = 0; int32 offerset = 0; uint8* load_buf = NULL; size_t load_len = 0; - file_param *pfile_param = NULL; - pfile_param = (file_param *)os_zalloc( sizeof(file_param)); - if (pfile_param==NULL) - return false; + file_param file_param; + + bzero(&file_param, sizeof(file_param)); again: - espconn_ssl_read_param_from_flash(&pfile_param->file_head, sizeof(file_head), offerset, auth_info); - pfile_param->file_offerset = offerset; - os_printf("%s %d, type[%s],length[%d]\n", __FILE__, __LINE__, pfile_param->file_head.file_name, pfile_param->file_head.file_length); - if (pfile_param->file_head.file_length == 0xFFFF){ - os_free(pfile_param); + espconn_ssl_read_param_from_flash(&file_param.file_head, sizeof(file_head), offerset, auth_info); + file_param.file_offerset = offerset; + os_printf("%s %d, type[%s],length[%d]\n", __FILE__, __LINE__, file_param.file_head.file_name, file_param.file_head.file_length); + if (file_param.file_head.file_length == 0xFFFF) { return false; - } else{ + } else { /*Optional is load the private key*/ - if (auth_info->auth_type == ESPCONN_PK && os_memcmp(pfile_param->file_head.file_name, type_name, os_strlen(type_name)) != 0){ - offerset += sizeof(file_head) + pfile_param->file_head.file_length; + if (auth_info->auth_type == ESPCONN_PK && os_memcmp(&file_param.file_head.file_name, type_name, os_strlen(type_name)) != 0) { + offerset += sizeof(file_head) + file_param.file_head.file_length; goto again; } /*Optional is load the cert*/ - if (auth_info->auth_type == ESPCONN_CERT_OWN && os_memcmp(pfile_param->file_head.file_name, "certificate", os_strlen("certificate")) != 0){ - offerset += sizeof(file_head) + pfile_param->file_head.file_length; + if (auth_info->auth_type == ESPCONN_CERT_OWN && os_memcmp(file_param.file_head.file_name, "certificate", os_strlen("certificate")) != 0) { + offerset += sizeof(file_head) + file_param.file_head.file_length; goto again; } - load_buf = (uint8_t *) os_zalloc( pfile_param->file_head.file_length + FILE_OFFSET); - if (load_buf == NULL){ - os_free(pfile_param); + load_buf = (uint8_t *) os_zalloc( file_param.file_head.file_length + FILE_OFFSET); + if (load_buf == NULL) { return false; } - offerset = sizeof(file_head) + pfile_param->file_offerset; - espconn_ssl_read_param_from_flash(load_buf, pfile_param->file_head.file_length, offerset, auth_info); + offerset = sizeof(file_head) + file_param.file_offerset; + espconn_ssl_read_param_from_flash(load_buf, file_param.file_head.file_length, offerset, auth_info); } - load_len = pfile_param->file_head.file_length; - /* - * Determine buffer content. Buffer contains either one DER certificate or - * one or more PEM certificates. - */ - if ((char*)os_strstr(load_buf, begin) != NULL){ + load_len = file_param.file_head.file_length; + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ + if ((char*)os_strstr(load_buf, begin) != NULL) { load_len += 1; load_buf[load_len - 1] = '\0'; } - switch (auth_info->auth_type){ + switch (auth_info->auth_type) { case ESPCONN_CERT_AUTH: /*Optional is not optimal for security*/ ret = mbedtls_x509_crt_parse(&msg->psession->cacert, (const uint8*) load_buf,load_len); @@ -716,10 +612,9 @@ static bool mbedtls_msg_info_load(mbedtls_msg *msg, mbedtls_auth_info *auth_info } exit: os_free(load_buf); - os_free(pfile_param); - if (ret < 0){ + if (ret < 0) { return false; - }else{ + } else { return true; } } @@ -739,7 +634,7 @@ static bool mbedtls_msg_config(mbedtls_msg *msg) mbedtls_auth_info auth_info; /*end_point mode*/ - if (msg->listen_fd.fd == -1){ + if (msg->listen_fd.fd == -1) { pers = "client"; auth_type = MBEDTLS_SSL_IS_CLIENT; } else { @@ -751,10 +646,11 @@ static bool mbedtls_msg_config(mbedtls_msg *msg) ret = mbedtls_ctr_drbg_seed(&msg->ctr_drbg, mbedtls_entropy_func, &msg->entropy, (const unsigned char*) pers, os_strlen(pers)); lwIP_REQUIRE_NOERROR(ret, exit); - if (auth_type == MBEDTLS_SSL_IS_SERVER){ + if (auth_type == MBEDTLS_SSL_IS_SERVER) { uint32 flash_sector = 0; /*Load the certificate*/ - unsigned int def_certificate_len = 0;unsigned char *def_certificate = NULL; + unsigned int def_certificate_len = 0; + unsigned char *def_certificate = NULL; def_certificate = (unsigned char *)mbedtls_get_default_obj(&flash_sector,ESPCONN_CERT_OWN, &def_certificate_len); lwIP_REQUIRE_ACTION(def_certificate, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED); ret = mbedtls_x509_crt_parse(&msg->psession->clicert, (const unsigned char *)def_certificate, def_certificate_len); @@ -763,7 +659,8 @@ static bool mbedtls_msg_config(mbedtls_msg *msg) lwIP_REQUIRE_NOERROR(ret, exit); /*Load the private RSA key*/ - unsigned int def_private_key_len = 0;unsigned char *def_private_key = NULL; + unsigned int def_private_key_len = 0; + unsigned char *def_private_key = NULL; def_private_key = (unsigned char *)mbedtls_get_default_obj(&flash_sector,ESPCONN_PK, &def_private_key_len); lwIP_REQUIRE_ACTION(def_private_key, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED); ret = mbedtls_pk_parse_key(&msg->psession->pkey, (const unsigned char *)def_private_key, def_private_key_len, NULL, 0); @@ -780,7 +677,7 @@ static bool mbedtls_msg_config(mbedtls_msg *msg) load_flag = mbedtls_msg_info_load(msg, &auth_info); lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM); } - } else{ + } else { /*Load the certificate and private RSA key*/ if (ssl_option.client.cert_req_sector.flag) { auth_info.auth_level = ESPCONN_CLIENT; @@ -793,7 +690,7 @@ static bool mbedtls_msg_config(mbedtls_msg *msg) } /*Load the trusted CA*/ - if(ssl_option.client.cert_ca_sector.flag){ + if(ssl_option.client.cert_ca_sector.flag) { auth_info.auth_level = ESPCONN_CLIENT; auth_info.auth_type = ESPCONN_CERT_AUTH; load_flag = mbedtls_msg_info_load(msg, &auth_info); @@ -806,7 +703,7 @@ static bool mbedtls_msg_config(mbedtls_msg *msg) lwIP_REQUIRE_NOERROR(ret, exit); /*OPTIONAL is not optimal for security, but makes interop easier in this session*/ - if (auth_type == MBEDTLS_SSL_IS_CLIENT && ssl_option.client.cert_ca_sector.flag == false){ + if (auth_type == MBEDTLS_SSL_IS_CLIENT && ssl_option.client.cert_ca_sector.flag == false) { mbedtls_ssl_conf_authmode(&msg->conf, MBEDTLS_SSL_VERIFY_NONE); } mbedtls_ssl_conf_rng(&msg->conf, mbedtls_ctr_drbg_random, &msg->ctr_drbg); @@ -818,14 +715,14 @@ static bool mbedtls_msg_config(mbedtls_msg *msg) mbedtls_ssl_set_bio(&msg->ssl, &msg->fd, mbedtls_net_send, mbedtls_net_recv, NULL); exit: - if (ret != 0){ + if (ret != 0) { return false; - } else{ + } else { return true; } } -int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) +int espconn_mbedtls_parse_internal(int socket, sint8 error) { int ret = ERR_OK; bool config_flag = false; @@ -836,8 +733,8 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) TLSmsg = Threadmsg->pssl; lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM); - if (error == ERR_OK){ - if (TLSmsg->quiet){ + if (error == ERR_OK) { + if (TLSmsg->quiet) { uint8 *TheadBuff = NULL; size_t ThreadLen = MBEDTLS_SSL_PLAIN_ADD; TheadBuff = (uint8 *)os_zalloc(ThreadLen + 1); @@ -845,16 +742,16 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) do { os_memset(TheadBuff, 0, ThreadLen); ret = mbedtls_ssl_read(&TLSmsg->ssl, TheadBuff, ThreadLen); - if (ret > 0){ + if (ret > 0) { ESPCONN_EVENT_RECV(Threadmsg->pespconn, TheadBuff, ret); - } else{ - if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == 0){ + } else { + if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == 0) { ret = ESPCONN_OK; break; - } else if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY){ + } else if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { ret = ESPCONN_OK; mbedtls_ssl_close_notify(&TLSmsg->ssl); - } else{ + } else { break; } } @@ -862,15 +759,15 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) os_free(TheadBuff); TheadBuff = NULL; lwIP_REQUIRE_NOERROR(ret, exit); - } else{ - if (TLSmsg->ssl.state == MBEDTLS_SSL_HELLO_REQUEST){ - if (Threadmsg->preverse != NULL){ + } else { + if (TLSmsg->ssl.state == MBEDTLS_SSL_HELLO_REQUEST) { + if (Threadmsg->preverse != NULL) { struct espconn *accept_conn = NULL; struct espconn *espconn = Threadmsg->preverse; struct sockaddr_in name; socklen_t name_len = sizeof(name); remot_info *pinfo = NULL; - espconn_get_connection_info(espconn, &pinfo , ESPCONN_SSL); + espconn_get_connection_info(espconn, &pinfo, ESPCONN_SSL); if (espconn->link_cnt == 0x01) return ERR_ISCONN; @@ -892,14 +789,14 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) /*insert the node to the active connection list*/ espconn_list_creat(&plink_active, Threadmsg); os_printf("server handshake start.\n"); - } else{ + } else { os_printf("client handshake start.\n"); } config_flag = mbedtls_msg_config(TLSmsg); - if (config_flag){ + if (config_flag) { // mbedtls_keep_alive(TLSmsg->fd.fd, 1, SSL_KEEP_IDLE, SSL_KEEP_INTVL, SSL_KEEP_CNT); system_overclock(); - } else{ + } else { ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; lwIP_REQUIRE_NOERROR(ret, exit); } @@ -914,7 +811,7 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { ret = ESPCONN_OK; break; - } else{ + } else { break; } } @@ -923,7 +820,7 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) lwIP_REQUIRE_NOERROR(ret, exit); /**/ TLSmsg->quiet = mbedtls_handshake_result(TLSmsg); - if (TLSmsg->quiet){ + if (TLSmsg->quiet) { if (Threadmsg->preverse != NULL) { os_printf("server handshake ok!\n"); } else { @@ -932,18 +829,15 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) // mbedtls_keep_alive(TLSmsg->fd.fd, 0, SSL_KEEP_IDLE, SSL_KEEP_INTVL, SSL_KEEP_CNT); mbedtls_session_free(&TLSmsg->psession); mbedtls_handshake_succ(&TLSmsg->ssl); -#if defined(ESP8266_PLATFORM) - mbedtls_hanshake_finished(TLSmsg); -#endif system_restoreclock(); TLSmsg->SentFnFlag = true; ESPCONN_EVENT_CONNECTED(Threadmsg->pespconn); - } else{ + } else { lwIP_REQUIRE_NOERROR_ACTION(TLSmsg->verify_result, exit, ret = TLSmsg->verify_result); } } - } else if (error < 0){ + } else if (error < 0) { Threadmsg->pcommon.err = error; Threadmsg->pespconn->state = ESPCONN_CLOSE; mbedtls_net_free(&TLSmsg->fd); @@ -954,9 +848,9 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) } exit: - if (ret != ESPCONN_OK){ + if (ret != ESPCONN_OK) { mbedtls_fail_info(Threadmsg, ret); - if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY){ + if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { Threadmsg->hs_status = ESPCONN_OK; } ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE,(uint32)Threadmsg); @@ -964,7 +858,7 @@ int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) return ret; } -int __attribute__((weak)) mbedtls_parse_thread(int socket, int event, int error) +int espconn_mbedtls_parse_thread(int socket, int event, int error) { int ret = ERR_OK; espconn_msg *Threadmsg = NULL; @@ -973,25 +867,21 @@ int __attribute__((weak)) mbedtls_parse_thread(int socket, int event, int error) lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM); TLSmsg = Threadmsg->pssl; lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM); - if (TLSmsg->quiet){ + if (TLSmsg->quiet) { int out_msglen = TLSmsg->ssl.out_msglen + 5; if (Threadmsg->pcommon.write_flag) - TLSmsg->record.record_len += error; + TLSmsg->record_len += error; - if (TLSmsg->record.record_len == out_msglen){ - TLSmsg->record.record_len = 0; + if (TLSmsg->record_len == out_msglen) { + TLSmsg->record_len = 0; Threadmsg->pcommon.write_flag = false; - if (Threadmsg->pcommon.cntr != 0){ + if (Threadmsg->pcommon.cntr != 0) { espconn_ssl_sent(Threadmsg, Threadmsg->pcommon.ptrbuf, Threadmsg->pcommon.cntr); - } else{ + } else { TLSmsg->SentFnFlag = true; ESPCONN_EVENT_SEND(Threadmsg->pespconn); } - } else{ - } - } else{ - } exit: return ret; @@ -1017,34 +907,34 @@ mbedtls_thread(os_event_t *events) lwIP_REQUIRE_ACTION(Threadmsg->pespconn,exit,ret = ERR_ARG); /*find the active connection*/ - for (ListMsg = plink_active; ListMsg != NULL; ListMsg = ListMsg->pnext){ - if (Threadmsg == ListMsg){ + for (ListMsg = plink_active; ListMsg != NULL; ListMsg = ListMsg->pnext) { + if (Threadmsg == ListMsg) { active_flag = true; break; } } - if (active_flag){ + if (active_flag) { /*remove the node from the active connection list*/ espconn_list_delete(&plink_active, Threadmsg); - if (TLSmsg->listen_fd.fd != -1){ + if (TLSmsg->listen_fd.fd != -1) { mbedtls_msg_server_step(TLSmsg); espconn_copy_partial(Threadmsg->preverse, Threadmsg->pespconn); mbedtls_espconn_free(&Threadmsg->pespconn); - } else{ + } else { mbedtls_msg_free(&TLSmsg); Threadmsg->pssl = NULL; } - switch (events->sig){ - case NETCONN_EVENT_ERROR: - espconn_close_internal(Threadmsg, NETCONN_EVENT_ERROR); - break; - case NETCONN_EVENT_CLOSE: - espconn_close_internal(Threadmsg, NETCONN_EVENT_CLOSE); - break; - default: - break; + switch (events->sig) { + case NETCONN_EVENT_ERROR: + espconn_close_internal(Threadmsg, NETCONN_EVENT_ERROR); + break; + case NETCONN_EVENT_CLOSE: + espconn_close_internal(Threadmsg, NETCONN_EVENT_CLOSE); + break; + default: + break; } } exit: @@ -1074,7 +964,7 @@ sint8 espconn_ssl_client(struct espconn *espconn) mbedTLSMsg = mbedtls_msg_new(); lwIP_REQUIRE_ACTION(mbedTLSMsg, exit, ret = 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]); + espconn->proto.tcp->remote_ip[2],espconn->proto.tcp->remote_ip[3]); server_name = ipaddr_ntoa(&ipaddr); server_port = (const char *)sys_itoa(espconn->proto.tcp->remote_port); @@ -1088,7 +978,7 @@ sint8 espconn_ssl_client(struct espconn *espconn) /*insert the node to the active connection list*/ espconn_list_creat(&plink_active, pclient); exit: - if (ret != ESPCONN_OK){ + if (ret != ESPCONN_OK) { if (mbedTLSMsg != NULL) mbedtls_msg_free(&mbedTLSMsg); if (pclient != NULL) @@ -1204,19 +1094,19 @@ void espconn_ssl_sent(void *arg, uint8 *psent, uint16 length) pmbedtls_msg mbedTLSMsg = Threadmsg->pssl; lwIP_ASSERT(mbedTLSMsg); - if (length > MBEDTLS_SSL_PLAIN_ADD){ + if (length > MBEDTLS_SSL_PLAIN_ADD) { out_msglen = MBEDTLS_SSL_PLAIN_ADD; } Threadmsg->pcommon.write_flag = true; ret = mbedtls_ssl_write(&mbedTLSMsg->ssl, psent, out_msglen); - if (ret > 0){ + if (ret > 0) { Threadmsg->pcommon.ptrbuf = psent + ret; Threadmsg->pcommon.cntr = length - ret; - } else{ + } else { if (ret == MBEDTLS_ERR_SSL_WANT_WRITE || ret == 0) { - } else{ + } else { mbedtls_fail_info(Threadmsg, ret); ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE,(uint32)Threadmsg); } @@ -1246,60 +1136,60 @@ void espconn_ssl_disconnect(espconn_msg *Threadmsg) int mbedtls_x509_test(int verbose, char *ca_crt, size_t ca_crt_len, char *cli_crt, size_t cli_crt_len) { #if defined(MBEDTLS_SHA1_C) - int ret; - uint32_t flags; - mbedtls_x509_crt cacert; - mbedtls_x509_crt clicert; + int ret; + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; - if( verbose != 0 ) - os_printf( " X.509 certificate load: " ); + if( verbose != 0 ) + os_printf( " X.509 certificate load: " ); - mbedtls_x509_crt_init( &clicert ); + mbedtls_x509_crt_init( &clicert ); - ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) cli_crt, - cli_crt_len ); - if( ret != 0 ) - { - if( verbose != 0 ) - os_printf( "failed\n" ); + ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) cli_crt, + cli_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + os_printf( "failed\n" ); - return( ret ); - } + return( ret ); + } - mbedtls_x509_crt_init( &cacert ); + mbedtls_x509_crt_init( &cacert ); - ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) ca_crt, - ca_crt_len ); - if( ret != 0 ) - { - if( verbose != 0 ) - os_printf( "failed\n" ); + ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) ca_crt, + ca_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + os_printf( "failed\n" ); - return( ret ); - } + return( ret ); + } - if( verbose != 0 ) - os_printf( "passed\n X.509 signature verify: "); + if( verbose != 0 ) + os_printf( "passed\n X.509 signature verify: "); - ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); - if( ret != 0 ) - { - if( verbose != 0 ) - os_printf( "failed\n" ); + ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); + if( ret != 0 ) + { + if( verbose != 0 ) + os_printf( "failed\n" ); - return( ret ); - } + return( ret ); + } - if( verbose != 0 ) - os_printf( "passed\n\n"); + if( verbose != 0 ) + os_printf( "passed\n\n"); - mbedtls_x509_crt_free( &cacert ); - mbedtls_x509_crt_free( &clicert ); + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); - return( 0 ); + return( 0 ); #else - ((void) verbose); - return( 0 ); + ((void) verbose); + return( 0 ); #endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ } diff --git a/app/mbedtls/app/lwIPSocket.c b/app/mbedtls/app/lwIPSocket.c index 4b3bcdb937..f1014cf2d9 100644 --- a/app/mbedtls/app/lwIPSocket.c +++ b/app/mbedtls/app/lwIPSocket.c @@ -45,48 +45,6 @@ static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; /** The global array of available sockets */ static lwIP_sock sockets[NUM_SOCKETS]; -/** Table to quickly map an lwIP error (err_t) to a socket error - * by using -err as an index */ -static const int err_to_errno_table[] = -{ - 0, /* ERR_OK 0 No error, everything OK. */ -// ENOMEM, /* ERR_MEM -1 Out of memory error. */ -// ENOBUFS, /* ERR_BUF -2 Buffer error. */ -// EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ -// EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ -// EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ -// EINVAL, /* ERR_VAL -6 Illegal value. */ -// EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ -// ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ -// ECONNRESET, /* ERR_RST -9 Connection reset. */ -// ESHUTDOWN, /* ERR_CLSD -10 Connection closed. */ -// ENOTCONN, /* ERR_CONN -11 Not connected. */ -// EIO, /* ERR_ARG -12 Illegal argument. */ -// EADDRINUSE, /* ERR_USE -13 Address in use. */ - -1, /* ERR_IF -14 Low-level netif error */ - -1, /* ERR_ISCONN -15 Already connected. */ -}; - -#define ERR_TO_ERRNO_TABLE_SIZE \ - (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) - -#define err_to_errno(err) \ - ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ - err_to_errno_table[-(err)] : EIO) - -#ifdef ERRNO -#ifndef set_errno -#define set_errno(err) errno = (err) -#endif -#else /* ERRNO */ -#define set_errno(err) -#endif /* ERRNO */ - -#define sock_set_errno(sk, e) do { \ - sk->err = (e); \ - set_errno(sk->err); \ -} while (0) - static lwIP_sock *get_socket(int s); static int find_socket(lwIP_netconn *newconn) @@ -197,7 +155,7 @@ static err_t recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) ringbuf_memcpy_into(newconn->readbuf, pthis->payload, pthis->len); tcp_recved(newconn->tcp, pthis->len); newconn->state = NETCONN_STATE_ESTABLISHED; - lwIP_EVENT_PARSE(find_socket(newconn), ERR_OK); + espconn_mbedtls_parse_internal(find_socket(newconn), ERR_OK); } pbuf_free(p); } @@ -210,7 +168,7 @@ static err_t recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) } else { - lwIP_EVENT_PARSE(find_socket(newconn), NETCONN_EVENT_CLOSE); + espconn_mbedtls_parse_internal(find_socket(newconn), NETCONN_EVENT_CLOSE); } exit: return err; @@ -229,7 +187,7 @@ static err_t sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) lwIP_netconn *conn = arg; lwIP_ASSERT(conn); conn->state = NETCONN_STATE_ESTABLISHED; - lwIP_EVENT_THREAD(find_socket(conn), NETCONN_EVENT_SEND, len); + espconn_mbedtls_parse_thread(find_socket(conn), NETCONN_EVENT_SEND, len); return ERR_OK; } @@ -257,7 +215,7 @@ static void err_tcp(void *arg, err_t err) break; } - lwIP_EVENT_PARSE(find_socket(conn), err); + espconn_mbedtls_parse_internal(find_socket(conn), err); return; } @@ -275,7 +233,7 @@ static err_t do_connected(void *arg, struct tcp_pcb *pcb, err_t err) conn->state = NETCONN_STATE_ESTABLISHED; conn->readbuf = ringbuf_new(TCP_SND_BUF); lwIP_REQUIRE_ACTION(conn->readbuf, exit, err = ESP_MEM); - lwIP_EVENT_PARSE(find_socket(conn), ERR_OK); + espconn_mbedtls_parse_internal(find_socket(conn), ERR_OK); exit: return err; } @@ -325,7 +283,7 @@ static err_t do_accepted(void *arg, struct tcp_pcb *newpcb, err_t err) setup_tcp(newconn); newconn->state = NETCONN_STATE_ESTABLISHED; conn->acceptmbox = newconn; - lwIP_EVENT_PARSE(find_socket(conn), ERR_OK); + espconn_mbedtls_parse_internal(find_socket(conn), ERR_OK); exit: return err; } @@ -844,189 +802,3 @@ int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) { return lwip_getaddrname(s, name, namelen, 0); } - -int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) -{ - return lwip_getaddrname(s, name, namelen, 1); -} - -int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) -{ - lwIP_sock *sock = NULL; - err_t err = ERR_OK; - - lwIP_REQUIRE_ACTION(optval, exit, err = ESP_ARG); - lwIP_REQUIRE_ACTION(optlen, exit, err = ESP_ARG); - - sock = get_socket(s); - lwIP_REQUIRE_ACTION(sock, exit, err = ESP_MEM); - switch (level) - { - /* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) - { - /* The option flags */ - case SO_ACCEPTCONN: - case SO_BROADCAST: - case SO_KEEPALIVE: -#if SO_REUSE - case SO_REUSEADDR: - case SO_REUSEPORT: -#endif /* SO_REUSE */ - *(int*)optval = sock->conn->tcp->so_options & optname; - break; - case SO_TYPE: - switch (NETCONNTYPE_GROUP(sock->conn->type)) - { - case NETCONN_TCP: - *(int*)optval = SOCK_STREAM; - break; - case NETCONN_UDP: - *(int*)optval = SOCK_DGRAM; - break; - default: - *(int*)optval = sock->conn->type; - break; - } - break; - break; - } - break; - /* Level: IPPROTO_IP */ - case IPPROTO_IP: - break; -#if LWIP_TCP - /* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - if (*optlen < sizeof(int)) - { - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - } - - /* If this is no TCP socket, ignore any options. */ - if (sock->conn->type != NETCONN_TCP) - { - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - } - - switch (optname) - { - case TCP_NODELAY: - case TCP_KEEPALIVE: - *(int*)optval = (int)sock->conn->tcp->keep_idle; - break; -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - *(int*)optval = (int)(sock->conn->tcp->keep_idle/1000); - break; - case TCP_KEEPINTVL: - *(int*)optval = (int)(sock->conn->tcp->keep_intvl/1000); - break; - case TCP_KEEPCNT: - *(int*)optval = (int)sock->conn->tcp->keep_cnt; -#endif /* LWIP_TCP_KEEPALIVE */ - break; - - default: - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - break; - } /* switch (optname) */ - break; -#endif /* LWIP_TCP */ - default: - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - break; - } - -exit: - return err; -} - -int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) -{ - lwIP_sock *sock = NULL; - err_t err = ERR_OK; - lwIP_REQUIRE_ACTION(optval, exit, err = ESP_ARG); - - sock = get_socket(s); - lwIP_REQUIRE_ACTION(sock, exit, err = ESP_MEM); - lwIP_REQUIRE_ACTION(sock->conn, exit, err = ESP_MEM); - lwIP_REQUIRE_ACTION(sock->conn->tcp, exit, err = ESP_MEM); - switch (level) - { - /* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) - { - case SO_KEEPALIVE: - if (optlen < sizeof(int)) - { - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - } - if (*(int*)optval) - { - sock->conn->tcp->so_options |= optname; - } - else - { - sock->conn->tcp->so_options &= ~optname; - } - break; - } - break; - /* Level: IPPROTO_IP */ - case IPPROTO_IP: - break; - /* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - if (optlen < sizeof(int)) - { - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - } - - /* If this is no TCP socket, ignore any options. */ - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) - { - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - } - switch (optname) - { - case TCP_KEEPALIVE: - sock->conn->tcp->keep_idle = (u32_t) (*(int*) optval); - break; - -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - sock->conn->tcp->keep_idle = 1000 * (u32_t) (*(int*) optval); - break; - case TCP_KEEPINTVL: - sock->conn->tcp->keep_intvl = 1000 * (u32_t) (*(int*) optval); - break; - case TCP_KEEPCNT: - sock->conn->tcp->keep_cnt = (u32_t) (*(int*) optval); - break; -#endif /* LWIP_TCP_KEEPALIVE */ - default: - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - break; - } - break; - /* UNDEFINED LEVEL */ - default: - err = ESP_ARG; - lwIP_REQUIRE_NOERROR(err, exit); - break; - } - -exit: - return err; -} diff --git a/app/mbedtls/library/aes.c b/app/mbedtls/library/aes.c index 3d2eac82dd..aff0a9939a 100644 --- a/app/mbedtls/library/aes.c +++ b/app/mbedtls/library/aes.c @@ -36,6 +36,8 @@ #include #include "mbedtls/aes.h" +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" #if defined(MBEDTLS_PADLOCK_C) #include "mbedtls/padlock.h" #endif @@ -54,10 +56,11 @@ #if !defined(MBEDTLS_AES_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} +/* Parameter validation macros based on platform_util.h */ +#define AES_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_AES_BAD_INPUT_DATA ) +#define AES_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) /* * 32-bit integer manipulation macros (little endian) @@ -201,6 +204,8 @@ static const unsigned char FSb[256] = static const uint32_t FT0[256] = { FT }; #undef V +#if !defined(MBEDTLS_AES_FEWER_TABLES) + #define V(a,b,c,d) 0x##b##c##d##a static const uint32_t FT1[256] = { FT }; #undef V @@ -213,6 +218,8 @@ static const uint32_t FT2[256] = { FT }; static const uint32_t FT3[256] = { FT }; #undef V +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + #undef FT /* @@ -328,6 +335,8 @@ static const unsigned char RSb[256] = static const uint32_t RT0[256] = { RT }; #undef V +#if !defined(MBEDTLS_AES_FEWER_TABLES) + #define V(a,b,c,d) 0x##b##c##d##a static const uint32_t RT1[256] = { RT }; #undef V @@ -340,6 +349,8 @@ static const uint32_t RT2[256] = { RT }; static const uint32_t RT3[256] = { RT }; #undef V +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + #undef RT /* @@ -359,18 +370,22 @@ static const uint32_t RCON[10] = */ static unsigned char FSb[256]; static uint32_t FT0[256]; +#if !defined(MBEDTLS_AES_FEWER_TABLES) static uint32_t FT1[256]; static uint32_t FT2[256]; static uint32_t FT3[256]; +#endif /* !MBEDTLS_AES_FEWER_TABLES */ /* * Reverse S-box & tables */ static unsigned char RSb[256]; static uint32_t RT0[256]; +#if !defined(MBEDTLS_AES_FEWER_TABLES) static uint32_t RT1[256]; static uint32_t RT2[256]; static uint32_t RT3[256]; +#endif /* !MBEDTLS_AES_FEWER_TABLES */ /* * Round constants @@ -380,9 +395,9 @@ static uint32_t RCON[10]; /* * Tables generation code */ -#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) -#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) -#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) +#define ROTL8(x) ( ( (x) << 8 ) & 0xFFFFFFFF ) | ( (x) >> 24 ) +#define XTIME(x) ( ( (x) << 1 ) ^ ( ( (x) & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( (x) && (y) ) ? pow[(log[(x)]+log[(y)]) % 255] : 0 ) static int aes_init_done = 0; @@ -445,9 +460,11 @@ static void aes_gen_tables( void ) ( (uint32_t) x << 16 ) ^ ( (uint32_t) z << 24 ); +#if !defined(MBEDTLS_AES_FEWER_TABLES) FT1[i] = ROTL8( FT0[i] ); FT2[i] = ROTL8( FT1[i] ); FT3[i] = ROTL8( FT2[i] ); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ x = RSb[i]; @@ -456,16 +473,52 @@ static void aes_gen_tables( void ) ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ ( (uint32_t) MUL( 0x0B, x ) << 24 ); +#if !defined(MBEDTLS_AES_FEWER_TABLES) RT1[i] = ROTL8( RT0[i] ); RT2[i] = ROTL8( RT1[i] ); RT3[i] = ROTL8( RT2[i] ); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ } } +#undef ROTL8 + #endif /* MBEDTLS_AES_ROM_TABLES */ +#if defined(MBEDTLS_AES_FEWER_TABLES) + +#define ROTL8(x) ( (uint32_t)( ( x ) << 8 ) + (uint32_t)( ( x ) >> 24 ) ) +#define ROTL16(x) ( (uint32_t)( ( x ) << 16 ) + (uint32_t)( ( x ) >> 16 ) ) +#define ROTL24(x) ( (uint32_t)( ( x ) << 24 ) + (uint32_t)( ( x ) >> 8 ) ) + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) ROTL8( RT0[idx] ) +#define AES_RT2(idx) ROTL16( RT0[idx] ) +#define AES_RT3(idx) ROTL24( RT0[idx] ) + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) ROTL8( FT0[idx] ) +#define AES_FT2(idx) ROTL16( FT0[idx] ) +#define AES_FT3(idx) ROTL24( FT0[idx] ) + +#else /* MBEDTLS_AES_FEWER_TABLES */ + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) RT1[idx] +#define AES_RT2(idx) RT2[idx] +#define AES_RT3(idx) RT3[idx] + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) FT1[idx] +#define AES_FT2(idx) FT2[idx] +#define AES_FT3(idx) FT3[idx] + +#endif /* MBEDTLS_AES_FEWER_TABLES */ + void mbedtls_aes_init( mbedtls_aes_context *ctx ) { + AES_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); } @@ -474,8 +527,27 @@ void mbedtls_aes_free( mbedtls_aes_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +void mbedtls_aes_xts_init( mbedtls_aes_xts_context *ctx ) +{ + AES_VALIDATE( ctx != NULL ); + + mbedtls_aes_init( &ctx->crypt ); + mbedtls_aes_init( &ctx->tweak ); +} + +void mbedtls_aes_xts_free( mbedtls_aes_xts_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_aes_free( &ctx->crypt ); + mbedtls_aes_free( &ctx->tweak ); } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ /* * AES key schedule (encryption) @@ -487,14 +559,8 @@ int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, unsigned int i; uint32_t *RK; -#if !defined(MBEDTLS_AES_ROM_TABLES) - if( aes_init_done == 0 ) - { - aes_gen_tables(); - aes_init_done = 1; - - } -#endif + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); switch( keybits ) { @@ -504,6 +570,14 @@ int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); } +#if !defined(MBEDTLS_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + } +#endif + #if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) if( aes_padlock_ace == -1 ) aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); @@ -603,6 +677,9 @@ int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, uint32_t *RK; uint32_t *SK; + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); + mbedtls_aes_init( &cty ); #if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) @@ -641,10 +718,10 @@ int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, { for( j = 0; j < 4; j++, SK++ ) { - *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ - RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ - RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ - RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; + *RK++ = AES_RT0( FSb[ ( *SK ) & 0xFF ] ) ^ + AES_RT1( FSb[ ( *SK >> 8 ) & 0xFF ] ) ^ + AES_RT2( FSb[ ( *SK >> 16 ) & 0xFF ] ) ^ + AES_RT3( FSb[ ( *SK >> 24 ) & 0xFF ] ); } } @@ -658,53 +735,133 @@ int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, return( ret ); } -#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */ -#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ - FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ - FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y0 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ - FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ - FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y2 >> 24 ) & 0xFF ]; \ +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int mbedtls_aes_xts_decode_keys( const unsigned char *key, + unsigned int keybits, + const unsigned char **key1, + unsigned int *key1bits, + const unsigned char **key2, + unsigned int *key2bits ) +{ + const unsigned int half_keybits = keybits / 2; + const unsigned int half_keybytes = half_keybits / 8; + + switch( keybits ) + { + case 256: break; + case 512: break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + *key1bits = half_keybits; + *key2bits = half_keybits; + *key1 = &key[0]; + *key2 = &key[half_keybytes]; + + return 0; +} + +int mbedtls_aes_xts_setkey_enc( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); + + ret = mbedtls_aes_xts_decode_keys( key, keybits, &key1, &key1bits, + &key2, &key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set the tweak key. Always set tweak key for the encryption mode. */ + ret = mbedtls_aes_setkey_enc( &ctx->tweak, key2, key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set crypt key for encryption. */ + return mbedtls_aes_setkey_enc( &ctx->crypt, key1, key1bits ); } -#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ - RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ - RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y2 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ - RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ - RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y0 >> 24 ) & 0xFF ]; \ +int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); + + ret = mbedtls_aes_xts_decode_keys( key, keybits, &key1, &key1bits, + &key2, &key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set the tweak key. Always set tweak key for encryption. */ + ret = mbedtls_aes_setkey_enc( &ctx->tweak, key2, key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set crypt key for decryption. */ + return mbedtls_aes_setkey_dec( &ctx->crypt, key1, key1bits ); } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */ + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_FT0( ( (Y0) ) & 0xFF ) ^ \ + AES_FT1( ( (Y1) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y2) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y3) >> 24 ) & 0xFF ); \ + \ + (X1) = *RK++ ^ AES_FT0( ( (Y1) ) & 0xFF ) ^ \ + AES_FT1( ( (Y2) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y3) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y0) >> 24 ) & 0xFF ); \ + \ + (X2) = *RK++ ^ AES_FT0( ( (Y2) ) & 0xFF ) ^ \ + AES_FT1( ( (Y3) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y0) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y1) >> 24 ) & 0xFF ); \ + \ + (X3) = *RK++ ^ AES_FT0( ( (Y3) ) & 0xFF ) ^ \ + AES_FT1( ( (Y0) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y1) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y2) >> 24 ) & 0xFF ); \ + } while( 0 ) + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_RT0( ( (Y0) ) & 0xFF ) ^ \ + AES_RT1( ( (Y3) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y2) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y1) >> 24 ) & 0xFF ); \ + \ + (X1) = *RK++ ^ AES_RT0( ( (Y1) ) & 0xFF ) ^ \ + AES_RT1( ( (Y0) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y3) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y2) >> 24 ) & 0xFF ); \ + \ + (X2) = *RK++ ^ AES_RT0( ( (Y2) ) & 0xFF ) ^ \ + AES_RT1( ( (Y1) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y0) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y3) >> 24 ) & 0xFF ); \ + \ + (X3) = *RK++ ^ AES_RT0( ( (Y3) ) & 0xFF ) ^ \ + AES_RT1( ( (Y2) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y1) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y0) >> 24 ) & 0xFF ); \ + } while( 0 ) /* * AES-ECB block encryption @@ -846,10 +1003,16 @@ void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, * AES-ECB block encryption/decryption */ int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ) + int mode, + const unsigned char input[16], + unsigned char output[16] ) { + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + #if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) ); @@ -887,6 +1050,13 @@ int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, int i; unsigned char temp[16]; + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + if( length % 16 ) return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); @@ -939,6 +1109,172 @@ int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, } #endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) + +/* Endianess with 64 bits values */ +#ifndef GET_UINT64_LE +#define GET_UINT64_LE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) + 7] << 56 ) \ + | ( (uint64_t) (b)[(i) + 6] << 48 ) \ + | ( (uint64_t) (b)[(i) + 5] << 40 ) \ + | ( (uint64_t) (b)[(i) + 4] << 32 ) \ + | ( (uint64_t) (b)[(i) + 3] << 24 ) \ + | ( (uint64_t) (b)[(i) + 2] << 16 ) \ + | ( (uint64_t) (b)[(i) + 1] << 8 ) \ + | ( (uint64_t) (b)[(i) ] ); \ +} +#endif + +#ifndef PUT_UINT64_LE +#define PUT_UINT64_LE(n,b,i) \ +{ \ + (b)[(i) + 7] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) ] = (unsigned char) ( (n) ); \ +} +#endif + +typedef unsigned char mbedtls_be128[16]; + +/* + * GF(2^128) multiplication function + * + * This function multiplies a field element by x in the polynomial field + * representation. It uses 64-bit word operations to gain speed but compensates + * for machine endianess and hence works correctly on both big and little + * endian machines. + */ +static void mbedtls_gf128mul_x_ble( unsigned char r[16], + const unsigned char x[16] ) +{ + uint64_t a, b, ra, rb; + + GET_UINT64_LE( a, x, 0 ); + GET_UINT64_LE( b, x, 8 ); + + ra = ( a << 1 ) ^ 0x0087 >> ( 8 - ( ( b >> 63 ) << 3 ) ); + rb = ( a >> 63 ) | ( b << 1 ); + + PUT_UINT64_LE( ra, r, 0 ); + PUT_UINT64_LE( rb, r, 8 ); +} + +/* + * AES-XTS buffer encryption/decryption + */ +int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t blocks = length / 16; + size_t leftover = length % 16; + unsigned char tweak[16]; + unsigned char prev_tweak[16]; + unsigned char tmp[16]; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( data_unit != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + /* Data units must be at least 16 bytes long. */ + if( length < 16 ) + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + + /* NIST SP 800-38E disallows data units larger than 2**20 blocks. */ + if( length > ( 1 << 20 ) * 16 ) + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + + /* Compute the tweak. */ + ret = mbedtls_aes_crypt_ecb( &ctx->tweak, MBEDTLS_AES_ENCRYPT, + data_unit, tweak ); + if( ret != 0 ) + return( ret ); + + while( blocks-- ) + { + size_t i; + + if( leftover && ( mode == MBEDTLS_AES_DECRYPT ) && blocks == 0 ) + { + /* We are on the last block in a decrypt operation that has + * leftover bytes, so we need to use the next tweak for this block, + * and this tweak for the lefover bytes. Save the current tweak for + * the leftovers and then update the current tweak for use on this, + * the last full block. */ + memcpy( prev_tweak, tweak, sizeof( tweak ) ); + mbedtls_gf128mul_x_ble( tweak, tweak ); + } + + for( i = 0; i < 16; i++ ) + tmp[i] = input[i] ^ tweak[i]; + + ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp ); + if( ret != 0 ) + return( ret ); + + for( i = 0; i < 16; i++ ) + output[i] = tmp[i] ^ tweak[i]; + + /* Update the tweak for the next block. */ + mbedtls_gf128mul_x_ble( tweak, tweak ); + + output += 16; + input += 16; + } + + if( leftover ) + { + /* If we are on the leftover bytes in a decrypt operation, we need to + * use the previous tweak for these bytes (as saved in prev_tweak). */ + unsigned char *t = mode == MBEDTLS_AES_DECRYPT ? prev_tweak : tweak; + + /* We are now on the final part of the data unit, which doesn't divide + * evenly by 16. It's time for ciphertext stealing. */ + size_t i; + unsigned char *prev_output = output - 16; + + /* Copy ciphertext bytes from the previous block to our output for each + * byte of cyphertext we won't steal. At the same time, copy the + * remainder of the input for this final round (since the loop bounds + * are the same). */ + for( i = 0; i < leftover; i++ ) + { + output[i] = prev_output[i]; + tmp[i] = input[i] ^ t[i]; + } + + /* Copy ciphertext bytes from the previous block for input in this + * round. */ + for( ; i < 16; i++ ) + tmp[i] = prev_output[i] ^ t[i]; + + ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp ); + if( ret != 0 ) + return ret; + + /* Write the result back to the previous block, overriding the previous + * output we copied. */ + for( i = 0; i < 16; i++ ) + prev_output[i] = tmp[i] ^ t[i]; + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + #if defined(MBEDTLS_CIPHER_MODE_CFB) /* * AES-CFB128 buffer encryption/decryption @@ -952,7 +1288,20 @@ int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, unsigned char *output ) { int c; - size_t n = *iv_off; + size_t n; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( iv_off != NULL ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + n = *iv_off; + + if( n > 15 ) + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); if( mode == MBEDTLS_AES_DECRYPT ) { @@ -990,15 +1339,21 @@ int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, * AES-CFB8 buffer encryption/decryption */ int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) { unsigned char c; unsigned char ov[17]; + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); while( length-- ) { memcpy( ov, iv, 16 ); @@ -1017,7 +1372,52 @@ int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, return( 0 ); } -#endif /*MBEDTLS_CIPHER_MODE_CFB */ +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB (Output Feedback Mode) buffer encryption/decryption + */ +int mbedtls_aes_crypt_ofb( mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret = 0; + size_t n; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( iv_off != NULL ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + n = *iv_off; + + if( n > 15 ) + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) + { + ret = mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + if( ret != 0 ) + goto exit; + } + *output++ = *input++ ^ iv[n]; + + n = ( n + 1 ) & 0x0F; + } + + *iv_off = n; + +exit: + return( ret ); +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ #if defined(MBEDTLS_CIPHER_MODE_CTR) /* @@ -1032,7 +1432,19 @@ int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, unsigned char *output ) { int c, i; - size_t n = *nc_off; + size_t n; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( nc_off != NULL ); + AES_VALIDATE_RET( nonce_counter != NULL ); + AES_VALIDATE_RET( stream_block != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + n = *nc_off; + + if ( n > 0x0F ) + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); while( length-- ) { @@ -1171,6 +1583,72 @@ static const unsigned char aes_test_cfb128_ct[3][64] = }; #endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB test vectors from: + * + * https://csrc.nist.gov/publications/detail/sp/800-38a/final + */ +static const unsigned char aes_test_ofb_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_ofb_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_ofb_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_ofb_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, + 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25, + 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, + 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc, + 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, + 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, + 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01, + 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, + 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2, + 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, + 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, + 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, + 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, + 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, + 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, + 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84 } +}; +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + #if defined(MBEDTLS_CIPHER_MODE_CTR) /* * AES-CTR test vectors from: @@ -1234,6 +1712,74 @@ static const int aes_test_ctr_len[3] = { 16, 32, 36 }; #endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/* + * AES-XTS test vectors from: + * + * IEEE P1619/D16 Annex B + * https://web.archive.org/web/20150629024421/http://grouper.ieee.org/groups/1619/email/pdf00086.pdf + * (Archived from original at http://grouper.ieee.org/groups/1619/email/pdf00086.pdf) + */ +static const unsigned char aes_test_xts_key[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, +}; + +static const unsigned char aes_test_xts_pt32[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, +}; + +static const unsigned char aes_test_xts_ct32[][32] = +{ + { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e }, + { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 }, + { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a, + 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2, + 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53, + 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 }, +}; + +static const unsigned char aes_test_xts_data_unit[][16] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +}; + +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + /* * Checkup routine */ @@ -1250,11 +1796,14 @@ int mbedtls_aes_self_test( int verbose ) #if defined(MBEDTLS_CIPHER_MODE_CBC) unsigned char prv[16]; #endif -#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_OFB) size_t offset; #endif -#if defined(MBEDTLS_CIPHER_MODE_CTR) +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_XTS) int len; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) unsigned char nonce_counter[16]; unsigned char stream_block[16]; #endif @@ -1294,7 +1843,7 @@ int mbedtls_aes_self_test( int verbose ) * there is an alternative underlying implementation i.e. when * MBEDTLS_AES_ALT is defined. */ - if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 ) + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) { mbedtls_printf( "skipped\n" ); continue; @@ -1358,7 +1907,7 @@ int mbedtls_aes_self_test( int verbose ) * there is an alternative underlying implementation i.e. when * MBEDTLS_AES_ALT is defined. */ - if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 ) + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) { mbedtls_printf( "skipped\n" ); continue; @@ -1423,7 +1972,7 @@ int mbedtls_aes_self_test( int verbose ) * there is an alternative underlying implementation i.e. when * MBEDTLS_AES_ALT is defined. */ - if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 ) + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) { mbedtls_printf( "skipped\n" ); continue; @@ -1462,6 +2011,69 @@ int mbedtls_aes_self_test( int verbose ) mbedtls_printf( "\n" ); #endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /* + * OFB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-OFB-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_ofb_iv, 16 ); + memcpy( key, aes_test_ofb_key[u], keybits / 8 ); + + offset = 0; + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_ofb_ct[u], 64 ); + aes_tests = aes_test_ofb_pt; + } + else + { + memcpy( buf, aes_test_ofb_pt, 64 ); + aes_tests = aes_test_ofb_ct[u]; + } + + ret = mbedtls_aes_crypt_ofb( &ctx, 64, &offset, iv, buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, 64 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + #if defined(MBEDTLS_CIPHER_MODE_CTR) /* * CTR mode @@ -1514,6 +2126,73 @@ int mbedtls_aes_self_test( int verbose ) mbedtls_printf( "\n" ); #endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) + { + static const int num_tests = + sizeof(aes_test_xts_key) / sizeof(*aes_test_xts_key); + mbedtls_aes_xts_context ctx_xts; + + /* + * XTS mode + */ + mbedtls_aes_xts_init( &ctx_xts ); + + for( i = 0; i < num_tests << 1; i++ ) + { + const unsigned char *data_unit; + u = i >> 1; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-XTS-128 (%s): ", + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( key, 0, sizeof( key ) ); + memcpy( key, aes_test_xts_key[u], 32 ); + data_unit = aes_test_xts_data_unit[u]; + + len = sizeof( *aes_test_xts_ct32 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + ret = mbedtls_aes_xts_setkey_dec( &ctx_xts, key, 256 ); + if( ret != 0) + goto exit; + memcpy( buf, aes_test_xts_ct32[u], len ); + aes_tests = aes_test_xts_pt32[u]; + } + else + { + ret = mbedtls_aes_xts_setkey_enc( &ctx_xts, key, 256 ); + if( ret != 0) + goto exit; + memcpy( buf, aes_test_xts_pt32[u], len ); + aes_tests = aes_test_xts_ct32[u]; + } + + + ret = mbedtls_aes_crypt_xts( &ctx_xts, mode, len, data_unit, + buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, len ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + mbedtls_aes_xts_free( &ctx_xts ); + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + ret = 0; exit: diff --git a/app/mbedtls/library/aesni.c b/app/mbedtls/library/aesni.c index 1ca3c3ef5b..062708b047 100644 --- a/app/mbedtls/library/aesni.c +++ b/app/mbedtls/library/aesni.c @@ -32,6 +32,12 @@ #if defined(MBEDTLS_AESNI_C) +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#warning "MBEDTLS_AESNI_C is known to cause spurious error reports with some memory sanitizers as they do not understand the assembly code." +#endif +#endif + #include "mbedtls/aesni.h" #include diff --git a/app/mbedtls/library/arc4.c b/app/mbedtls/library/arc4.c index 05b33d3fdb..b8998ac6cd 100644 --- a/app/mbedtls/library/arc4.c +++ b/app/mbedtls/library/arc4.c @@ -33,6 +33,7 @@ #if defined(MBEDTLS_ARC4_C) #include "mbedtls/arc4.h" +#include "mbedtls/platform_util.h" #include @@ -47,11 +48,6 @@ #if !defined(MBEDTLS_ARC4_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} - void mbedtls_arc4_init( mbedtls_arc4_context *ctx ) { memset( ctx, 0, sizeof( mbedtls_arc4_context ) ); @@ -62,7 +58,7 @@ void mbedtls_arc4_free( mbedtls_arc4_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_arc4_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_arc4_context ) ); } /* diff --git a/app/mbedtls/library/aria.c b/app/mbedtls/library/aria.c new file mode 100644 index 0000000000..aff66d667f --- /dev/null +++ b/app/mbedtls/library/aria.c @@ -0,0 +1,1079 @@ +/* + * ARIA implementation + * + * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * This implementation is based on the following standards: + * [1] http://210.104.33.10/ARIA/doc/ARIA-specification-e.pdf + * [2] https://tools.ietf.org/html/rfc5794 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ARIA_C) + +#include "mbedtls/aria.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_ARIA_ALT) + +#include "mbedtls/platform_util.h" + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define ARIA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ) +#define ARIA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE( n, b, i ) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE( n, b, i ) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +/* + * modify byte order: ( A B C D ) -> ( B A D C ), i.e. swap pairs of bytes + * + * This is submatrix P1 in [1] Appendix B.1 + * + * Common compilers fail to translate this to minimal number of instructions, + * so let's provide asm versions for common platforms with C fallback. + */ +#if defined(MBEDTLS_HAVE_ASM) +#if defined(__arm__) /* rev16 available from v6 up */ +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) && \ + __ARM_ARCH >= 6 +static inline uint32_t aria_p1( uint32_t x ) +{ + uint32_t r; + __asm( "rev16 %0, %1" : "=l" (r) : "l" (x) ); + return( r ); +} +#define ARIA_P1 aria_p1 +#elif defined(__ARMCC_VERSION) && __ARMCC_VERSION < 6000000 && \ + ( __TARGET_ARCH_ARM >= 6 || __TARGET_ARCH_THUMB >= 3 ) +static inline uint32_t aria_p1( uint32_t x ) +{ + uint32_t r; + __asm( "rev16 r, x" ); + return( r ); +} +#define ARIA_P1 aria_p1 +#endif +#endif /* arm */ +#if defined(__GNUC__) && \ + defined(__i386__) || defined(__amd64__) || defined( __x86_64__) +/* I couldn't find an Intel equivalent of rev16, so two instructions */ +#define ARIA_P1(x) ARIA_P2( ARIA_P3( x ) ) +#endif /* x86 gnuc */ +#endif /* MBEDTLS_HAVE_ASM && GNUC */ +#if !defined(ARIA_P1) +#define ARIA_P1(x) ((((x) >> 8) & 0x00FF00FF) ^ (((x) & 0x00FF00FF) << 8)) +#endif + +/* + * modify byte order: ( A B C D ) -> ( C D A B ), i.e. rotate by 16 bits + * + * This is submatrix P2 in [1] Appendix B.1 + * + * Common compilers will translate this to a single instruction. + */ +#define ARIA_P2(x) (((x) >> 16) ^ ((x) << 16)) + +/* + * modify byte order: ( A B C D ) -> ( D C B A ), i.e. change endianness + * + * This is submatrix P3 in [1] Appendix B.1 + * + * Some compilers fail to translate this to a single instruction, + * so let's provide asm versions for common platforms with C fallback. + */ +#if defined(MBEDTLS_HAVE_ASM) +#if defined(__arm__) /* rev available from v6 up */ +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) && \ + __ARM_ARCH >= 6 +static inline uint32_t aria_p3( uint32_t x ) +{ + uint32_t r; + __asm( "rev %0, %1" : "=l" (r) : "l" (x) ); + return( r ); +} +#define ARIA_P3 aria_p3 +#elif defined(__ARMCC_VERSION) && __ARMCC_VERSION < 6000000 && \ + ( __TARGET_ARCH_ARM >= 6 || __TARGET_ARCH_THUMB >= 3 ) +static inline uint32_t aria_p3( uint32_t x ) +{ + uint32_t r; + __asm( "rev r, x" ); + return( r ); +} +#define ARIA_P3 aria_p3 +#endif +#endif /* arm */ +#if defined(__GNUC__) && \ + defined(__i386__) || defined(__amd64__) || defined( __x86_64__) +static inline uint32_t aria_p3( uint32_t x ) +{ + __asm( "bswap %0" : "=r" (x) : "0" (x) ); + return( x ); +} +#define ARIA_P3 aria_p3 +#endif /* x86 gnuc */ +#endif /* MBEDTLS_HAVE_ASM && GNUC */ +#if !defined(ARIA_P3) +#define ARIA_P3(x) ARIA_P2( ARIA_P1 ( x ) ) +#endif + +/* + * ARIA Affine Transform + * (a, b, c, d) = state in/out + * + * If we denote the first byte of input by 0, ..., the last byte by f, + * then inputs are: a = 0123, b = 4567, c = 89ab, d = cdef. + * + * Reading [1] 2.4 or [2] 2.4.3 in columns and performing simple + * rearrangements on adjacent pairs, output is: + * + * a = 3210 + 4545 + 6767 + 88aa + 99bb + dccd + effe + * = 3210 + 4567 + 6745 + 89ab + 98ba + dcfe + efcd + * b = 0101 + 2323 + 5476 + 8998 + baab + eecc + ffdd + * = 0123 + 2301 + 5476 + 89ab + ba98 + efcd + fedc + * c = 0022 + 1133 + 4554 + 7667 + ab89 + dcdc + fefe + * = 0123 + 1032 + 4567 + 7654 + ab89 + dcfe + fedc + * d = 1001 + 2332 + 6644 + 7755 + 9898 + baba + cdef + * = 1032 + 2301 + 6745 + 7654 + 98ba + ba98 + cdef + * + * Note: another presentation of the A transform can be found as the first + * half of App. B.1 in [1] in terms of 4-byte operators P1, P2, P3 and P4. + * The implementation below uses only P1 and P2 as they are sufficient. + */ +static inline void aria_a( uint32_t *a, uint32_t *b, + uint32_t *c, uint32_t *d ) +{ + uint32_t ta, tb, tc; + ta = *b; // 4567 + *b = *a; // 0123 + *a = ARIA_P2( ta ); // 6745 + tb = ARIA_P2( *d ); // efcd + *d = ARIA_P1( *c ); // 98ba + *c = ARIA_P1( tb ); // fedc + ta ^= *d; // 4567+98ba + tc = ARIA_P2( *b ); // 2301 + ta = ARIA_P1( ta ) ^ tc ^ *c; // 2301+5476+89ab+fedc + tb ^= ARIA_P2( *d ); // ba98+efcd + tc ^= ARIA_P1( *a ); // 2301+7654 + *b ^= ta ^ tb; // 0123+2301+5476+89ab+ba98+efcd+fedc OUT + tb = ARIA_P2( tb ) ^ ta; // 2301+5476+89ab+98ba+cdef+fedc + *a ^= ARIA_P1( tb ); // 3210+4567+6745+89ab+98ba+dcfe+efcd OUT + ta = ARIA_P2( ta ); // 0123+7654+ab89+dcfe + *d ^= ARIA_P1( ta ) ^ tc; // 1032+2301+6745+7654+98ba+ba98+cdef OUT + tc = ARIA_P2( tc ); // 0123+5476 + *c ^= ARIA_P1( tc ) ^ ta; // 0123+1032+4567+7654+ab89+dcfe+fedc OUT +} + +/* + * ARIA Substitution Layer SL1 / SL2 + * (a, b, c, d) = state in/out + * (sa, sb, sc, sd) = 256 8-bit S-Boxes (see below) + * + * By passing sb1, sb2, is1, is2 as S-Boxes you get SL1 + * By passing is1, is2, sb1, sb2 as S-Boxes you get SL2 + */ +static inline void aria_sl( uint32_t *a, uint32_t *b, + uint32_t *c, uint32_t *d, + const uint8_t sa[256], const uint8_t sb[256], + const uint8_t sc[256], const uint8_t sd[256] ) +{ + *a = ( (uint32_t) sa[ *a & 0xFF] ) ^ + (((uint32_t) sb[(*a >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*a >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *a >> 24 ]) << 24); + *b = ( (uint32_t) sa[ *b & 0xFF] ) ^ + (((uint32_t) sb[(*b >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*b >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *b >> 24 ]) << 24); + *c = ( (uint32_t) sa[ *c & 0xFF] ) ^ + (((uint32_t) sb[(*c >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*c >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *c >> 24 ]) << 24); + *d = ( (uint32_t) sa[ *d & 0xFF] ) ^ + (((uint32_t) sb[(*d >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*d >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *d >> 24 ]) << 24); +} + +/* + * S-Boxes + */ +static const uint8_t aria_sb1[256] = +{ + 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 +}; + +static const uint8_t aria_sb2[256] = +{ + 0xE2, 0x4E, 0x54, 0xFC, 0x94, 0xC2, 0x4A, 0xCC, 0x62, 0x0D, 0x6A, 0x46, + 0x3C, 0x4D, 0x8B, 0xD1, 0x5E, 0xFA, 0x64, 0xCB, 0xB4, 0x97, 0xBE, 0x2B, + 0xBC, 0x77, 0x2E, 0x03, 0xD3, 0x19, 0x59, 0xC1, 0x1D, 0x06, 0x41, 0x6B, + 0x55, 0xF0, 0x99, 0x69, 0xEA, 0x9C, 0x18, 0xAE, 0x63, 0xDF, 0xE7, 0xBB, + 0x00, 0x73, 0x66, 0xFB, 0x96, 0x4C, 0x85, 0xE4, 0x3A, 0x09, 0x45, 0xAA, + 0x0F, 0xEE, 0x10, 0xEB, 0x2D, 0x7F, 0xF4, 0x29, 0xAC, 0xCF, 0xAD, 0x91, + 0x8D, 0x78, 0xC8, 0x95, 0xF9, 0x2F, 0xCE, 0xCD, 0x08, 0x7A, 0x88, 0x38, + 0x5C, 0x83, 0x2A, 0x28, 0x47, 0xDB, 0xB8, 0xC7, 0x93, 0xA4, 0x12, 0x53, + 0xFF, 0x87, 0x0E, 0x31, 0x36, 0x21, 0x58, 0x48, 0x01, 0x8E, 0x37, 0x74, + 0x32, 0xCA, 0xE9, 0xB1, 0xB7, 0xAB, 0x0C, 0xD7, 0xC4, 0x56, 0x42, 0x26, + 0x07, 0x98, 0x60, 0xD9, 0xB6, 0xB9, 0x11, 0x40, 0xEC, 0x20, 0x8C, 0xBD, + 0xA0, 0xC9, 0x84, 0x04, 0x49, 0x23, 0xF1, 0x4F, 0x50, 0x1F, 0x13, 0xDC, + 0xD8, 0xC0, 0x9E, 0x57, 0xE3, 0xC3, 0x7B, 0x65, 0x3B, 0x02, 0x8F, 0x3E, + 0xE8, 0x25, 0x92, 0xE5, 0x15, 0xDD, 0xFD, 0x17, 0xA9, 0xBF, 0xD4, 0x9A, + 0x7E, 0xC5, 0x39, 0x67, 0xFE, 0x76, 0x9D, 0x43, 0xA7, 0xE1, 0xD0, 0xF5, + 0x68, 0xF2, 0x1B, 0x34, 0x70, 0x05, 0xA3, 0x8A, 0xD5, 0x79, 0x86, 0xA8, + 0x30, 0xC6, 0x51, 0x4B, 0x1E, 0xA6, 0x27, 0xF6, 0x35, 0xD2, 0x6E, 0x24, + 0x16, 0x82, 0x5F, 0xDA, 0xE6, 0x75, 0xA2, 0xEF, 0x2C, 0xB2, 0x1C, 0x9F, + 0x5D, 0x6F, 0x80, 0x0A, 0x72, 0x44, 0x9B, 0x6C, 0x90, 0x0B, 0x5B, 0x33, + 0x7D, 0x5A, 0x52, 0xF3, 0x61, 0xA1, 0xF7, 0xB0, 0xD6, 0x3F, 0x7C, 0x6D, + 0xED, 0x14, 0xE0, 0xA5, 0x3D, 0x22, 0xB3, 0xF8, 0x89, 0xDE, 0x71, 0x1A, + 0xAF, 0xBA, 0xB5, 0x81 +}; + +static const uint8_t aria_is1[256] = +{ + 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 uint8_t aria_is2[256] = +{ + 0x30, 0x68, 0x99, 0x1B, 0x87, 0xB9, 0x21, 0x78, 0x50, 0x39, 0xDB, 0xE1, + 0x72, 0x09, 0x62, 0x3C, 0x3E, 0x7E, 0x5E, 0x8E, 0xF1, 0xA0, 0xCC, 0xA3, + 0x2A, 0x1D, 0xFB, 0xB6, 0xD6, 0x20, 0xC4, 0x8D, 0x81, 0x65, 0xF5, 0x89, + 0xCB, 0x9D, 0x77, 0xC6, 0x57, 0x43, 0x56, 0x17, 0xD4, 0x40, 0x1A, 0x4D, + 0xC0, 0x63, 0x6C, 0xE3, 0xB7, 0xC8, 0x64, 0x6A, 0x53, 0xAA, 0x38, 0x98, + 0x0C, 0xF4, 0x9B, 0xED, 0x7F, 0x22, 0x76, 0xAF, 0xDD, 0x3A, 0x0B, 0x58, + 0x67, 0x88, 0x06, 0xC3, 0x35, 0x0D, 0x01, 0x8B, 0x8C, 0xC2, 0xE6, 0x5F, + 0x02, 0x24, 0x75, 0x93, 0x66, 0x1E, 0xE5, 0xE2, 0x54, 0xD8, 0x10, 0xCE, + 0x7A, 0xE8, 0x08, 0x2C, 0x12, 0x97, 0x32, 0xAB, 0xB4, 0x27, 0x0A, 0x23, + 0xDF, 0xEF, 0xCA, 0xD9, 0xB8, 0xFA, 0xDC, 0x31, 0x6B, 0xD1, 0xAD, 0x19, + 0x49, 0xBD, 0x51, 0x96, 0xEE, 0xE4, 0xA8, 0x41, 0xDA, 0xFF, 0xCD, 0x55, + 0x86, 0x36, 0xBE, 0x61, 0x52, 0xF8, 0xBB, 0x0E, 0x82, 0x48, 0x69, 0x9A, + 0xE0, 0x47, 0x9E, 0x5C, 0x04, 0x4B, 0x34, 0x15, 0x79, 0x26, 0xA7, 0xDE, + 0x29, 0xAE, 0x92, 0xD7, 0x84, 0xE9, 0xD2, 0xBA, 0x5D, 0xF3, 0xC5, 0xB0, + 0xBF, 0xA4, 0x3B, 0x71, 0x44, 0x46, 0x2B, 0xFC, 0xEB, 0x6F, 0xD5, 0xF6, + 0x14, 0xFE, 0x7C, 0x70, 0x5A, 0x7D, 0xFD, 0x2F, 0x18, 0x83, 0x16, 0xA5, + 0x91, 0x1F, 0x05, 0x95, 0x74, 0xA9, 0xC1, 0x5B, 0x4A, 0x85, 0x6D, 0x13, + 0x07, 0x4F, 0x4E, 0x45, 0xB2, 0x0F, 0xC9, 0x1C, 0xA6, 0xBC, 0xEC, 0x73, + 0x90, 0x7B, 0xCF, 0x59, 0x8F, 0xA1, 0xF9, 0x2D, 0xF2, 0xB1, 0x00, 0x94, + 0x37, 0x9F, 0xD0, 0x2E, 0x9C, 0x6E, 0x28, 0x3F, 0x80, 0xF0, 0x3D, 0xD3, + 0x25, 0x8A, 0xB5, 0xE7, 0x42, 0xB3, 0xC7, 0xEA, 0xF7, 0x4C, 0x11, 0x33, + 0x03, 0xA2, 0xAC, 0x60 +}; + +/* + * Helper for key schedule: r = FO( p, k ) ^ x + */ +static void aria_fo_xor( uint32_t r[4], const uint32_t p[4], + const uint32_t k[4], const uint32_t x[4] ) +{ + uint32_t a, b, c, d; + + a = p[0] ^ k[0]; + b = p[1] ^ k[1]; + c = p[2] ^ k[2]; + d = p[3] ^ k[3]; + + aria_sl( &a, &b, &c, &d, aria_sb1, aria_sb2, aria_is1, aria_is2 ); + aria_a( &a, &b, &c, &d ); + + r[0] = a ^ x[0]; + r[1] = b ^ x[1]; + r[2] = c ^ x[2]; + r[3] = d ^ x[3]; +} + +/* + * Helper for key schedule: r = FE( p, k ) ^ x + */ +static void aria_fe_xor( uint32_t r[4], const uint32_t p[4], + const uint32_t k[4], const uint32_t x[4] ) +{ + uint32_t a, b, c, d; + + a = p[0] ^ k[0]; + b = p[1] ^ k[1]; + c = p[2] ^ k[2]; + d = p[3] ^ k[3]; + + aria_sl( &a, &b, &c, &d, aria_is1, aria_is2, aria_sb1, aria_sb2 ); + aria_a( &a, &b, &c, &d ); + + r[0] = a ^ x[0]; + r[1] = b ^ x[1]; + r[2] = c ^ x[2]; + r[3] = d ^ x[3]; +} + +/* + * Big endian 128-bit rotation: r = a ^ (b <<< n), used only in key setup. + * + * We chose to store bytes into 32-bit words in little-endian format (see + * GET/PUT_UINT32_LE) so we need to reverse bytes here. + */ +static void aria_rot128( uint32_t r[4], const uint32_t a[4], + const uint32_t b[4], uint8_t n ) +{ + uint8_t i, j; + uint32_t t, u; + + const uint8_t n1 = n % 32; // bit offset + const uint8_t n2 = n1 ? 32 - n1 : 0; // reverse bit offset + + j = ( n / 32 ) % 4; // initial word offset + t = ARIA_P3( b[j] ); // big endian + for( i = 0; i < 4; i++ ) + { + j = ( j + 1 ) % 4; // get next word, big endian + u = ARIA_P3( b[j] ); + t <<= n1; // rotate + t |= u >> n2; + t = ARIA_P3( t ); // back to little endian + r[i] = a[i] ^ t; // store + t = u; // move to next word + } +} + +/* + * Set encryption key + */ +int mbedtls_aria_setkey_enc( mbedtls_aria_context *ctx, + const unsigned char *key, unsigned int keybits ) +{ + /* round constant masks */ + const uint32_t rc[3][4] = + { + { 0xB7C17C51, 0x940A2227, 0xE8AB13FE, 0xE06E9AFA }, + { 0xCC4AB16D, 0x20C8219E, 0xD5B128FF, 0xB0E25DEF }, + { 0x1D3792DB, 0x70E92621, 0x75972403, 0x0EC9E804 } + }; + + int i; + uint32_t w[4][4], *w2; + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( key != NULL ); + + if( keybits != 128 && keybits != 192 && keybits != 256 ) + return( MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ); + + /* Copy key to W0 (and potential remainder to W1) */ + GET_UINT32_LE( w[0][0], key, 0 ); + GET_UINT32_LE( w[0][1], key, 4 ); + GET_UINT32_LE( w[0][2], key, 8 ); + GET_UINT32_LE( w[0][3], key, 12 ); + + memset( w[1], 0, 16 ); + if( keybits >= 192 ) + { + GET_UINT32_LE( w[1][0], key, 16 ); // 192 bit key + GET_UINT32_LE( w[1][1], key, 20 ); + } + if( keybits == 256 ) + { + GET_UINT32_LE( w[1][2], key, 24 ); // 256 bit key + GET_UINT32_LE( w[1][3], key, 28 ); + } + + i = ( keybits - 128 ) >> 6; // index: 0, 1, 2 + ctx->nr = 12 + 2 * i; // no. rounds: 12, 14, 16 + + aria_fo_xor( w[1], w[0], rc[i], w[1] ); // W1 = FO(W0, CK1) ^ KR + i = i < 2 ? i + 1 : 0; + aria_fe_xor( w[2], w[1], rc[i], w[0] ); // W2 = FE(W1, CK2) ^ W0 + i = i < 2 ? i + 1 : 0; + aria_fo_xor( w[3], w[2], rc[i], w[1] ); // W3 = FO(W2, CK3) ^ W1 + + for( i = 0; i < 4; i++ ) // create round keys + { + w2 = w[(i + 1) & 3]; + aria_rot128( ctx->rk[i ], w[i], w2, 128 - 19 ); + aria_rot128( ctx->rk[i + 4], w[i], w2, 128 - 31 ); + aria_rot128( ctx->rk[i + 8], w[i], w2, 61 ); + aria_rot128( ctx->rk[i + 12], w[i], w2, 31 ); + } + aria_rot128( ctx->rk[16], w[0], w[1], 19 ); + + /* w holds enough info to reconstruct the round keys */ + mbedtls_platform_zeroize( w, sizeof( w ) ); + + return( 0 ); +} + +/* + * Set decryption key + */ +int mbedtls_aria_setkey_dec( mbedtls_aria_context *ctx, + const unsigned char *key, unsigned int keybits ) +{ + int i, j, k, ret; + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( key != NULL ); + + ret = mbedtls_aria_setkey_enc( ctx, key, keybits ); + if( ret != 0 ) + return( ret ); + + /* flip the order of round keys */ + for( i = 0, j = ctx->nr; i < j; i++, j-- ) + { + for( k = 0; k < 4; k++ ) + { + uint32_t t = ctx->rk[i][k]; + ctx->rk[i][k] = ctx->rk[j][k]; + ctx->rk[j][k] = t; + } + } + + /* apply affine transform to middle keys */ + for( i = 1; i < ctx->nr; i++ ) + { + aria_a( &ctx->rk[i][0], &ctx->rk[i][1], + &ctx->rk[i][2], &ctx->rk[i][3] ); + } + + return( 0 ); +} + +/* + * Encrypt a block + */ +int mbedtls_aria_crypt_ecb( mbedtls_aria_context *ctx, + const unsigned char input[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char output[MBEDTLS_ARIA_BLOCKSIZE] ) +{ + int i; + + uint32_t a, b, c, d; + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( input != NULL ); + ARIA_VALIDATE_RET( output != NULL ); + + GET_UINT32_LE( a, input, 0 ); + GET_UINT32_LE( b, input, 4 ); + GET_UINT32_LE( c, input, 8 ); + GET_UINT32_LE( d, input, 12 ); + + i = 0; + while( 1 ) + { + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + i++; + + aria_sl( &a, &b, &c, &d, aria_sb1, aria_sb2, aria_is1, aria_is2 ); + aria_a( &a, &b, &c, &d ); + + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + i++; + + aria_sl( &a, &b, &c, &d, aria_is1, aria_is2, aria_sb1, aria_sb2 ); + if( i >= ctx->nr ) + break; + aria_a( &a, &b, &c, &d ); + } + + /* final key mixing */ + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + + PUT_UINT32_LE( a, output, 0 ); + PUT_UINT32_LE( b, output, 4 ); + PUT_UINT32_LE( c, output, 8 ); + PUT_UINT32_LE( d, output, 12 ); + + return( 0 ); +} + +/* Initialize context */ +void mbedtls_aria_init( mbedtls_aria_context *ctx ) +{ + ARIA_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_aria_context ) ); +} + +/* Clear context */ +void mbedtls_aria_free( mbedtls_aria_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_aria_context ) ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * ARIA-CBC buffer encryption/decryption + */ +int mbedtls_aria_crypt_cbc( mbedtls_aria_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[MBEDTLS_ARIA_BLOCKSIZE]; + + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( mode == MBEDTLS_ARIA_ENCRYPT || + mode == MBEDTLS_ARIA_DECRYPT ); + ARIA_VALIDATE_RET( length == 0 || input != NULL ); + ARIA_VALIDATE_RET( length == 0 || output != NULL ); + ARIA_VALIDATE_RET( iv != NULL ); + + if( length % MBEDTLS_ARIA_BLOCKSIZE ) + return( MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_ARIA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, MBEDTLS_ARIA_BLOCKSIZE ); + mbedtls_aria_crypt_ecb( ctx, input, output ); + + for( i = 0; i < MBEDTLS_ARIA_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, MBEDTLS_ARIA_BLOCKSIZE ); + + input += MBEDTLS_ARIA_BLOCKSIZE; + output += MBEDTLS_ARIA_BLOCKSIZE; + length -= MBEDTLS_ARIA_BLOCKSIZE; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < MBEDTLS_ARIA_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_aria_crypt_ecb( ctx, output, output ); + memcpy( iv, output, MBEDTLS_ARIA_BLOCKSIZE ); + + input += MBEDTLS_ARIA_BLOCKSIZE; + output += MBEDTLS_ARIA_BLOCKSIZE; + length -= MBEDTLS_ARIA_BLOCKSIZE; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * ARIA-CFB128 buffer encryption/decryption + */ +int mbedtls_aria_crypt_cfb128( mbedtls_aria_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + size_t n; + + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( mode == MBEDTLS_ARIA_ENCRYPT || + mode == MBEDTLS_ARIA_DECRYPT ); + ARIA_VALIDATE_RET( length == 0 || input != NULL ); + ARIA_VALIDATE_RET( length == 0 || output != NULL ); + ARIA_VALIDATE_RET( iv != NULL ); + ARIA_VALIDATE_RET( iv_off != NULL ); + + n = *iv_off; + + /* An overly large value of n can lead to an unlimited + * buffer overflow. Therefore, guard against this + * outside of parameter validation. */ + if( n >= MBEDTLS_ARIA_BLOCKSIZE ) + return( MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ); + + if( mode == MBEDTLS_ARIA_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aria_crypt_ecb( ctx, iv, iv ); + + c = *input++; + *output++ = c ^ iv[n]; + iv[n] = c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aria_crypt_ecb( ctx, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * ARIA-CTR buffer encryption/decryption + */ +int mbedtls_aria_crypt_ctr( mbedtls_aria_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n; + + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( length == 0 || input != NULL ); + ARIA_VALIDATE_RET( length == 0 || output != NULL ); + ARIA_VALIDATE_RET( nonce_counter != NULL ); + ARIA_VALIDATE_RET( stream_block != NULL ); + ARIA_VALIDATE_RET( nc_off != NULL ); + + n = *nc_off; + /* An overly large value of n can lead to an unlimited + * buffer overflow. Therefore, guard against this + * outside of parameter validation. */ + if( n >= MBEDTLS_ARIA_BLOCKSIZE ) + return( MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) { + mbedtls_aria_crypt_ecb( ctx, nonce_counter, + stream_block ); + + for( i = MBEDTLS_ARIA_BLOCKSIZE; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* !MBEDTLS_ARIA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Basic ARIA ECB test vectors from RFC 5794 + */ +static const uint8_t aria_test1_ecb_key[32] = // test key +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 128 bit + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // 192 bit + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F // 256 bit +}; + +static const uint8_t aria_test1_ecb_pt[MBEDTLS_ARIA_BLOCKSIZE] = // plaintext +{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // same for all + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF // key sizes +}; + +static const uint8_t aria_test1_ecb_ct[3][MBEDTLS_ARIA_BLOCKSIZE] = // ciphertext +{ + { 0xD7, 0x18, 0xFB, 0xD6, 0xAB, 0x64, 0x4C, 0x73, // 128 bit + 0x9D, 0xA9, 0x5F, 0x3B, 0xE6, 0x45, 0x17, 0x78 }, + { 0x26, 0x44, 0x9C, 0x18, 0x05, 0xDB, 0xE7, 0xAA, // 192 bit + 0x25, 0xA4, 0x68, 0xCE, 0x26, 0x3A, 0x9E, 0x79 }, + { 0xF9, 0x2B, 0xD7, 0xC7, 0x9F, 0xB7, 0x2E, 0x2F, // 256 bit + 0x2B, 0x8F, 0x80, 0xC1, 0x97, 0x2D, 0x24, 0xFC } +}; + +/* + * Mode tests from "Test Vectors for ARIA" Version 1.0 + * http://210.104.33.10/ARIA/doc/ARIA-testvector-e.pdf + */ +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR)) +static const uint8_t aria_test2_key[32] = +{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 128 bit + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 192 bit + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff // 256 bit +}; + +static const uint8_t aria_test2_pt[48] = +{ + 0x11, 0x11, 0x11, 0x11, 0xaa, 0xaa, 0xaa, 0xaa, // same for all + 0x11, 0x11, 0x11, 0x11, 0xbb, 0xbb, 0xbb, 0xbb, + 0x11, 0x11, 0x11, 0x11, 0xcc, 0xcc, 0xcc, 0xcc, + 0x11, 0x11, 0x11, 0x11, 0xdd, 0xdd, 0xdd, 0xdd, + 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, + 0x22, 0x22, 0x22, 0x22, 0xbb, 0xbb, 0xbb, 0xbb, +}; +#endif + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB)) +static const uint8_t aria_test2_iv[MBEDTLS_ARIA_BLOCKSIZE] = +{ + 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78, // same for CBC, CFB + 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, 0xf0 // CTR has zero IV +}; +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const uint8_t aria_test2_cbc_ct[3][48] = // CBC ciphertext +{ + { 0x49, 0xd6, 0x18, 0x60, 0xb1, 0x49, 0x09, 0x10, // 128-bit key + 0x9c, 0xef, 0x0d, 0x22, 0xa9, 0x26, 0x81, 0x34, + 0xfa, 0xdf, 0x9f, 0xb2, 0x31, 0x51, 0xe9, 0x64, + 0x5f, 0xba, 0x75, 0x01, 0x8b, 0xdb, 0x15, 0x38, + 0xb5, 0x33, 0x34, 0x63, 0x4b, 0xbf, 0x7d, 0x4c, + 0xd4, 0xb5, 0x37, 0x70, 0x33, 0x06, 0x0c, 0x15 }, + { 0xaf, 0xe6, 0xcf, 0x23, 0x97, 0x4b, 0x53, 0x3c, // 192-bit key + 0x67, 0x2a, 0x82, 0x62, 0x64, 0xea, 0x78, 0x5f, + 0x4e, 0x4f, 0x7f, 0x78, 0x0d, 0xc7, 0xf3, 0xf1, + 0xe0, 0x96, 0x2b, 0x80, 0x90, 0x23, 0x86, 0xd5, + 0x14, 0xe9, 0xc3, 0xe7, 0x72, 0x59, 0xde, 0x92, + 0xdd, 0x11, 0x02, 0xff, 0xab, 0x08, 0x6c, 0x1e }, + { 0x52, 0x3a, 0x8a, 0x80, 0x6a, 0xe6, 0x21, 0xf1, // 256-bit key + 0x55, 0xfd, 0xd2, 0x8d, 0xbc, 0x34, 0xe1, 0xab, + 0x7b, 0x9b, 0x42, 0x43, 0x2a, 0xd8, 0xb2, 0xef, + 0xb9, 0x6e, 0x23, 0xb1, 0x3f, 0x0a, 0x6e, 0x52, + 0xf3, 0x61, 0x85, 0xd5, 0x0a, 0xd0, 0x02, 0xc5, + 0xf6, 0x01, 0xbe, 0xe5, 0x49, 0x3f, 0x11, 0x8b } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const uint8_t aria_test2_cfb_ct[3][48] = // CFB ciphertext +{ + { 0x37, 0x20, 0xe5, 0x3b, 0xa7, 0xd6, 0x15, 0x38, // 128-bit key + 0x34, 0x06, 0xb0, 0x9f, 0x0a, 0x05, 0xa2, 0x00, + 0xc0, 0x7c, 0x21, 0xe6, 0x37, 0x0f, 0x41, 0x3a, + 0x5d, 0x13, 0x25, 0x00, 0xa6, 0x82, 0x85, 0x01, + 0x7c, 0x61, 0xb4, 0x34, 0xc7, 0xb7, 0xca, 0x96, + 0x85, 0xa5, 0x10, 0x71, 0x86, 0x1e, 0x4d, 0x4b }, + { 0x41, 0x71, 0xf7, 0x19, 0x2b, 0xf4, 0x49, 0x54, // 192-bit key + 0x94, 0xd2, 0x73, 0x61, 0x29, 0x64, 0x0f, 0x5c, + 0x4d, 0x87, 0xa9, 0xa2, 0x13, 0x66, 0x4c, 0x94, + 0x48, 0x47, 0x7c, 0x6e, 0xcc, 0x20, 0x13, 0x59, + 0x8d, 0x97, 0x66, 0x95, 0x2d, 0xd8, 0xc3, 0x86, + 0x8f, 0x17, 0xe3, 0x6e, 0xf6, 0x6f, 0xd8, 0x4b }, + { 0x26, 0x83, 0x47, 0x05, 0xb0, 0xf2, 0xc0, 0xe2, // 256-bit key + 0x58, 0x8d, 0x4a, 0x7f, 0x09, 0x00, 0x96, 0x35, + 0xf2, 0x8b, 0xb9, 0x3d, 0x8c, 0x31, 0xf8, 0x70, + 0xec, 0x1e, 0x0b, 0xdb, 0x08, 0x2b, 0x66, 0xfa, + 0x40, 0x2d, 0xd9, 0xc2, 0x02, 0xbe, 0x30, 0x0c, + 0x45, 0x17, 0xd1, 0x96, 0xb1, 0x4d, 0x4c, 0xe1 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const uint8_t aria_test2_ctr_ct[3][48] = // CTR ciphertext +{ + { 0xac, 0x5d, 0x7d, 0xe8, 0x05, 0xa0, 0xbf, 0x1c, // 128-bit key + 0x57, 0xc8, 0x54, 0x50, 0x1a, 0xf6, 0x0f, 0xa1, + 0x14, 0x97, 0xe2, 0xa3, 0x45, 0x19, 0xde, 0xa1, + 0x56, 0x9e, 0x91, 0xe5, 0xb5, 0xcc, 0xae, 0x2f, + 0xf3, 0xbf, 0xa1, 0xbf, 0x97, 0x5f, 0x45, 0x71, + 0xf4, 0x8b, 0xe1, 0x91, 0x61, 0x35, 0x46, 0xc3 }, + { 0x08, 0x62, 0x5c, 0xa8, 0xfe, 0x56, 0x9c, 0x19, // 192-bit key + 0xba, 0x7a, 0xf3, 0x76, 0x0a, 0x6e, 0xd1, 0xce, + 0xf4, 0xd1, 0x99, 0x26, 0x3e, 0x99, 0x9d, 0xde, + 0x14, 0x08, 0x2d, 0xbb, 0xa7, 0x56, 0x0b, 0x79, + 0xa4, 0xc6, 0xb4, 0x56, 0xb8, 0x70, 0x7d, 0xce, + 0x75, 0x1f, 0x98, 0x54, 0xf1, 0x88, 0x93, 0xdf }, + { 0x30, 0x02, 0x6c, 0x32, 0x96, 0x66, 0x14, 0x17, // 256-bit key + 0x21, 0x17, 0x8b, 0x99, 0xc0, 0xa1, 0xf1, 0xb2, + 0xf0, 0x69, 0x40, 0x25, 0x3f, 0x7b, 0x30, 0x89, + 0xe2, 0xa3, 0x0e, 0xa8, 0x6a, 0xa3, 0xc8, 0x8f, + 0x59, 0x40, 0xf0, 0x5a, 0xd7, 0xee, 0x41, 0xd7, + 0x13, 0x47, 0xbb, 0x72, 0x61, 0xe3, 0x48, 0xf1 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#define ARIA_SELF_TEST_IF_FAIL \ + { \ + if( verbose ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } else { \ + if( verbose ) \ + mbedtls_printf( "passed\n" ); \ + } + +/* + * Checkup routine + */ +int mbedtls_aria_self_test( int verbose ) +{ + int i; + uint8_t blk[MBEDTLS_ARIA_BLOCKSIZE]; + mbedtls_aria_context ctx; + +#if (defined(MBEDTLS_CIPHER_MODE_CFB) || defined(MBEDTLS_CIPHER_MODE_CTR)) + size_t j; +#endif + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || \ + defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR)) + uint8_t buf[48], iv[MBEDTLS_ARIA_BLOCKSIZE]; +#endif + + /* + * Test set 1 + */ + for( i = 0; i < 3; i++ ) + { + /* test ECB encryption */ + if( verbose ) + mbedtls_printf( " ARIA-ECB-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test1_ecb_key, 128 + 64 * i ); + mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_pt, blk ); + if( memcmp( blk, aria_test1_ecb_ct[i], MBEDTLS_ARIA_BLOCKSIZE ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* test ECB decryption */ + if( verbose ) + mbedtls_printf( " ARIA-ECB-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_dec( &ctx, aria_test1_ecb_key, 128 + 64 * i ); + mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_ct[i], blk ); + if( memcmp( blk, aria_test1_ecb_pt, MBEDTLS_ARIA_BLOCKSIZE ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); + + /* + * Test set 2 + */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) + for( i = 0; i < 3; i++ ) + { + /* Test CBC encryption */ + if( verbose ) + mbedtls_printf( " ARIA-CBC-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0x55, sizeof( buf ) ); + mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, iv, + aria_test2_pt, buf ); + if( memcmp( buf, aria_test2_cbc_ct[i], 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* Test CBC decryption */ + if( verbose ) + mbedtls_printf( " ARIA-CBC-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_dec( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0xAA, sizeof( buf ) ); + mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_DECRYPT, 48, iv, + aria_test2_cbc_ct[i], buf ); + if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); + +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + for( i = 0; i < 3; i++ ) + { + /* Test CFB encryption */ + if( verbose ) + mbedtls_printf( " ARIA-CFB-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0x55, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, &j, iv, + aria_test2_pt, buf ); + if( memcmp( buf, aria_test2_cfb_ct[i], 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* Test CFB decryption */ + if( verbose ) + mbedtls_printf( " ARIA-CFB-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0xAA, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_DECRYPT, 48, &j, + iv, aria_test2_cfb_ct[i], buf ); + if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + for( i = 0; i < 3; i++ ) + { + /* Test CTR encryption */ + if( verbose ) + mbedtls_printf( " ARIA-CTR-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memset( iv, 0, MBEDTLS_ARIA_BLOCKSIZE ); // IV = 0 + memset( buf, 0x55, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk, + aria_test2_pt, buf ); + if( memcmp( buf, aria_test2_ctr_ct[i], 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* Test CTR decryption */ + if( verbose ) + mbedtls_printf( " ARIA-CTR-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memset( iv, 0, MBEDTLS_ARIA_BLOCKSIZE ); // IV = 0 + memset( buf, 0xAA, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk, + aria_test2_ctr_ct[i], buf ); + if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ARIA_C */ diff --git a/app/mbedtls/library/asn1parse.c b/app/mbedtls/library/asn1parse.c index 4dd65c03c0..171c340b8c 100644 --- a/app/mbedtls/library/asn1parse.c +++ b/app/mbedtls/library/asn1parse.c @@ -28,6 +28,7 @@ #if defined(MBEDTLS_ASN1_PARSE_C) #include "mbedtls/asn1.h" +#include "mbedtls/platform_util.h" #include @@ -43,11 +44,6 @@ #define mbedtls_free free #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} - /* * ASN.1 DER decoding routines */ @@ -313,7 +309,7 @@ int mbedtls_asn1_get_alg( unsigned char **p, if( *p == end ) { - mbedtls_zeroize( params, sizeof(mbedtls_asn1_buf) ); + mbedtls_platform_zeroize( params, sizeof(mbedtls_asn1_buf) ); return( 0 ); } @@ -358,7 +354,7 @@ void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur ) mbedtls_free( cur->oid.p ); mbedtls_free( cur->val.p ); - mbedtls_zeroize( cur, sizeof( mbedtls_asn1_named_data ) ); + mbedtls_platform_zeroize( cur, sizeof( mbedtls_asn1_named_data ) ); } void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ) diff --git a/app/mbedtls/library/asn1write.c b/app/mbedtls/library/asn1write.c index c13e85e56a..c0b4622d58 100644 --- a/app/mbedtls/library/asn1write.c +++ b/app/mbedtls/library/asn1write.c @@ -236,9 +236,6 @@ int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ) int ret; size_t len = 0; - // DER format assumes 2s complement for numbers, so the leftmost bit - // should be 0 for positive numbers and 1 for negative numbers. - // if( *p - start < 1 ) return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); @@ -260,56 +257,65 @@ int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ) return( (int) len ); } -int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, - const char *text, size_t text_len ) +int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, int tag, + const char *text, size_t text_len ) { int ret; size_t len = 0; MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, - (const unsigned char *) text, text_len ) ); + (const unsigned char *) text, text_len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_PRINTABLE_STRING ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) ); return( (int) len ); } -int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, - const char *text, size_t text_len ) +int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) { - int ret; - size_t len = 0; - - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, - (const unsigned char *) text, text_len ) ); + return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len) ); +} - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_IA5_STRING ) ); +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text, text_len) ); +} - return( (int) len ); +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) ); } int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, const unsigned char *buf, size_t bits ) { int ret; - size_t len = 0, size; + size_t len = 0; + size_t unused_bits, byte_len; - size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 ); + byte_len = ( bits + 7 ) / 8; + unused_bits = ( byte_len * 8 ) - bits; - // Calculate byte length - // - if( *p < start || (size_t)( *p - start ) < size + 1 ) + if( *p < start || (size_t)( *p - start ) < byte_len + 1 ) return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); - len = size + 1; - (*p) -= size; - memcpy( *p, buf, size ); + len = byte_len + 1; - // Write unused bits - // - *--(*p) = (unsigned char) (size * 8 - bits); + /* Write the bitstring. Ensure the unused bits are zeroed */ + if( byte_len > 0 ) + { + byte_len--; + *--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 ); + ( *p ) -= byte_len; + memcpy( *p, buf, byte_len ); + } + + /* Write unused bits */ + *--( *p ) = (unsigned char)unused_bits; MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); diff --git a/app/mbedtls/library/bignum.c b/app/mbedtls/library/bignum.c index ba817bebf5..7a700bc1ee 100644 --- a/app/mbedtls/library/bignum.c +++ b/app/mbedtls/library/bignum.c @@ -45,6 +45,7 @@ #include "mbedtls/bignum.h" #include "mbedtls/bn_mul.h" +#include "mbedtls/platform_util.h" #include @@ -58,15 +59,10 @@ #define mbedtls_free free #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) { - volatile mbedtls_mpi_uint *p = v; while( n-- ) *p++ = 0; -} - -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +#define MPI_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA ) +#define MPI_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) #define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ #define biL (ciL << 3) /* bits in limb */ @@ -81,13 +77,18 @@ static void mbedtls_zeroize( void *v, size_t n ) { #define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) #define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) +{ + mbedtls_platform_zeroize( v, ciL * n ); +} + /* * Initialize one MPI */ void mbedtls_mpi_init( mbedtls_mpi *X ) { - if( X == NULL ) - return; + MPI_VALIDATE( X != NULL ); X->s = 1; X->n = 0; @@ -119,6 +120,7 @@ void mbedtls_mpi_free( mbedtls_mpi *X ) int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ) { mbedtls_mpi_uint *p; + MPI_VALIDATE_RET( X != NULL ); if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); @@ -150,6 +152,10 @@ int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) { mbedtls_mpi_uint *p; size_t i; + MPI_VALIDATE_RET( X != NULL ); + + if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); /* Actually resize up in this case */ if( X->n <= nblimbs ) @@ -184,8 +190,10 @@ int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) */ int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) { - int ret; + int ret = 0; size_t i; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); if( X == Y ) return( 0 ); @@ -203,9 +211,15 @@ int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) X->s = Y->s; - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); + if( X->n < i ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); + } + else + { + memset( X->p + i, 0, ( X->n - i ) * ciL ); + } - memset( X->p, 0, X->n * ciL ); memcpy( X->p, Y->p, i * ciL ); cleanup: @@ -219,6 +233,8 @@ int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) { mbedtls_mpi T; + MPI_VALIDATE( X != NULL ); + MPI_VALIDATE( Y != NULL ); memcpy( &T, X, sizeof( mbedtls_mpi ) ); memcpy( X, Y, sizeof( mbedtls_mpi ) ); @@ -234,6 +250,8 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned { int ret = 0; size_t i; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); /* make sure assign is 0 or 1 in a time-constant manner */ assign = (assign | (unsigned char)-assign) >> 7; @@ -263,6 +281,8 @@ int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char sw int ret, s; size_t i; mbedtls_mpi_uint tmp; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); if( X == Y ) return( 0 ); @@ -295,6 +315,7 @@ int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char sw int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) { int ret; + MPI_VALIDATE_RET( X != NULL ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) ); memset( X->p, 0, X->n * ciL ); @@ -312,6 +333,8 @@ int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) */ int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ) { + MPI_VALIDATE_RET( X != NULL ); + if( X->n * biL <= pos ) return( 0 ); @@ -330,6 +353,7 @@ int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ) int ret = 0; size_t off = pos / biL; size_t idx = pos % biL; + MPI_VALIDATE_RET( X != NULL ); if( val != 0 && val != 1 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); @@ -356,6 +380,7 @@ int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ) size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ) { size_t i, j, count = 0; + MBEDTLS_INTERNAL_VALIDATE_RET( X != NULL, 0 ); for( i = 0; i < X->n; i++ ) for( j = 0; j < biL; j++, count++ ) @@ -436,6 +461,8 @@ int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ) size_t i, j, slen, n; mbedtls_mpi_uint d; mbedtls_mpi T; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( s != NULL ); if( radix < 2 || radix > 16 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); @@ -548,19 +575,27 @@ int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, size_t n; char *p; mbedtls_mpi T; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( olen != NULL ); + MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); if( radix < 2 || radix > 16 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); - n = mbedtls_mpi_bitlen( X ); - if( radix >= 4 ) n >>= 1; - if( radix >= 16 ) n >>= 1; - /* - * Round up the buffer length to an even value to ensure that there is - * enough room for hexadecimal values that can be represented in an odd - * number of digits. - */ - n += 3 + ( ( n + 1 ) & 1 ); + n = mbedtls_mpi_bitlen( X ); /* Number of bits necessary to present `n`. */ + if( radix >= 4 ) n >>= 1; /* Number of 4-adic digits necessary to present + * `n`. If radix > 4, this might be a strict + * overapproximation of the number of + * radix-adic digits needed to present `n`. */ + if( radix >= 16 ) n >>= 1; /* Number of hexadecimal digits necessary to + * present `n`. */ + + n += 1; /* Terminating null byte */ + n += 1; /* Compensate for the divisions above, which round down `n` + * in case it's not even. */ + n += 1; /* Potential '-'-sign. */ + n += ( n & 1 ); /* Make n even to have enough space for hexadecimal writing, + * which always uses an even number of hex-digits. */ if( buflen < n ) { @@ -572,7 +607,10 @@ int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, mbedtls_mpi_init( &T ); if( X->s == -1 ) + { *p++ = '-'; + buflen--; + } if( radix == 16 ) { @@ -629,6 +667,12 @@ int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ) */ char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( fin != NULL ); + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + memset( s, 0, sizeof( s ) ); if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); @@ -660,6 +704,10 @@ int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE * newline characters and '\0' */ char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + MPI_VALIDATE_RET( X != NULL ); + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); memset( s, 0, sizeof( s ) ); @@ -687,14 +735,109 @@ int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE } #endif /* MBEDTLS_FS_IO */ + +/* Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint + * into the storage form used by mbedtls_mpi. */ + +static mbedtls_mpi_uint mpi_uint_bigendian_to_host_c( mbedtls_mpi_uint x ) +{ + uint8_t i; + unsigned char *x_ptr; + mbedtls_mpi_uint tmp = 0; + + for( i = 0, x_ptr = (unsigned char*) &x; i < ciL; i++, x_ptr++ ) + { + tmp <<= CHAR_BIT; + tmp |= (mbedtls_mpi_uint) *x_ptr; + } + + return( tmp ); +} + +static mbedtls_mpi_uint mpi_uint_bigendian_to_host( mbedtls_mpi_uint x ) +{ +#if defined(__BYTE_ORDER__) + +/* Nothing to do on bigendian systems. */ +#if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ) + return( x ); +#endif /* __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */ + +#if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ) + +/* For GCC and Clang, have builtins for byte swapping. */ +#if defined(__GNUC__) && defined(__GNUC_PREREQ) +#if __GNUC_PREREQ(4,3) +#define have_bswap +#endif +#endif + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define have_bswap +#endif +#endif + +#if defined(have_bswap) + /* The compiler is hopefully able to statically evaluate this! */ + switch( sizeof(mbedtls_mpi_uint) ) + { + case 4: + return( __builtin_bswap32(x) ); + case 8: + return( __builtin_bswap64(x) ); + } +#endif +#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ +#endif /* __BYTE_ORDER__ */ + + /* Fall back to C-based reordering if we don't know the byte order + * or we couldn't use a compiler-specific builtin. */ + return( mpi_uint_bigendian_to_host_c( x ) ); +} + +static void mpi_bigendian_to_host( mbedtls_mpi_uint * const p, size_t limbs ) +{ + mbedtls_mpi_uint *cur_limb_left; + mbedtls_mpi_uint *cur_limb_right; + if( limbs == 0 ) + return; + + /* + * Traverse limbs and + * - adapt byte-order in each limb + * - swap the limbs themselves. + * For that, simultaneously traverse the limbs from left to right + * and from right to left, as long as the left index is not bigger + * than the right index (it's not a problem if limbs is odd and the + * indices coincide in the last iteration). + */ + for( cur_limb_left = p, cur_limb_right = p + ( limbs - 1 ); + cur_limb_left <= cur_limb_right; + cur_limb_left++, cur_limb_right-- ) + { + mbedtls_mpi_uint tmp; + /* Note that if cur_limb_left == cur_limb_right, + * this code effectively swaps the bytes only once. */ + tmp = mpi_uint_bigendian_to_host( *cur_limb_left ); + *cur_limb_left = mpi_uint_bigendian_to_host( *cur_limb_right ); + *cur_limb_right = tmp; + } +} + /* * Import X from unsigned binary data, big endian */ int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ) { int ret; - size_t i, j; - size_t const limbs = CHARS_TO_LIMBS( buflen ); + size_t const limbs = CHARS_TO_LIMBS( buflen ); + size_t const overhead = ( limbs * ciL ) - buflen; + unsigned char *Xp; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); /* Ensure that target MPI has exactly the necessary number of limbs */ if( X->n != limbs ) @@ -703,11 +846,17 @@ int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t bu mbedtls_mpi_init( X ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); } - MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); - for( i = buflen, j = 0; i > 0; i--, j++ ) - X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3); + /* Avoid calling `memcpy` with NULL source argument, + * even if buflen is 0. */ + if( buf != NULL ) + { + Xp = (unsigned char*) X->p; + memcpy( Xp + overhead, buf, buflen ); + + mpi_bigendian_to_host( X->p, limbs ); + } cleanup: @@ -720,11 +869,16 @@ int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t bu int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ) { - size_t stored_bytes = X->n * ciL; + size_t stored_bytes; size_t bytes_to_copy; unsigned char *p; size_t i; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); + + stored_bytes = X->n * ciL; + if( stored_bytes < buflen ) { /* There is enough space in the output buffer. Write initial @@ -763,6 +917,7 @@ int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ) int ret; size_t i, v0, t1; mbedtls_mpi_uint r0 = 0, r1; + MPI_VALIDATE_RET( X != NULL ); v0 = count / (biL ); t1 = count & (biL - 1); @@ -812,6 +967,7 @@ int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ) { size_t i, v0, v1; mbedtls_mpi_uint r0 = 0, r1; + MPI_VALIDATE_RET( X != NULL ); v0 = count / biL; v1 = count & (biL - 1); @@ -854,6 +1010,8 @@ int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ) int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ) { size_t i, j; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); for( i = X->n; i > 0; i-- ) if( X->p[i - 1] != 0 ) @@ -884,6 +1042,8 @@ int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ) int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) { size_t i, j; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); for( i = X->n; i > 0; i-- ) if( X->p[i - 1] != 0 ) @@ -918,6 +1078,7 @@ int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ) { mbedtls_mpi Y; mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); *p = ( z < 0 ) ? -z : z; Y.s = ( z < 0 ) ? -1 : 1; @@ -935,6 +1096,9 @@ int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi int ret; size_t i, j; mbedtls_mpi_uint *o, *p, c, tmp; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); if( X == B ) { @@ -1000,7 +1164,7 @@ static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d ) while( c != 0 ) { z = ( *d < c ); *d -= c; - c = z; i++; d++; + c = z; d++; } } @@ -1012,6 +1176,9 @@ int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi mbedtls_mpi TB; int ret; size_t n; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); @@ -1052,8 +1219,12 @@ int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi */ int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) { - int ret, s = A->s; + int ret, s; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + s = A->s; if( A->s * B->s < 0 ) { if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) @@ -1083,8 +1254,12 @@ int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi */ int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) { - int ret, s = A->s; + int ret, s; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + s = A->s; if( A->s * B->s > 0 ) { if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) @@ -1116,6 +1291,8 @@ int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint { mbedtls_mpi _B; mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); p[0] = ( b < 0 ) ? -b : b; _B.s = ( b < 0 ) ? -1 : 1; @@ -1132,6 +1309,8 @@ int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint { mbedtls_mpi _B; mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); p[0] = ( b < 0 ) ? -b : b; _B.s = ( b < 0 ) ? -1 : 1; @@ -1221,6 +1400,9 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi int ret; size_t i, j; mbedtls_mpi TA, TB; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); @@ -1238,8 +1420,8 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); - for( i++; j > 0; j-- ) - mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + for( ; j > 0; j-- ) + mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] ); X->s = A->s * B->s; @@ -1257,6 +1439,8 @@ int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint { mbedtls_mpi _B; mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); _B.s = 1; _B.n = 1; @@ -1365,11 +1549,14 @@ static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1, /* * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) */ -int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B ) { int ret; size_t i, n, t, k; mbedtls_mpi X, Y, Z, T1, T2; + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); if( mbedtls_mpi_cmp_int( B, 0 ) == 0 ) return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); @@ -1480,10 +1667,13 @@ int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, c /* * Division by int: A = Q * b + R */ -int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, + const mbedtls_mpi *A, + mbedtls_mpi_sint b ) { mbedtls_mpi _B; mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( A != NULL ); p[0] = ( b < 0 ) ? -b : b; _B.s = ( b < 0 ) ? -1 : 1; @@ -1499,6 +1689,9 @@ int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, m int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) { int ret; + MPI_VALIDATE_RET( R != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); if( mbedtls_mpi_cmp_int( B, 0 ) < 0 ) return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); @@ -1523,6 +1716,8 @@ int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_ { size_t i; mbedtls_mpi_uint x, y, z; + MPI_VALIDATE_RET( r != NULL ); + MPI_VALIDATE_RET( A != NULL ); if( b == 0 ) return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); @@ -1636,7 +1831,8 @@ static int mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi /* * Montgomery reduction: A = A * R^-1 mod N */ -static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T ) +static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, + mbedtls_mpi_uint mm, const mbedtls_mpi *T ) { mbedtls_mpi_uint z = 1; mbedtls_mpi U; @@ -1650,7 +1846,9 @@ static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint m /* * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) */ -int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ) +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *_RR ) { int ret; size_t wbits, wsize, one = 1; @@ -1660,6 +1858,11 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos; int neg; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( E != NULL ); + MPI_VALIDATE_RET( N != NULL ); + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); @@ -1679,8 +1882,10 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; +#if( MBEDTLS_MPI_WINDOW_SIZE < 6 ) if( wsize > MBEDTLS_MPI_WINDOW_SIZE ) wsize = MBEDTLS_MPI_WINDOW_SIZE; +#endif j = N->n + 1; MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); @@ -1864,6 +2069,10 @@ int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B size_t lz, lzt; mbedtls_mpi TG, TA, TB; + MPI_VALIDATE_RET( G != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); @@ -1919,16 +2128,28 @@ int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, void *p_rng ) { int ret; - unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + size_t const limbs = CHARS_TO_LIMBS( size ); + size_t const overhead = ( limbs * ciL ) - size; + unsigned char *Xp; - if( size > MBEDTLS_MPI_MAX_SIZE ) - return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); - MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); + /* Ensure that target MPI has exactly the necessary number of limbs */ + if( X->n != limbs ) + { + mbedtls_mpi_free( X ); + mbedtls_mpi_init( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); + } + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + Xp = (unsigned char*) X->p; + f_rng( p_rng, Xp + overhead, size ); + + mpi_bigendian_to_host( X->p, limbs ); cleanup: - mbedtls_zeroize( buf, sizeof( buf ) ); return( ret ); } @@ -1939,6 +2160,9 @@ int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi { int ret; mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( N != NULL ); if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); @@ -2098,7 +2322,11 @@ static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, size_t i, j, k, s; mbedtls_mpi W, R, T, A, RR; - mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A ); + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + + mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); + mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A ); mbedtls_mpi_init( &RR ); /* @@ -2110,8 +2338,6 @@ static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) ); - i = mbedtls_mpi_bitlen( X ); - for( i = 0; i < rounds; i++ ) { /* @@ -2128,7 +2354,8 @@ static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, } if (count++ > 30) { - return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; } } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 || @@ -2170,7 +2397,8 @@ static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, } cleanup: - mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A ); + mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); + mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A ); mbedtls_mpi_free( &RR ); return( ret ); @@ -2179,12 +2407,14 @@ static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, /* * Pseudo-primality test: small factors, then Miller-Rabin */ -static int mpi_is_prime_internal( const mbedtls_mpi *X, int rounds, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; mbedtls_mpi XX; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); XX.s = 1; XX.n = X->n; @@ -2208,6 +2438,7 @@ static int mpi_is_prime_internal( const mbedtls_mpi *X, int rounds, return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) ); } +#if !defined(MBEDTLS_DEPRECATED_REMOVED) /* * Pseudo-primality test, error probability 2^-80 */ @@ -2215,22 +2446,45 @@ int mbedtls_mpi_is_prime( const mbedtls_mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - return mpi_is_prime_internal( X, 40, f_rng, p_rng ); + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + + /* + * In the past our key generation aimed for an error rate of at most + * 2^-80. Since this function is deprecated, aim for the same certainty + * here as well. + */ + return( mbedtls_mpi_is_prime_ext( X, 40, f_rng, p_rng ) ); } +#endif /* * Prime number generation + * + * To generate an RSA key in a way recommended by FIPS 186-4, both primes must + * be either 1024 bits or 1536 bits long, and flags must contain + * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR. */ -int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - int ret; +#ifdef MBEDTLS_HAVE_INT64 +// ceil(2^63.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL +#else +// ceil(2^31.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U +#endif + int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; size_t k, n; int rounds; mbedtls_mpi_uint r; mbedtls_mpi Y; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); @@ -2238,78 +2492,89 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, n = BITS_TO_LIMBS( nbits ); - /* - * 2^-80 error probability, number of rounds chosen per HAC, table 4.4 - */ - rounds = ( ( nbits >= 1300 ) ? 2 : ( nbits >= 850 ) ? 3 : - ( nbits >= 650 ) ? 4 : ( nbits >= 350 ) ? 8 : - ( nbits >= 250 ) ? 12 : ( nbits >= 150 ) ? 18 : 27 ); - - MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); - - k = mbedtls_mpi_bitlen( X ); - if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) ); - - mbedtls_mpi_set_bit( X, nbits-1, 1 ); - - X->p[0] |= 1; - - if( dh_flag == 0 ) + if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR ) == 0 ) { - while( ( ret = mpi_is_prime_internal( X, rounds, f_rng, p_rng ) ) != 0 ) - { - if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; - - MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) ); - } + /* + * 2^-80 error probability, number of rounds chosen per HAC, table 4.4 + */ + rounds = ( ( nbits >= 1300 ) ? 2 : ( nbits >= 850 ) ? 3 : + ( nbits >= 650 ) ? 4 : ( nbits >= 350 ) ? 8 : + ( nbits >= 250 ) ? 12 : ( nbits >= 150 ) ? 18 : 27 ); } else { /* - * An necessary condition for Y and X = 2Y + 1 to be prime - * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). - * Make sure it is satisfied, while keeping X = 3 mod 4 + * 2^-100 error probability, number of rounds computed based on HAC, + * fact 4.48 */ + rounds = ( ( nbits >= 1450 ) ? 4 : ( nbits >= 1150 ) ? 5 : + ( nbits >= 1000 ) ? 6 : ( nbits >= 850 ) ? 7 : + ( nbits >= 750 ) ? 8 : ( nbits >= 500 ) ? 13 : + ( nbits >= 250 ) ? 28 : ( nbits >= 150 ) ? 40 : 51 ); + } - X->p[0] |= 2; - - MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) ); - if( r == 0 ) - MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) ); - else if( r == 1 ) - MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) ); + while( 1 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */ + if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue; - /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ - MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) ); + k = n * biL; + if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) ); + X->p[0] |= 1; - while( 1 ) + if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH ) == 0 ) { - /* - * First, check small factors for X and Y - * before doing Miller-Rabin on any of them - */ - if( ( ret = mpi_check_small_factors( X ) ) == 0 && - ( ret = mpi_check_small_factors( &Y ) ) == 0 && - ( ret = mpi_miller_rabin( X, rounds, f_rng, p_rng ) ) - == 0 && - ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng ) ) - == 0 ) - { - break; - } + ret = mbedtls_mpi_is_prime_ext( X, rounds, f_rng, p_rng ); if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) goto cleanup; - + } + else + { /* - * Next candidates. We want to preserve Y = (X-1) / 2 and - * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) - * so up Y by 6 and X by 12. + * An necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 */ - MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) ); + + X->p[0] |= 2; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) ); + if( r == 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) ); + else if( r == 1 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) ); + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if( ( ret = mpi_check_small_factors( X ) ) == 0 && + ( ret = mpi_check_small_factors( &Y ) ) == 0 && + ( ret = mpi_miller_rabin( X, rounds, f_rng, p_rng ) ) + == 0 && + ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng ) ) + == 0 ) + goto cleanup; + + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + /* + * Next candidates. We want to preserve Y = (X-1) / 2 and + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) ); + } } } diff --git a/app/mbedtls/library/blowfish.c b/app/mbedtls/library/blowfish.c index 9003f0dfeb..cbf9238246 100644 --- a/app/mbedtls/library/blowfish.c +++ b/app/mbedtls/library/blowfish.c @@ -34,15 +34,17 @@ #if defined(MBEDTLS_BLOWFISH_C) #include "mbedtls/blowfish.h" +#include "mbedtls/platform_util.h" #include #if !defined(MBEDTLS_BLOWFISH_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} +/* Parameter validation macros */ +#define BLOWFISH_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ) +#define BLOWFISH_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) /* * 32-bit integer manipulation macros (big endian) @@ -157,6 +159,7 @@ static void blowfish_dec( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ) { + BLOWFISH_VALIDATE( ctx != NULL ); memset( ctx, 0, sizeof( mbedtls_blowfish_context ) ); } @@ -165,22 +168,26 @@ void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_blowfish_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_blowfish_context ) ); } /* * Blowfish key schedule */ -int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, - unsigned int keybits ) +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, + const unsigned char *key, + unsigned int keybits ) { unsigned int i, j, k; uint32_t data, datal, datar; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( key != NULL ); - if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS || - ( keybits % 8 ) ) + if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || + keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS || + keybits % 8 != 0 ) { - return( MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH ); + return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ); } keybits >>= 3; @@ -235,6 +242,11 @@ int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ) { uint32_t X0, X1; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT || + mode == MBEDTLS_BLOWFISH_DECRYPT ); + BLOWFISH_VALIDATE_RET( input != NULL ); + BLOWFISH_VALIDATE_RET( output != NULL ); GET_UINT32_BE( X0, input, 0 ); GET_UINT32_BE( X1, input, 4 ); @@ -267,6 +279,12 @@ int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, { int i; unsigned char temp[MBEDTLS_BLOWFISH_BLOCKSIZE]; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT || + mode == MBEDTLS_BLOWFISH_DECRYPT ); + BLOWFISH_VALIDATE_RET( iv != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || input != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || output != NULL ); if( length % MBEDTLS_BLOWFISH_BLOCKSIZE ) return( MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH ); @@ -321,7 +339,19 @@ int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, unsigned char *output ) { int c; - size_t n = *iv_off; + size_t n; + + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT || + mode == MBEDTLS_BLOWFISH_DECRYPT ); + BLOWFISH_VALIDATE_RET( iv != NULL ); + BLOWFISH_VALIDATE_RET( iv_off != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || input != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || output != NULL ); + + n = *iv_off; + if( n >= 8 ) + return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ); if( mode == MBEDTLS_BLOWFISH_DECRYPT ) { @@ -369,7 +399,17 @@ int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, unsigned char *output ) { int c, i; - size_t n = *nc_off; + size_t n; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( nonce_counter != NULL ); + BLOWFISH_VALIDATE_RET( stream_block != NULL ); + BLOWFISH_VALIDATE_RET( nc_off != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || input != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || output != NULL ); + + n = *nc_off; + if( n >= 8 ) + return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ); while( length-- ) { diff --git a/app/mbedtls/library/camellia.c b/app/mbedtls/library/camellia.c index ac6f96a83a..22262b89a8 100644 --- a/app/mbedtls/library/camellia.c +++ b/app/mbedtls/library/camellia.c @@ -34,6 +34,7 @@ #if defined(MBEDTLS_CAMELLIA_C) #include "mbedtls/camellia.h" +#include "mbedtls/platform_util.h" #include @@ -48,10 +49,11 @@ #if !defined(MBEDTLS_CAMELLIA_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} +/* Parameter validation macros */ +#define CAMELLIA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ) +#define CAMELLIA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) /* * 32-bit integer manipulation macros (big endian) @@ -325,6 +327,7 @@ static void camellia_feistel( const uint32_t x[2], const uint32_t k[2], void mbedtls_camellia_init( mbedtls_camellia_context *ctx ) { + CAMELLIA_VALIDATE( ctx != NULL ); memset( ctx, 0, sizeof( mbedtls_camellia_context ) ); } @@ -333,14 +336,15 @@ void mbedtls_camellia_free( mbedtls_camellia_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_camellia_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_camellia_context ) ); } /* * Camellia key schedule (encryption) */ -int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, - unsigned int keybits ) +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ) { int idx; size_t i; @@ -350,6 +354,9 @@ int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned c uint32_t KC[16]; uint32_t TK[20]; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( key != NULL ); + RK = ctx->rk; memset( t, 0, 64 ); @@ -360,7 +367,7 @@ int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned c case 128: ctx->nr = 3; idx = 0; break; case 192: case 256: ctx->nr = 4; idx = 1; break; - default : return( MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH ); + default : return( MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ); } for( i = 0; i < keybits / 8; ++i ) @@ -444,14 +451,17 @@ int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned c /* * Camellia key schedule (decryption) */ -int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, - unsigned int keybits ) +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ) { int idx, ret; size_t i; mbedtls_camellia_context cty; uint32_t *RK; uint32_t *SK; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( key != NULL ); mbedtls_camellia_init( &cty ); @@ -499,6 +509,11 @@ int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, { int NR; uint32_t *RK, X[4]; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( mode == MBEDTLS_CAMELLIA_ENCRYPT || + mode == MBEDTLS_CAMELLIA_DECRYPT ); + CAMELLIA_VALIDATE_RET( input != NULL ); + CAMELLIA_VALIDATE_RET( output != NULL ); ( (void) mode ); @@ -556,14 +571,20 @@ int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, * Camellia-CBC buffer encryption/decryption */ int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) { int i; unsigned char temp[16]; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( mode == MBEDTLS_CAMELLIA_ENCRYPT || + mode == MBEDTLS_CAMELLIA_DECRYPT ); + CAMELLIA_VALIDATE_RET( iv != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || input != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || output != NULL ); if( length % 16 ) return( MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH ); @@ -618,7 +639,18 @@ int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, unsigned char *output ) { int c; - size_t n = *iv_off; + size_t n; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( mode == MBEDTLS_CAMELLIA_ENCRYPT || + mode == MBEDTLS_CAMELLIA_DECRYPT ); + CAMELLIA_VALIDATE_RET( iv != NULL ); + CAMELLIA_VALIDATE_RET( iv_off != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || input != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || output != NULL ); + + n = *iv_off; + if( n >= 16 ) + return( MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ); if( mode == MBEDTLS_CAMELLIA_DECRYPT ) { @@ -666,7 +698,17 @@ int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, unsigned char *output ) { int c, i; - size_t n = *nc_off; + size_t n; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( nonce_counter != NULL ); + CAMELLIA_VALIDATE_RET( stream_block != NULL ); + CAMELLIA_VALIDATE_RET( nc_off != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || input != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || output != NULL ); + + n = *nc_off; + if( n >= 16 ) + return( MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ); while( length-- ) { diff --git a/app/mbedtls/library/ccm.c b/app/mbedtls/library/ccm.c index 658f0d2ff3..c6211ee773 100644 --- a/app/mbedtls/library/ccm.c +++ b/app/mbedtls/library/ccm.c @@ -37,6 +37,7 @@ #if defined(MBEDTLS_CCM_C) #include "mbedtls/ccm.h" +#include "mbedtls/platform_util.h" #include @@ -51,10 +52,10 @@ #if !defined(MBEDTLS_CCM_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} +#define CCM_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CCM_BAD_INPUT ) +#define CCM_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) #define CCM_ENCRYPT 0 #define CCM_DECRYPT 1 @@ -64,6 +65,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { */ void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) { + CCM_VALIDATE( ctx != NULL ); memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); } @@ -75,6 +77,9 @@ int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, int ret; const mbedtls_cipher_info_t *cipher_info; + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( key != NULL ); + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); if( cipher_info == NULL ) return( MBEDTLS_ERR_CCM_BAD_INPUT ); @@ -101,8 +106,10 @@ int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, */ void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) { + if( ctx == NULL ) + return; mbedtls_cipher_free( &ctx->cipher_ctx ); - mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); } /* @@ -127,11 +134,17 @@ void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) * This avoids allocating one more 16 bytes buffer while allowing src == dst. */ #define CTR_CRYPT( dst, src, len ) \ - if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \ - return( ret ); \ - \ - for( i = 0; i < len; i++ ) \ - dst[i] = src[i] ^ b[i]; + do \ + { \ + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, \ + 16, b, &olen ) ) != 0 ) \ + { \ + return( ret ); \ + } \ + \ + for( i = 0; i < (len); i++ ) \ + (dst)[i] = (src)[i] ^ b[i]; \ + } while( 0 ) /* * Authenticated encryption or decryption @@ -156,8 +169,10 @@ static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, * Check length requirements: SP800-38C A.1 * Additional requirement: a < 2^16 - 2^8 to simplify the code. * 'length' checked later (when writing it to the first block) + * + * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4). */ - if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 ) + if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 ) return( MBEDTLS_ERR_CCM_BAD_INPUT ); /* Also implies q is within bounds */ @@ -306,20 +321,45 @@ static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, /* * Authenticated encryption */ -int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, +int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, unsigned char *tag, size_t tag_len ) { + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, add, add_len, input, output, tag, tag_len ) ); } +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); + if( tag_len == 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add, + add_len, input, output, tag, tag_len ) ); +} + /* * Authenticated decryption */ -int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, +int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, @@ -330,6 +370,13 @@ int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, unsigned char i; int diff; + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); + if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, iv, iv_len, add, add_len, input, output, check_tag, tag_len ) ) != 0 ) @@ -343,13 +390,32 @@ int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, if( diff != 0 ) { - mbedtls_zeroize( output, length ); + mbedtls_platform_zeroize( output, length ); return( MBEDTLS_ERR_CCM_AUTH_FAILED ); } return( 0 ); } +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ) +{ + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); + + if( tag_len == 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + return( mbedtls_ccm_star_auth_decrypt( ctx, length, iv, iv_len, add, + add_len, input, output, tag, tag_len ) ); +} #endif /* !MBEDTLS_CCM_ALT */ #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) diff --git a/app/mbedtls/library/certs.c b/app/mbedtls/library/certs.c index f1379b8cb1..80ab0b9d6c 100644 --- a/app/mbedtls/library/certs.c +++ b/app/mbedtls/library/certs.c @@ -29,325 +29,1658 @@ #if defined(MBEDTLS_CERTS_C) -#if defined(MBEDTLS_ECDSA_C) -#define TEST_CA_CRT_EC \ -"-----BEGIN CERTIFICATE-----\r\n" \ -"MIICUjCCAdegAwIBAgIJAMFD4n5iQ8zoMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT\r\n" \ -"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ -"QyBDQTAeFw0xMzA5MjQxNTQ5NDhaFw0yMzA5MjIxNTQ5NDhaMD4xCzAJBgNVBAYT\r\n" \ -"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ -"QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu\r\n" \ -"ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy\r\n" \ -"aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqOBoDCBnTAdBgNVHQ4EFgQUnW0g\r\n" \ -"JEkBPyvLeLUZvH4kydv7NnwwbgYDVR0jBGcwZYAUnW0gJEkBPyvLeLUZvH4kydv7\r\n" \ -"NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UE\r\n" \ -"AxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAwGA1UdEwQFMAMBAf8w\r\n" \ -"CgYIKoZIzj0EAwIDaQAwZgIxAMO0YnNWKJUAfXgSJtJxexn4ipg+kv4znuR50v56\r\n" \ -"t4d0PCu412mUC6Nnd7izvtE2MgIxAP1nnJQjZ8BWukszFQDG48wxCCyci9qpdSMv\r\n" \ -"uCjn8pwUOkABXK8Mss90fzCfCEOtIA==\r\n" \ -"-----END CERTIFICATE-----\r\n" -const char mbedtls_test_ca_crt_ec[] = TEST_CA_CRT_EC; -const size_t mbedtls_test_ca_crt_ec_len = sizeof( mbedtls_test_ca_crt_ec ); - -const char mbedtls_test_ca_key_ec[] = -"-----BEGIN EC PRIVATE KEY-----\r\n" -"Proc-Type: 4,ENCRYPTED\r\n" -"DEK-Info: DES-EDE3-CBC,307EAB469933D64E\r\n" -"\r\n" -"IxbrRmKcAzctJqPdTQLA4SWyBYYGYJVkYEna+F7Pa5t5Yg/gKADrFKcm6B72e7DG\r\n" -"ihExtZI648s0zdYw6qSJ74vrPSuWDe5qm93BqsfVH9svtCzWHW0pm1p0KTBCFfUq\r\n" -"UsuWTITwJImcnlAs1gaRZ3sAWm7cOUidL0fo2G0fYUFNcYoCSLffCFTEHBuPnagb\r\n" -"a77x/sY1Bvii8S9/XhDTb6pTMx06wzrm\r\n" -"-----END EC PRIVATE KEY-----\r\n"; -const size_t mbedtls_test_ca_key_ec_len = sizeof( mbedtls_test_ca_key_ec ); - -const char mbedtls_test_ca_pwd_ec[] = "PolarSSLTest"; -const size_t mbedtls_test_ca_pwd_ec_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; - -const char mbedtls_test_srv_crt_ec[] = -"-----BEGIN CERTIFICATE-----\r\n" -"MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" -"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" -"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" -"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\r\n" -"CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\r\n" -"2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\r\n" -"BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\r\n" -"PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\r\n" -"clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\r\n" -"CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\r\n" -"C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\r\n" -"fGa5kHvHARBPc8YAIVIqDvHH1Q==\r\n" -"-----END CERTIFICATE-----\r\n"; -const size_t mbedtls_test_srv_crt_ec_len = sizeof( mbedtls_test_srv_crt_ec ); - -const char mbedtls_test_srv_key_ec[] = -"-----BEGIN EC PRIVATE KEY-----\r\n" -"MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n" -"AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\r\n" -"6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\r\n" -"-----END EC PRIVATE KEY-----\r\n"; -const size_t mbedtls_test_srv_key_ec_len = sizeof( mbedtls_test_srv_key_ec ); - -const char mbedtls_test_cli_crt_ec[] = -"-----BEGIN CERTIFICATE-----\r\n" -"MIICLDCCAbKgAwIBAgIBDTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" -"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" -"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjBBMQswCQYDVQQGEwJOTDERMA8G\r\n" -"A1UEChMIUG9sYXJTU0wxHzAdBgNVBAMTFlBvbGFyU1NMIFRlc3QgQ2xpZW50IDIw\r\n" -"WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARX5a6xc9/TrLuTuIH/Eq7u5lOszlVT\r\n" -"9jQOzC7jYyUL35ji81xgNpbA1RgUcOV/n9VLRRjlsGzVXPiWj4dwo+THo4GdMIGa\r\n" -"MAkGA1UdEwQCMAAwHQYDVR0OBBYEFHoAX4Zk/OBd5REQO7LmO8QmP8/iMG4GA1Ud\r\n" -"IwRnMGWAFJ1tICRJAT8ry3i1Gbx+JMnb+zZ8oUKkQDA+MQswCQYDVQQGEwJOTDER\r\n" -"MA8GA1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0GC\r\n" -"CQDBQ+J+YkPM6DAKBggqhkjOPQQDAgNoADBlAjBKZQ17IIOimbmoD/yN7o89u3BM\r\n" -"lgOsjnhw3fIOoLIWy2WOGsk/LGF++DzvrRzuNiACMQCd8iem1XS4JK7haj8xocpU\r\n" -"LwjQje5PDGHfd3h9tP38Qknu5bJqws0md2KOKHyeV0U=\r\n" -"-----END CERTIFICATE-----\r\n"; -const size_t mbedtls_test_cli_crt_ec_len = sizeof( mbedtls_test_cli_crt_ec ); - -const char mbedtls_test_cli_key_ec[] = -"-----BEGIN EC PRIVATE KEY-----\r\n" -"MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n" -"AwEHoUQDQgAEV+WusXPf06y7k7iB/xKu7uZTrM5VU/Y0Dswu42MlC9+Y4vNcYDaW\r\n" -"wNUYFHDlf5/VS0UY5bBs1Vz4lo+HcKPkxw==\r\n" -"-----END EC PRIVATE KEY-----\r\n"; -const size_t mbedtls_test_cli_key_ec_len = sizeof( mbedtls_test_cli_key_ec ); -#endif /* MBEDTLS_ECDSA_C */ +/* + * Test CA Certificates + * + * We define test CA certificates for each choice of the following parameters: + * - PEM or DER encoding + * - SHA-1 or SHA-256 hash + * - RSA or EC key + * + * Things to add: + * - multiple EC curve types + * + */ -#if defined(MBEDTLS_RSA_C) +/* This is taken from tests/data_files/test-ca2.crt */ +/* BEGIN FILE string macro TEST_CA_CRT_EC_PEM tests/data_files/test-ca2.crt */ +#define TEST_CA_CRT_EC_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIICBDCCAYigAwIBAgIJAMFD4n5iQ8zoMAwGCCqGSM49BAMCBQAwPjELMAkGA1UE\r\n" \ + "BhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xhcnNzbCBUZXN0\r\n" \ + "IEVDIENBMB4XDTE5MDIxMDE0NDQwMFoXDTI5MDIxMDE0NDQwMFowPjELMAkGA1UE\r\n" \ + "BhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xhcnNzbCBUZXN0\r\n" \ + "IEVDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEw9orNEE3WC+HVv78ibopQ0tO\r\n" \ + "4G7DDldTMzlY1FK0kZU5CyPfXxckYkj8GpUpziwth8KIUoCv1mqrId240xxuWLjK\r\n" \ + "6LJpjvNBrSnDtF91p0dv1RkpVWmaUzsgtGYWYDMeo1AwTjAMBgNVHRMEBTADAQH/\r\n" \ + "MB0GA1UdDgQWBBSdbSAkSQE/K8t4tRm8fiTJ2/s2fDAfBgNVHSMEGDAWgBSdbSAk\r\n" \ + "SQE/K8t4tRm8fiTJ2/s2fDAMBggqhkjOPQQDAgUAA2gAMGUCMFHKrjAPpHB0BN1a\r\n" \ + "LH8TwcJ3vh0AxeKZj30mRdOKBmg/jLS3rU3g8VQBHpn8sOTTBwIxANxPO5AerimZ\r\n" \ + "hCjMe0d4CTHf1gFZMF70+IqEP+o5VHsIp2Cqvflb0VGWFC5l9a4cQg==\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This is generated from tests/data_files/test-ca2.crt.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_CA_CRT_EC_DER tests/data_files/test-ca2.crt.der */ +#define TEST_CA_CRT_EC_DER { \ + 0x30, 0x82, 0x02, 0x04, 0x30, 0x82, 0x01, 0x88, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x09, 0x00, 0xc1, 0x43, 0xe2, 0x7e, 0x62, 0x43, 0xcc, 0xe8, \ + 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, \ + 0x05, 0x00, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, \ + 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, \ + 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, \ + 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x50, \ + 0x6f, 0x6c, 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, \ + 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, \ + 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, 0x30, 0x30, 0x5a, 0x17, \ + 0x0d, 0x32, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, 0x30, \ + 0x30, 0x5a, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, \ + 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, \ + 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, \ + 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x50, \ + 0x6f, 0x6c, 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, \ + 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, \ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, \ + 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xc3, 0xda, 0x2b, 0x34, 0x41, 0x37, \ + 0x58, 0x2f, 0x87, 0x56, 0xfe, 0xfc, 0x89, 0xba, 0x29, 0x43, 0x4b, 0x4e, \ + 0xe0, 0x6e, 0xc3, 0x0e, 0x57, 0x53, 0x33, 0x39, 0x58, 0xd4, 0x52, 0xb4, \ + 0x91, 0x95, 0x39, 0x0b, 0x23, 0xdf, 0x5f, 0x17, 0x24, 0x62, 0x48, 0xfc, \ + 0x1a, 0x95, 0x29, 0xce, 0x2c, 0x2d, 0x87, 0xc2, 0x88, 0x52, 0x80, 0xaf, \ + 0xd6, 0x6a, 0xab, 0x21, 0xdd, 0xb8, 0xd3, 0x1c, 0x6e, 0x58, 0xb8, 0xca, \ + 0xe8, 0xb2, 0x69, 0x8e, 0xf3, 0x41, 0xad, 0x29, 0xc3, 0xb4, 0x5f, 0x75, \ + 0xa7, 0x47, 0x6f, 0xd5, 0x19, 0x29, 0x55, 0x69, 0x9a, 0x53, 0x3b, 0x20, \ + 0xb4, 0x66, 0x16, 0x60, 0x33, 0x1e, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x0c, \ + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, \ + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9d, \ + 0x6d, 0x20, 0x24, 0x49, 0x01, 0x3f, 0x2b, 0xcb, 0x78, 0xb5, 0x19, 0xbc, \ + 0x7e, 0x24, 0xc9, 0xdb, 0xfb, 0x36, 0x7c, 0x30, 0x1f, 0x06, 0x03, 0x55, \ + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x9d, 0x6d, 0x20, 0x24, \ + 0x49, 0x01, 0x3f, 0x2b, 0xcb, 0x78, 0xb5, 0x19, 0xbc, 0x7e, 0x24, 0xc9, \ + 0xdb, 0xfb, 0x36, 0x7c, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, \ + 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, \ + 0x30, 0x51, 0xca, 0xae, 0x30, 0x0f, 0xa4, 0x70, 0x74, 0x04, 0xdd, 0x5a, \ + 0x2c, 0x7f, 0x13, 0xc1, 0xc2, 0x77, 0xbe, 0x1d, 0x00, 0xc5, 0xe2, 0x99, \ + 0x8f, 0x7d, 0x26, 0x45, 0xd3, 0x8a, 0x06, 0x68, 0x3f, 0x8c, 0xb4, 0xb7, \ + 0xad, 0x4d, 0xe0, 0xf1, 0x54, 0x01, 0x1e, 0x99, 0xfc, 0xb0, 0xe4, 0xd3, \ + 0x07, 0x02, 0x31, 0x00, 0xdc, 0x4f, 0x3b, 0x90, 0x1e, 0xae, 0x29, 0x99, \ + 0x84, 0x28, 0xcc, 0x7b, 0x47, 0x78, 0x09, 0x31, 0xdf, 0xd6, 0x01, 0x59, \ + 0x30, 0x5e, 0xf4, 0xf8, 0x8a, 0x84, 0x3f, 0xea, 0x39, 0x54, 0x7b, 0x08, \ + 0xa7, 0x60, 0xaa, 0xbd, 0xf9, 0x5b, 0xd1, 0x51, 0x96, 0x14, 0x2e, 0x65, \ + 0xf5, 0xae, 0x1c, 0x42 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/test-ca2.key.enc */ +/* BEGIN FILE string macro TEST_CA_KEY_EC_PEM tests/data_files/test-ca2.key.enc */ +#define TEST_CA_KEY_EC_PEM \ + "-----BEGIN EC PRIVATE KEY-----\r\n" \ + "Proc-Type: 4,ENCRYPTED\r\n" \ + "DEK-Info: DES-EDE3-CBC,307EAB469933D64E\r\n" \ + "\r\n" \ + "IxbrRmKcAzctJqPdTQLA4SWyBYYGYJVkYEna+F7Pa5t5Yg/gKADrFKcm6B72e7DG\r\n" \ + "ihExtZI648s0zdYw6qSJ74vrPSuWDe5qm93BqsfVH9svtCzWHW0pm1p0KTBCFfUq\r\n" \ + "UsuWTITwJImcnlAs1gaRZ3sAWm7cOUidL0fo2G0fYUFNcYoCSLffCFTEHBuPnagb\r\n" \ + "a77x/sY1Bvii8S9/XhDTb6pTMx06wzrm\r\n" \ + "-----END EC PRIVATE KEY-----\r\n" +/* END FILE */ + +#define TEST_CA_PWD_EC_PEM "PolarSSLTest" + +/* This is generated from tests/data_files/test-ca2.key.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_CA_KEY_EC_DER tests/data_files/test-ca2.key.der */ +#define TEST_CA_KEY_EC_DER { \ + 0x30, 0x81, 0xa4, 0x02, 0x01, 0x01, 0x04, 0x30, 0x83, 0xd9, 0x15, 0x0e, \ + 0xa0, 0x71, 0xf0, 0x57, 0x10, 0x33, 0xa3, 0x38, 0xb8, 0x86, 0xc1, 0xa6, \ + 0x11, 0x5d, 0x6d, 0xb4, 0x03, 0xe1, 0x29, 0x76, 0x45, 0xd7, 0x87, 0x6f, \ + 0x23, 0xab, 0x44, 0x20, 0xea, 0x64, 0x7b, 0x85, 0xb1, 0x76, 0xe7, 0x85, \ + 0x95, 0xaa, 0x74, 0xd6, 0xd1, 0xa4, 0x5e, 0xea, 0xa0, 0x07, 0x06, 0x05, \ + 0x2b, 0x81, 0x04, 0x00, 0x22, 0xa1, 0x64, 0x03, 0x62, 0x00, 0x04, 0xc3, \ + 0xda, 0x2b, 0x34, 0x41, 0x37, 0x58, 0x2f, 0x87, 0x56, 0xfe, 0xfc, 0x89, \ + 0xba, 0x29, 0x43, 0x4b, 0x4e, 0xe0, 0x6e, 0xc3, 0x0e, 0x57, 0x53, 0x33, \ + 0x39, 0x58, 0xd4, 0x52, 0xb4, 0x91, 0x95, 0x39, 0x0b, 0x23, 0xdf, 0x5f, \ + 0x17, 0x24, 0x62, 0x48, 0xfc, 0x1a, 0x95, 0x29, 0xce, 0x2c, 0x2d, 0x87, \ + 0xc2, 0x88, 0x52, 0x80, 0xaf, 0xd6, 0x6a, 0xab, 0x21, 0xdd, 0xb8, 0xd3, \ + 0x1c, 0x6e, 0x58, 0xb8, 0xca, 0xe8, 0xb2, 0x69, 0x8e, 0xf3, 0x41, 0xad, \ + 0x29, 0xc3, 0xb4, 0x5f, 0x75, 0xa7, 0x47, 0x6f, 0xd5, 0x19, 0x29, 0x55, \ + 0x69, 0x9a, 0x53, 0x3b, 0x20, 0xb4, 0x66, 0x16, 0x60, 0x33, 0x1e \ +} +/* END FILE */ + +/* This is taken from tests/data_files/test-ca-sha256.crt. */ +/* BEGIN FILE string macro TEST_CA_CRT_RSA_SHA256_PEM tests/data_files/test-ca-sha256.crt */ +#define TEST_CA_CRT_RSA_SHA256_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIIDQTCCAimgAwIBAgIBAzANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" \ + "MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ + "MTkwMjEwMTQ0NDAwWhcNMjkwMjEwMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ + "A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ + "CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ + "mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ + "50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ + "YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ + "R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ + "KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ + "UDBOMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFLRa5KWz3tJS9rnVppUP6z68x/3/\r\n" \ + "MB8GA1UdIwQYMBaAFLRa5KWz3tJS9rnVppUP6z68x/3/MA0GCSqGSIb3DQEBCwUA\r\n" \ + "A4IBAQA4qFSCth2q22uJIdE4KGHJsJjVEfw2/xn+MkTvCMfxVrvmRvqCtjE4tKDl\r\n" \ + "oK4MxFOek07oDZwvtAT9ijn1hHftTNS7RH9zd/fxNpfcHnMZXVC4w4DNA1fSANtW\r\n" \ + "5sY1JB5Je9jScrsLSS+mAjyv0Ow3Hb2Bix8wu7xNNrV5fIf7Ubm+wt6SqEBxu3Kb\r\n" \ + "+EfObAT4huf3czznhH3C17ed6NSbXwoXfby7stWUDeRJv08RaFOykf/Aae7bY5PL\r\n" \ + "yTVrkAnikMntJ9YI+hNNYt3inqq11A5cN0+rVTst8UKCxzQ4GpvroSwPKTFkbMw4\r\n" \ + "/anT1dVxr/BtwJfiESoK3/4CeXR1\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This is generated from tests/data_files/test-ca-sha256.crt.der + * using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_CA_CRT_RSA_SHA256_DER tests/data_files/test-ca-sha256.crt.der */ +#define TEST_CA_CRT_RSA_SHA256_DER { \ + 0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x01, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \ + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x0b, 0x30, \ + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, \ + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, \ + 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, \ + 0x04, 0x03, 0x0c, 0x10, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, \ + 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, \ + 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, 0x30, 0x30, \ + 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, \ + 0x34, 0x30, 0x30, 0x5a, 0x30, 0x3b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, \ + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, \ + 0x53, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, \ + 0x10, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x20, 0x54, 0x65, \ + 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, \ + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, \ + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, \ + 0x01, 0x00, 0xc0, 0xdf, 0x37, 0xfc, 0x17, 0xbb, 0xe0, 0x96, 0x9d, 0x3f, \ + 0x86, 0xde, 0x96, 0x32, 0x7d, 0x44, 0xa5, 0x16, 0xa0, 0xcd, 0x21, 0xf1, \ + 0x99, 0xd4, 0xec, 0xea, 0xcb, 0x7c, 0x18, 0x58, 0x08, 0x94, 0xa5, 0xec, \ + 0x9b, 0xc5, 0x8b, 0xdf, 0x1a, 0x1e, 0x99, 0x38, 0x99, 0x87, 0x1e, 0x7b, \ + 0xc0, 0x8d, 0x39, 0xdf, 0x38, 0x5d, 0x70, 0x78, 0x07, 0xd3, 0x9e, 0xd9, \ + 0x93, 0xe8, 0xb9, 0x72, 0x51, 0xc5, 0xce, 0xa3, 0x30, 0x52, 0xa9, 0xf2, \ + 0xe7, 0x40, 0x70, 0x14, 0xcb, 0x44, 0xa2, 0x72, 0x0b, 0xc2, 0xe5, 0x40, \ + 0xf9, 0x3e, 0xe5, 0xa6, 0x0e, 0xb3, 0xf9, 0xec, 0x4a, 0x63, 0xc0, 0xb8, \ + 0x29, 0x00, 0x74, 0x9c, 0x57, 0x3b, 0xa8, 0xa5, 0x04, 0x90, 0x71, 0xf1, \ + 0xbd, 0x83, 0xd9, 0x3f, 0xd6, 0xa5, 0xe2, 0x3c, 0x2a, 0x8f, 0xef, 0x27, \ + 0x60, 0xc3, 0xc6, 0x9f, 0xcb, 0xba, 0xec, 0x60, 0x7d, 0xb7, 0xe6, 0x84, \ + 0x32, 0xbe, 0x4f, 0xfb, 0x58, 0x26, 0x22, 0x03, 0x5b, 0xd4, 0xb4, 0xd5, \ + 0xfb, 0xf5, 0xe3, 0x96, 0x2e, 0x70, 0xc0, 0xe4, 0x2e, 0xbd, 0xfc, 0x2e, \ + 0xee, 0xe2, 0x41, 0x55, 0xc0, 0x34, 0x2e, 0x7d, 0x24, 0x72, 0x69, 0xcb, \ + 0x47, 0xb1, 0x14, 0x40, 0x83, 0x7d, 0x67, 0xf4, 0x86, 0xf6, 0x31, 0xab, \ + 0xf1, 0x79, 0xa4, 0xb2, 0xb5, 0x2e, 0x12, 0xf9, 0x84, 0x17, 0xf0, 0x62, \ + 0x6f, 0x27, 0x3e, 0x13, 0x58, 0xb1, 0x54, 0x0d, 0x21, 0x9a, 0x73, 0x37, \ + 0xa1, 0x30, 0xcf, 0x6f, 0x92, 0xdc, 0xf6, 0xe9, 0xfc, 0xac, 0xdb, 0x2e, \ + 0x28, 0xd1, 0x7e, 0x02, 0x4b, 0x23, 0xa0, 0x15, 0xf2, 0x38, 0x65, 0x64, \ + 0x09, 0xea, 0x0c, 0x6e, 0x8e, 0x1b, 0x17, 0xa0, 0x71, 0xc8, 0xb3, 0x9b, \ + 0xc9, 0xab, 0xe9, 0xc3, 0xf2, 0xcf, 0x87, 0x96, 0x8f, 0x80, 0x02, 0x32, \ + 0x9e, 0x99, 0x58, 0x6f, 0xa2, 0xd5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, \ + 0x50, 0x30, 0x4e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, \ + 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, \ + 0x04, 0x16, 0x04, 0x14, 0xb4, 0x5a, 0xe4, 0xa5, 0xb3, 0xde, 0xd2, 0x52, \ + 0xf6, 0xb9, 0xd5, 0xa6, 0x95, 0x0f, 0xeb, 0x3e, 0xbc, 0xc7, 0xfd, 0xff, \ + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, \ + 0x14, 0xb4, 0x5a, 0xe4, 0xa5, 0xb3, 0xde, 0xd2, 0x52, 0xf6, 0xb9, 0xd5, \ + 0xa6, 0x95, 0x0f, 0xeb, 0x3e, 0xbc, 0xc7, 0xfd, 0xff, 0x30, 0x0d, 0x06, \ + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, \ + 0x03, 0x82, 0x01, 0x01, 0x00, 0x38, 0xa8, 0x54, 0x82, 0xb6, 0x1d, 0xaa, \ + 0xdb, 0x6b, 0x89, 0x21, 0xd1, 0x38, 0x28, 0x61, 0xc9, 0xb0, 0x98, 0xd5, \ + 0x11, 0xfc, 0x36, 0xff, 0x19, 0xfe, 0x32, 0x44, 0xef, 0x08, 0xc7, 0xf1, \ + 0x56, 0xbb, 0xe6, 0x46, 0xfa, 0x82, 0xb6, 0x31, 0x38, 0xb4, 0xa0, 0xe5, \ + 0xa0, 0xae, 0x0c, 0xc4, 0x53, 0x9e, 0x93, 0x4e, 0xe8, 0x0d, 0x9c, 0x2f, \ + 0xb4, 0x04, 0xfd, 0x8a, 0x39, 0xf5, 0x84, 0x77, 0xed, 0x4c, 0xd4, 0xbb, \ + 0x44, 0x7f, 0x73, 0x77, 0xf7, 0xf1, 0x36, 0x97, 0xdc, 0x1e, 0x73, 0x19, \ + 0x5d, 0x50, 0xb8, 0xc3, 0x80, 0xcd, 0x03, 0x57, 0xd2, 0x00, 0xdb, 0x56, \ + 0xe6, 0xc6, 0x35, 0x24, 0x1e, 0x49, 0x7b, 0xd8, 0xd2, 0x72, 0xbb, 0x0b, \ + 0x49, 0x2f, 0xa6, 0x02, 0x3c, 0xaf, 0xd0, 0xec, 0x37, 0x1d, 0xbd, 0x81, \ + 0x8b, 0x1f, 0x30, 0xbb, 0xbc, 0x4d, 0x36, 0xb5, 0x79, 0x7c, 0x87, 0xfb, \ + 0x51, 0xb9, 0xbe, 0xc2, 0xde, 0x92, 0xa8, 0x40, 0x71, 0xbb, 0x72, 0x9b, \ + 0xf8, 0x47, 0xce, 0x6c, 0x04, 0xf8, 0x86, 0xe7, 0xf7, 0x73, 0x3c, 0xe7, \ + 0x84, 0x7d, 0xc2, 0xd7, 0xb7, 0x9d, 0xe8, 0xd4, 0x9b, 0x5f, 0x0a, 0x17, \ + 0x7d, 0xbc, 0xbb, 0xb2, 0xd5, 0x94, 0x0d, 0xe4, 0x49, 0xbf, 0x4f, 0x11, \ + 0x68, 0x53, 0xb2, 0x91, 0xff, 0xc0, 0x69, 0xee, 0xdb, 0x63, 0x93, 0xcb, \ + 0xc9, 0x35, 0x6b, 0x90, 0x09, 0xe2, 0x90, 0xc9, 0xed, 0x27, 0xd6, 0x08, \ + 0xfa, 0x13, 0x4d, 0x62, 0xdd, 0xe2, 0x9e, 0xaa, 0xb5, 0xd4, 0x0e, 0x5c, \ + 0x37, 0x4f, 0xab, 0x55, 0x3b, 0x2d, 0xf1, 0x42, 0x82, 0xc7, 0x34, 0x38, \ + 0x1a, 0x9b, 0xeb, 0xa1, 0x2c, 0x0f, 0x29, 0x31, 0x64, 0x6c, 0xcc, 0x38, \ + 0xfd, 0xa9, 0xd3, 0xd5, 0xd5, 0x71, 0xaf, 0xf0, 0x6d, 0xc0, 0x97, 0xe2, \ + 0x11, 0x2a, 0x0a, 0xdf, 0xfe, 0x02, 0x79, 0x74, 0x75 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/test-ca-sha1.crt. */ +/* BEGIN FILE string macro TEST_CA_CRT_RSA_SHA1_PEM tests/data_files/test-ca-sha1.crt */ +#define TEST_CA_CRT_RSA_SHA1_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIIDQTCCAimgAwIBAgIBAzANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ + "MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ + "MTkwMjEwMTQ0NDAwWhcNMjkwMjEwMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ + "A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ + "CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ + "mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ + "50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ + "YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ + "R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ + "KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ + "UDBOMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFLRa5KWz3tJS9rnVppUP6z68x/3/\r\n" \ + "MB8GA1UdIwQYMBaAFLRa5KWz3tJS9rnVppUP6z68x/3/MA0GCSqGSIb3DQEBBQUA\r\n" \ + "A4IBAQB0ZiNRFdia6kskaPnhrqejIRq8YMEGAf2oIPnyZ78xoyERgc35lHGyMtsL\r\n" \ + "hWicNjP4d/hS9As4j5KA2gdNGi5ETA1X7SowWOGsryivSpMSHVy1+HdfWlsYQOzm\r\n" \ + "8o+faQNUm8XzPVmttfAVspxeHSxJZ36Oo+QWZ5wZlCIEyjEdLUId+Tm4Bz3B5jRD\r\n" \ + "zZa/SaqDokq66N2zpbgKKAl3GU2O++fBqP2dSkdQykmTxhLLWRN8FJqhYATyQntZ\r\n" \ + "0QSi3W9HfSZPnFTcPIXeoiPd2pLlxt1hZu8dws2LTXE63uP6MM4LHvWxiuJaWkP/\r\n" \ + "mtxyUALj2pQxRitopORFQdn7AOY5\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This is taken from tests/data_files/test-ca-sha1.crt.der. */ +/* BEGIN FILE binary macro TEST_CA_CRT_RSA_SHA1_DER tests/data_files/test-ca-sha1.crt.der */ +#define TEST_CA_CRT_RSA_SHA1_DER { \ + 0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x01, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \ + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x0b, 0x30, \ + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, \ + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, \ + 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, \ + 0x04, 0x03, 0x0c, 0x10, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, \ + 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, \ + 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, 0x30, 0x30, \ + 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, \ + 0x34, 0x30, 0x30, 0x5a, 0x30, 0x3b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, \ + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, \ + 0x53, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, \ + 0x10, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x20, 0x54, 0x65, \ + 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, \ + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, \ + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, \ + 0x01, 0x00, 0xc0, 0xdf, 0x37, 0xfc, 0x17, 0xbb, 0xe0, 0x96, 0x9d, 0x3f, \ + 0x86, 0xde, 0x96, 0x32, 0x7d, 0x44, 0xa5, 0x16, 0xa0, 0xcd, 0x21, 0xf1, \ + 0x99, 0xd4, 0xec, 0xea, 0xcb, 0x7c, 0x18, 0x58, 0x08, 0x94, 0xa5, 0xec, \ + 0x9b, 0xc5, 0x8b, 0xdf, 0x1a, 0x1e, 0x99, 0x38, 0x99, 0x87, 0x1e, 0x7b, \ + 0xc0, 0x8d, 0x39, 0xdf, 0x38, 0x5d, 0x70, 0x78, 0x07, 0xd3, 0x9e, 0xd9, \ + 0x93, 0xe8, 0xb9, 0x72, 0x51, 0xc5, 0xce, 0xa3, 0x30, 0x52, 0xa9, 0xf2, \ + 0xe7, 0x40, 0x70, 0x14, 0xcb, 0x44, 0xa2, 0x72, 0x0b, 0xc2, 0xe5, 0x40, \ + 0xf9, 0x3e, 0xe5, 0xa6, 0x0e, 0xb3, 0xf9, 0xec, 0x4a, 0x63, 0xc0, 0xb8, \ + 0x29, 0x00, 0x74, 0x9c, 0x57, 0x3b, 0xa8, 0xa5, 0x04, 0x90, 0x71, 0xf1, \ + 0xbd, 0x83, 0xd9, 0x3f, 0xd6, 0xa5, 0xe2, 0x3c, 0x2a, 0x8f, 0xef, 0x27, \ + 0x60, 0xc3, 0xc6, 0x9f, 0xcb, 0xba, 0xec, 0x60, 0x7d, 0xb7, 0xe6, 0x84, \ + 0x32, 0xbe, 0x4f, 0xfb, 0x58, 0x26, 0x22, 0x03, 0x5b, 0xd4, 0xb4, 0xd5, \ + 0xfb, 0xf5, 0xe3, 0x96, 0x2e, 0x70, 0xc0, 0xe4, 0x2e, 0xbd, 0xfc, 0x2e, \ + 0xee, 0xe2, 0x41, 0x55, 0xc0, 0x34, 0x2e, 0x7d, 0x24, 0x72, 0x69, 0xcb, \ + 0x47, 0xb1, 0x14, 0x40, 0x83, 0x7d, 0x67, 0xf4, 0x86, 0xf6, 0x31, 0xab, \ + 0xf1, 0x79, 0xa4, 0xb2, 0xb5, 0x2e, 0x12, 0xf9, 0x84, 0x17, 0xf0, 0x62, \ + 0x6f, 0x27, 0x3e, 0x13, 0x58, 0xb1, 0x54, 0x0d, 0x21, 0x9a, 0x73, 0x37, \ + 0xa1, 0x30, 0xcf, 0x6f, 0x92, 0xdc, 0xf6, 0xe9, 0xfc, 0xac, 0xdb, 0x2e, \ + 0x28, 0xd1, 0x7e, 0x02, 0x4b, 0x23, 0xa0, 0x15, 0xf2, 0x38, 0x65, 0x64, \ + 0x09, 0xea, 0x0c, 0x6e, 0x8e, 0x1b, 0x17, 0xa0, 0x71, 0xc8, 0xb3, 0x9b, \ + 0xc9, 0xab, 0xe9, 0xc3, 0xf2, 0xcf, 0x87, 0x96, 0x8f, 0x80, 0x02, 0x32, \ + 0x9e, 0x99, 0x58, 0x6f, 0xa2, 0xd5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, \ + 0x50, 0x30, 0x4e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, \ + 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, \ + 0x04, 0x16, 0x04, 0x14, 0xb4, 0x5a, 0xe4, 0xa5, 0xb3, 0xde, 0xd2, 0x52, \ + 0xf6, 0xb9, 0xd5, 0xa6, 0x95, 0x0f, 0xeb, 0x3e, 0xbc, 0xc7, 0xfd, 0xff, \ + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, \ + 0x14, 0xb4, 0x5a, 0xe4, 0xa5, 0xb3, 0xde, 0xd2, 0x52, 0xf6, 0xb9, 0xd5, \ + 0xa6, 0x95, 0x0f, 0xeb, 0x3e, 0xbc, 0xc7, 0xfd, 0xff, 0x30, 0x0d, 0x06, \ + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, \ + 0x03, 0x82, 0x01, 0x01, 0x00, 0x74, 0x66, 0x23, 0x51, 0x15, 0xd8, 0x9a, \ + 0xea, 0x4b, 0x24, 0x68, 0xf9, 0xe1, 0xae, 0xa7, 0xa3, 0x21, 0x1a, 0xbc, \ + 0x60, 0xc1, 0x06, 0x01, 0xfd, 0xa8, 0x20, 0xf9, 0xf2, 0x67, 0xbf, 0x31, \ + 0xa3, 0x21, 0x11, 0x81, 0xcd, 0xf9, 0x94, 0x71, 0xb2, 0x32, 0xdb, 0x0b, \ + 0x85, 0x68, 0x9c, 0x36, 0x33, 0xf8, 0x77, 0xf8, 0x52, 0xf4, 0x0b, 0x38, \ + 0x8f, 0x92, 0x80, 0xda, 0x07, 0x4d, 0x1a, 0x2e, 0x44, 0x4c, 0x0d, 0x57, \ + 0xed, 0x2a, 0x30, 0x58, 0xe1, 0xac, 0xaf, 0x28, 0xaf, 0x4a, 0x93, 0x12, \ + 0x1d, 0x5c, 0xb5, 0xf8, 0x77, 0x5f, 0x5a, 0x5b, 0x18, 0x40, 0xec, 0xe6, \ + 0xf2, 0x8f, 0x9f, 0x69, 0x03, 0x54, 0x9b, 0xc5, 0xf3, 0x3d, 0x59, 0xad, \ + 0xb5, 0xf0, 0x15, 0xb2, 0x9c, 0x5e, 0x1d, 0x2c, 0x49, 0x67, 0x7e, 0x8e, \ + 0xa3, 0xe4, 0x16, 0x67, 0x9c, 0x19, 0x94, 0x22, 0x04, 0xca, 0x31, 0x1d, \ + 0x2d, 0x42, 0x1d, 0xf9, 0x39, 0xb8, 0x07, 0x3d, 0xc1, 0xe6, 0x34, 0x43, \ + 0xcd, 0x96, 0xbf, 0x49, 0xaa, 0x83, 0xa2, 0x4a, 0xba, 0xe8, 0xdd, 0xb3, \ + 0xa5, 0xb8, 0x0a, 0x28, 0x09, 0x77, 0x19, 0x4d, 0x8e, 0xfb, 0xe7, 0xc1, \ + 0xa8, 0xfd, 0x9d, 0x4a, 0x47, 0x50, 0xca, 0x49, 0x93, 0xc6, 0x12, 0xcb, \ + 0x59, 0x13, 0x7c, 0x14, 0x9a, 0xa1, 0x60, 0x04, 0xf2, 0x42, 0x7b, 0x59, \ + 0xd1, 0x04, 0xa2, 0xdd, 0x6f, 0x47, 0x7d, 0x26, 0x4f, 0x9c, 0x54, 0xdc, \ + 0x3c, 0x85, 0xde, 0xa2, 0x23, 0xdd, 0xda, 0x92, 0xe5, 0xc6, 0xdd, 0x61, \ + 0x66, 0xef, 0x1d, 0xc2, 0xcd, 0x8b, 0x4d, 0x71, 0x3a, 0xde, 0xe3, 0xfa, \ + 0x30, 0xce, 0x0b, 0x1e, 0xf5, 0xb1, 0x8a, 0xe2, 0x5a, 0x5a, 0x43, 0xff, \ + 0x9a, 0xdc, 0x72, 0x50, 0x02, 0xe3, 0xda, 0x94, 0x31, 0x46, 0x2b, 0x68, \ + 0xa4, 0xe4, 0x45, 0x41, 0xd9, 0xfb, 0x00, 0xe6, 0x39 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/test-ca.key */ +/* BEGIN FILE string macro TEST_CA_KEY_RSA_PEM tests/data_files/test-ca.key */ +#define TEST_CA_KEY_RSA_PEM \ + "-----BEGIN RSA PRIVATE KEY-----\r\n" \ + "Proc-Type: 4,ENCRYPTED\r\n" \ + "DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n" \ + "\r\n" \ + "9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n" \ + "7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n" \ + "Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n" \ + "PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n" \ + "GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n" \ + "gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n" \ + "QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n" \ + "PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n" \ + "vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n" \ + "WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n" \ + "JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n" \ + "KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n" \ + "Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n" \ + "9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n" \ + "iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n" \ + "tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n" \ + "P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n" \ + "1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n" \ + "nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n" \ + "X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n" \ + "rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n" \ + "L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n" \ + "I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n" \ + "wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n" \ + "P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n" \ + "-----END RSA PRIVATE KEY-----\r\n" +/* END FILE */ + +#define TEST_CA_PWD_RSA_PEM "PolarSSLTest" + +/* This was generated from test-ca.key.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_CA_KEY_RSA_DER tests/data_files/test-ca.key.der */ +#define TEST_CA_KEY_RSA_DER { \ + 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, \ + 0xc0, 0xdf, 0x37, 0xfc, 0x17, 0xbb, 0xe0, 0x96, 0x9d, 0x3f, 0x86, 0xde, \ + 0x96, 0x32, 0x7d, 0x44, 0xa5, 0x16, 0xa0, 0xcd, 0x21, 0xf1, 0x99, 0xd4, \ + 0xec, 0xea, 0xcb, 0x7c, 0x18, 0x58, 0x08, 0x94, 0xa5, 0xec, 0x9b, 0xc5, \ + 0x8b, 0xdf, 0x1a, 0x1e, 0x99, 0x38, 0x99, 0x87, 0x1e, 0x7b, 0xc0, 0x8d, \ + 0x39, 0xdf, 0x38, 0x5d, 0x70, 0x78, 0x07, 0xd3, 0x9e, 0xd9, 0x93, 0xe8, \ + 0xb9, 0x72, 0x51, 0xc5, 0xce, 0xa3, 0x30, 0x52, 0xa9, 0xf2, 0xe7, 0x40, \ + 0x70, 0x14, 0xcb, 0x44, 0xa2, 0x72, 0x0b, 0xc2, 0xe5, 0x40, 0xf9, 0x3e, \ + 0xe5, 0xa6, 0x0e, 0xb3, 0xf9, 0xec, 0x4a, 0x63, 0xc0, 0xb8, 0x29, 0x00, \ + 0x74, 0x9c, 0x57, 0x3b, 0xa8, 0xa5, 0x04, 0x90, 0x71, 0xf1, 0xbd, 0x83, \ + 0xd9, 0x3f, 0xd6, 0xa5, 0xe2, 0x3c, 0x2a, 0x8f, 0xef, 0x27, 0x60, 0xc3, \ + 0xc6, 0x9f, 0xcb, 0xba, 0xec, 0x60, 0x7d, 0xb7, 0xe6, 0x84, 0x32, 0xbe, \ + 0x4f, 0xfb, 0x58, 0x26, 0x22, 0x03, 0x5b, 0xd4, 0xb4, 0xd5, 0xfb, 0xf5, \ + 0xe3, 0x96, 0x2e, 0x70, 0xc0, 0xe4, 0x2e, 0xbd, 0xfc, 0x2e, 0xee, 0xe2, \ + 0x41, 0x55, 0xc0, 0x34, 0x2e, 0x7d, 0x24, 0x72, 0x69, 0xcb, 0x47, 0xb1, \ + 0x14, 0x40, 0x83, 0x7d, 0x67, 0xf4, 0x86, 0xf6, 0x31, 0xab, 0xf1, 0x79, \ + 0xa4, 0xb2, 0xb5, 0x2e, 0x12, 0xf9, 0x84, 0x17, 0xf0, 0x62, 0x6f, 0x27, \ + 0x3e, 0x13, 0x58, 0xb1, 0x54, 0x0d, 0x21, 0x9a, 0x73, 0x37, 0xa1, 0x30, \ + 0xcf, 0x6f, 0x92, 0xdc, 0xf6, 0xe9, 0xfc, 0xac, 0xdb, 0x2e, 0x28, 0xd1, \ + 0x7e, 0x02, 0x4b, 0x23, 0xa0, 0x15, 0xf2, 0x38, 0x65, 0x64, 0x09, 0xea, \ + 0x0c, 0x6e, 0x8e, 0x1b, 0x17, 0xa0, 0x71, 0xc8, 0xb3, 0x9b, 0xc9, 0xab, \ + 0xe9, 0xc3, 0xf2, 0xcf, 0x87, 0x96, 0x8f, 0x80, 0x02, 0x32, 0x9e, 0x99, \ + 0x58, 0x6f, 0xa2, 0xd5, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, \ + 0x00, 0x3f, 0xf7, 0x07, 0xd3, 0x34, 0x6f, 0xdb, 0xc9, 0x37, 0xb7, 0x84, \ + 0xdc, 0x37, 0x45, 0xe1, 0x63, 0xad, 0xb8, 0xb6, 0x75, 0xb1, 0xc7, 0x35, \ + 0xb4, 0x77, 0x2a, 0x5b, 0x77, 0xf9, 0x7e, 0xe0, 0xc1, 0xa3, 0xd1, 0xb7, \ + 0xcb, 0xa9, 0x5a, 0xc1, 0x87, 0xda, 0x5a, 0xfa, 0x17, 0xe4, 0xd5, 0x38, \ + 0x03, 0xde, 0x68, 0x98, 0x81, 0xec, 0xb5, 0xf2, 0x2a, 0x8d, 0xe9, 0x2c, \ + 0xf3, 0xa6, 0xe5, 0x32, 0x17, 0x7f, 0x33, 0x81, 0xe8, 0x38, 0x72, 0xd5, \ + 0x9c, 0xfa, 0x4e, 0xfb, 0x26, 0xf5, 0x15, 0x0b, 0xaf, 0x84, 0x66, 0xab, \ + 0x02, 0xe0, 0x18, 0xd5, 0x91, 0x7c, 0xd6, 0x8f, 0xc9, 0x4b, 0x76, 0x08, \ + 0x2b, 0x1d, 0x81, 0x68, 0x30, 0xe1, 0xfa, 0x70, 0x6c, 0x13, 0x4e, 0x10, \ + 0x03, 0x35, 0x3e, 0xc5, 0xca, 0x58, 0x20, 0x8a, 0x21, 0x18, 0x38, 0xa0, \ + 0x0f, 0xed, 0xc4, 0xbb, 0x45, 0x6f, 0xf5, 0x84, 0x5b, 0xb0, 0xcf, 0x4e, \ + 0x9d, 0x58, 0x13, 0x6b, 0x35, 0x35, 0x69, 0xa1, 0xd2, 0xc4, 0xf2, 0xc1, \ + 0x48, 0x04, 0x20, 0x51, 0xb9, 0x6b, 0xa4, 0x5d, 0xa5, 0x4b, 0x84, 0x88, \ + 0x43, 0x48, 0x99, 0x2c, 0xbb, 0xa4, 0x97, 0xd6, 0xd6, 0x18, 0xf6, 0xec, \ + 0x5c, 0xd1, 0x31, 0x49, 0xc9, 0xf2, 0x8f, 0x0b, 0x4d, 0xef, 0x09, 0x02, \ + 0xfe, 0x7d, 0xfd, 0xbb, 0xaf, 0x2b, 0x83, 0x94, 0x22, 0xc4, 0xa7, 0x3e, \ + 0x66, 0xf5, 0xe0, 0x57, 0xdc, 0xf2, 0xed, 0x2c, 0x3e, 0x81, 0x74, 0x76, \ + 0x1e, 0x96, 0x6f, 0x74, 0x1e, 0x32, 0x0e, 0x14, 0x31, 0xd0, 0x74, 0xf0, \ + 0xf4, 0x07, 0xbd, 0xc3, 0xd1, 0x22, 0xc2, 0xa8, 0x95, 0x92, 0x06, 0x7f, \ + 0x43, 0x02, 0x91, 0xbc, 0xdd, 0x23, 0x01, 0x89, 0x94, 0x20, 0x44, 0x64, \ + 0xf5, 0x1d, 0x67, 0xd2, 0x8f, 0xe8, 0x69, 0xa5, 0x29, 0x25, 0xe6, 0x50, \ + 0x9c, 0xe3, 0xe9, 0xcb, 0x75, 0x02, 0x81, 0x81, 0x00, 0xe2, 0x29, 0x3e, \ + 0xaa, 0x6b, 0xd5, 0x59, 0x1e, 0x9c, 0xe6, 0x47, 0xd5, 0xb6, 0xd7, 0xe3, \ + 0xf1, 0x8e, 0x9e, 0xe9, 0x83, 0x5f, 0x10, 0x9f, 0x63, 0xec, 0x04, 0x44, \ + 0xcc, 0x3f, 0xf8, 0xd9, 0x3a, 0x17, 0xe0, 0x4f, 0xfe, 0xd8, 0x4d, 0xcd, \ + 0x46, 0x54, 0x74, 0xbf, 0x0a, 0xc4, 0x67, 0x9c, 0xa7, 0xd8, 0x89, 0x65, \ + 0x4c, 0xfd, 0x58, 0x2a, 0x47, 0x0f, 0xf4, 0x37, 0xb6, 0x55, 0xb0, 0x1d, \ + 0xed, 0xa7, 0x39, 0xfc, 0x4f, 0xa3, 0xc4, 0x75, 0x3a, 0xa3, 0x98, 0xa7, \ + 0x45, 0xf5, 0x66, 0xcb, 0x7c, 0x65, 0xfb, 0x80, 0x23, 0xe6, 0xff, 0xfd, \ + 0x99, 0x1f, 0x8e, 0x6b, 0xff, 0x5e, 0x93, 0x66, 0xdf, 0x6c, 0x6f, 0xc3, \ + 0xf6, 0x38, 0x2e, 0xff, 0x69, 0xb5, 0xac, 0xae, 0xbb, 0xc6, 0x71, 0x16, \ + 0x6b, 0xd0, 0xf8, 0x22, 0xd9, 0xf8, 0xa2, 0x72, 0x20, 0xd2, 0xe2, 0x3a, \ + 0x70, 0x4b, 0xde, 0xab, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xda, 0x51, 0x9b, \ + 0xb8, 0xb2, 0x2a, 0x14, 0x75, 0x58, 0x40, 0x8d, 0x27, 0x70, 0xfa, 0x31, \ + 0x48, 0xb0, 0x20, 0x21, 0x34, 0xfa, 0x4c, 0x57, 0xa8, 0x11, 0x88, 0xf3, \ + 0xa7, 0xae, 0x21, 0xe9, 0xb6, 0x2b, 0xd1, 0xcd, 0xa7, 0xf8, 0xd8, 0x0c, \ + 0x8a, 0x76, 0x22, 0x35, 0x44, 0xce, 0x3f, 0x25, 0x29, 0x83, 0x7d, 0x79, \ + 0xa7, 0x31, 0xd6, 0xec, 0xb2, 0xbf, 0xda, 0x34, 0xb6, 0xf6, 0xb2, 0x3b, \ + 0xf3, 0x78, 0x5a, 0x04, 0x83, 0x33, 0x3e, 0xa2, 0xe2, 0x81, 0x82, 0x13, \ + 0xd4, 0x35, 0x17, 0x63, 0x9b, 0x9e, 0xc4, 0x8d, 0x91, 0x4c, 0x03, 0x77, \ + 0xc7, 0x71, 0x5b, 0xee, 0x83, 0x6d, 0xd5, 0x78, 0x88, 0xf6, 0x2c, 0x79, \ + 0xc2, 0x4a, 0xb4, 0x79, 0x90, 0x70, 0xbf, 0xdf, 0x34, 0x56, 0x96, 0x71, \ + 0xe3, 0x0e, 0x68, 0x91, 0xbc, 0xea, 0xcb, 0x33, 0xc0, 0xbe, 0x45, 0xd7, \ + 0xfc, 0x30, 0xfd, 0x01, 0x3b, 0x02, 0x81, 0x81, 0x00, 0xd2, 0x9f, 0x2a, \ + 0xb7, 0x38, 0x19, 0xc7, 0x17, 0x95, 0x73, 0x78, 0xae, 0xf5, 0xcb, 0x75, \ + 0x83, 0x7f, 0x19, 0x4b, 0xcb, 0x86, 0xfb, 0x4a, 0x15, 0x9a, 0xb6, 0x17, \ + 0x04, 0x49, 0x07, 0x8d, 0xf6, 0x66, 0x4a, 0x06, 0xf6, 0x05, 0xa7, 0xdf, \ + 0x66, 0x82, 0x3c, 0xff, 0xb6, 0x1d, 0x57, 0x89, 0x33, 0x5f, 0x9c, 0x05, \ + 0x75, 0x7f, 0xf3, 0x5d, 0xdc, 0x34, 0x65, 0x72, 0x85, 0x22, 0xa4, 0x14, \ + 0x1b, 0x41, 0xc3, 0xe4, 0xd0, 0x9e, 0x69, 0xd5, 0xeb, 0x38, 0x74, 0x70, \ + 0x43, 0xdc, 0xd9, 0x50, 0xe4, 0x97, 0x6d, 0x73, 0xd6, 0xfb, 0xc8, 0xa7, \ + 0xfa, 0xb4, 0xc2, 0xc4, 0x9d, 0x5d, 0x0c, 0xd5, 0x9f, 0x79, 0xb3, 0x54, \ + 0xc2, 0xb7, 0x6c, 0x3d, 0x7d, 0xcb, 0x2d, 0xf8, 0xc4, 0xf3, 0x78, 0x5a, \ + 0x33, 0x2a, 0xb8, 0x0c, 0x6d, 0x06, 0xfa, 0xf2, 0x62, 0xd3, 0x42, 0xd0, \ + 0xbd, 0xc8, 0x4a, 0xa5, 0x0d, 0x02, 0x81, 0x81, 0x00, 0xd4, 0xa9, 0x90, \ + 0x15, 0xde, 0xbf, 0x2c, 0xc4, 0x8d, 0x9d, 0xfb, 0xa1, 0xc2, 0xe4, 0x83, \ + 0xe3, 0x79, 0x65, 0x22, 0xd3, 0xb7, 0x49, 0x6c, 0x4d, 0x94, 0x1f, 0x22, \ + 0xb1, 0x60, 0xe7, 0x3a, 0x00, 0xb1, 0x38, 0xa2, 0xab, 0x0f, 0xb4, 0x6c, \ + 0xaa, 0xe7, 0x9e, 0x34, 0xe3, 0x7c, 0x40, 0x78, 0x53, 0xb2, 0xf9, 0x23, \ + 0xea, 0xa0, 0x9a, 0xea, 0x60, 0xc8, 0x8f, 0xa6, 0xaf, 0xdf, 0x29, 0x09, \ + 0x4b, 0x06, 0x1e, 0x31, 0xad, 0x17, 0xda, 0xd8, 0xd1, 0xe9, 0x33, 0xab, \ + 0x5b, 0x18, 0x08, 0x5b, 0x87, 0xf8, 0xa5, 0x1f, 0xfd, 0xbb, 0xdc, 0xd8, \ + 0xed, 0x97, 0x57, 0xe4, 0xc3, 0x73, 0xd6, 0xf0, 0x9e, 0x01, 0xa6, 0x9b, \ + 0x48, 0x8e, 0x7a, 0xb4, 0xbb, 0xe5, 0x88, 0x91, 0xc5, 0x2a, 0xdf, 0x4b, \ + 0xba, 0xd0, 0x8b, 0x3e, 0x03, 0x97, 0x77, 0x2f, 0x47, 0x7e, 0x51, 0x0c, \ + 0xae, 0x65, 0x8d, 0xde, 0x87, 0x02, 0x81, 0x80, 0x20, 0x24, 0x0f, 0xd2, \ + 0xaf, 0xc2, 0x28, 0x3b, 0x97, 0x20, 0xb2, 0x92, 0x49, 0xeb, 0x09, 0x68, \ + 0x40, 0xb2, 0xbe, 0xd1, 0xc3, 0x83, 0x94, 0x34, 0x38, 0xd6, 0xc9, 0xec, \ + 0x34, 0x09, 0xf9, 0x41, 0x6d, 0x5c, 0x42, 0x94, 0xf7, 0x04, 0xfc, 0x32, \ + 0x39, 0x69, 0xbc, 0x1c, 0xfb, 0x3e, 0x61, 0x98, 0xc0, 0x80, 0xd8, 0x36, \ + 0x47, 0xc3, 0x6d, 0xc2, 0x2e, 0xe7, 0x81, 0x2a, 0x17, 0x34, 0x64, 0x30, \ + 0x4e, 0x96, 0xbb, 0x26, 0x16, 0xb9, 0x41, 0x36, 0xfe, 0x8a, 0xd6, 0x53, \ + 0x7c, 0xaa, 0xec, 0x39, 0x42, 0x50, 0xef, 0xe3, 0xb3, 0x01, 0x28, 0x32, \ + 0xca, 0x6d, 0xf5, 0x9a, 0x1e, 0x9f, 0x37, 0xbe, 0xfe, 0x38, 0x20, 0x22, \ + 0x91, 0x8c, 0xcd, 0x95, 0x02, 0xf2, 0x4d, 0x6f, 0x1a, 0xb4, 0x43, 0xf0, \ + 0x19, 0xdf, 0x65, 0xc0, 0x92, 0xe7, 0x9d, 0x2f, 0x09, 0xe7, 0xec, 0x69, \ + 0xa8, 0xc2, 0x8f, 0x0d \ +} +/* END FILE */ + +/* + * Test server Certificates + * + * Test server certificates are defined for each choice + * of the following parameters: + * - PEM or DER encoding + * - SHA-1 or SHA-256 hash + * - RSA or EC key + * + * Things to add: + * - multiple EC curve types + */ + +/* This is taken from tests/data_files/server5.crt. */ +/* BEGIN FILE string macro TEST_SRV_CRT_EC_PEM tests/data_files/server5.crt */ +#define TEST_SRV_CRT_EC_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" \ + "A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" \ + "MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" \ + "A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\r\n" \ + "CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\r\n" \ + "2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\r\n" \ + "BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\r\n" \ + "PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\r\n" \ + "clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\r\n" \ + "CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\r\n" \ + "C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\r\n" \ + "fGa5kHvHARBPc8YAIVIqDvHH1Q==\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This is generated from tests/data_files/server5.crt.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_SRV_CRT_EC_DER tests/data_files/server5.crt.der */ +#define TEST_SRV_CRT_EC_DER { \ + 0x30, 0x82, 0x02, 0x1f, 0x30, 0x82, 0x01, 0xa5, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x01, 0x09, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, \ + 0x3d, 0x04, 0x03, 0x02, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, \ + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, \ + 0x53, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, \ + 0x13, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20, 0x54, 0x65, \ + 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, \ + 0x31, 0x33, 0x30, 0x39, 0x32, 0x34, 0x31, 0x35, 0x35, 0x32, 0x30, 0x34, \ + 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x39, 0x32, 0x32, 0x31, 0x35, 0x35, \ + 0x32, 0x30, 0x34, 0x5a, 0x30, 0x34, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, \ + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, \ + 0x53, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, \ + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30, 0x59, \ + 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, \ + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, \ + 0x04, 0x37, 0xcc, 0x56, 0xd9, 0x76, 0x09, 0x1e, 0x5a, 0x72, 0x3e, 0xc7, \ + 0x59, 0x2d, 0xff, 0x20, 0x6e, 0xee, 0x7c, 0xf9, 0x06, 0x91, 0x74, 0xd0, \ + 0xad, 0x14, 0xb5, 0xf7, 0x68, 0x22, 0x59, 0x62, 0x92, 0x4e, 0xe5, 0x00, \ + 0xd8, 0x23, 0x11, 0xff, 0xea, 0x2f, 0xd2, 0x34, 0x5d, 0x5d, 0x16, 0xbd, \ + 0x8a, 0x88, 0xc2, 0x6b, 0x77, 0x0d, 0x55, 0xcd, 0x8a, 0x2a, 0x0e, 0xfa, \ + 0x01, 0xc8, 0xb4, 0xed, 0xff, 0xa3, 0x81, 0x9d, 0x30, 0x81, 0x9a, 0x30, \ + 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, \ + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x50, 0x61, 0xa5, \ + 0x8f, 0xd4, 0x07, 0xd9, 0xd7, 0x82, 0x01, 0x0c, 0xe5, 0x65, 0x7f, 0x8c, \ + 0x63, 0x46, 0xa7, 0x13, 0xbe, 0x30, 0x6e, 0x06, 0x03, 0x55, 0x1d, 0x23, \ + 0x04, 0x67, 0x30, 0x65, 0x80, 0x14, 0x9d, 0x6d, 0x20, 0x24, 0x49, 0x01, \ + 0x3f, 0x2b, 0xcb, 0x78, 0xb5, 0x19, 0xbc, 0x7e, 0x24, 0xc9, 0xdb, 0xfb, \ + 0x36, 0x7c, 0xa1, 0x42, 0xa4, 0x40, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, \ + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, \ + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x50, 0x6f, 0x6c, 0x61, \ + 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, \ + 0x03, 0x13, 0x13, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20, \ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x82, 0x09, \ + 0x00, 0xc1, 0x43, 0xe2, 0x7e, 0x62, 0x43, 0xcc, 0xe8, 0x30, 0x0a, 0x06, \ + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x68, 0x00, \ + 0x30, 0x65, 0x02, 0x31, 0x00, 0x9a, 0x2c, 0x5c, 0xd7, 0xa6, 0xdb, 0xa2, \ + 0xe5, 0x64, 0x0d, 0xf0, 0xb9, 0x4e, 0xdd, 0xd7, 0x61, 0xd6, 0x13, 0x31, \ + 0xc7, 0xab, 0x73, 0x80, 0xbb, 0xd3, 0xd3, 0x73, 0x13, 0x54, 0xad, 0x92, \ + 0x0b, 0x5d, 0xab, 0xd0, 0xbc, 0xf7, 0xae, 0x2f, 0xe6, 0xa1, 0x21, 0x29, \ + 0x35, 0x95, 0xaa, 0x3e, 0x39, 0x02, 0x30, 0x21, 0x36, 0x7f, 0x9d, 0xc6, \ + 0x5d, 0xc6, 0x0b, 0xab, 0x27, 0xf2, 0x25, 0x1d, 0x3b, 0xf1, 0xcf, 0xf1, \ + 0x35, 0x25, 0x14, 0xe7, 0xe5, 0xf1, 0x97, 0xb5, 0x59, 0xe3, 0x5e, 0x15, \ + 0x7c, 0x66, 0xb9, 0x90, 0x7b, 0xc7, 0x01, 0x10, 0x4f, 0x73, 0xc6, 0x00, \ + 0x21, 0x52, 0x2a, 0x0e, 0xf1, 0xc7, 0xd5 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/server5.key. */ +/* BEGIN FILE string macro TEST_SRV_KEY_EC_PEM tests/data_files/server5.key */ +#define TEST_SRV_KEY_EC_PEM \ + "-----BEGIN EC PRIVATE KEY-----\r\n" \ + "MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n" \ + "AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\r\n" \ + "6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\r\n" \ + "-----END EC PRIVATE KEY-----\r\n" +/* END FILE */ + +/* This is generated from tests/data_files/server5.key.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_SRV_KEY_EC_DER tests/data_files/server5.key.der */ +#define TEST_SRV_KEY_EC_DER { \ + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xf1, 0x2a, 0x13, 0x20, 0x76, \ + 0x02, 0x70, 0xa8, 0x3c, 0xbf, 0xfd, 0x53, 0xf6, 0x03, 0x1e, 0xf7, 0x6a, \ + 0x5d, 0x86, 0xc8, 0xa2, 0x04, 0xf2, 0xc3, 0x0c, 0xa9, 0xeb, 0xf5, 0x1f, \ + 0x0f, 0x0e, 0xa7, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, \ + 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x37, 0xcc, 0x56, \ + 0xd9, 0x76, 0x09, 0x1e, 0x5a, 0x72, 0x3e, 0xc7, 0x59, 0x2d, 0xff, 0x20, \ + 0x6e, 0xee, 0x7c, 0xf9, 0x06, 0x91, 0x74, 0xd0, 0xad, 0x14, 0xb5, 0xf7, \ + 0x68, 0x22, 0x59, 0x62, 0x92, 0x4e, 0xe5, 0x00, 0xd8, 0x23, 0x11, 0xff, \ + 0xea, 0x2f, 0xd2, 0x34, 0x5d, 0x5d, 0x16, 0xbd, 0x8a, 0x88, 0xc2, 0x6b, \ + 0x77, 0x0d, 0x55, 0xcd, 0x8a, 0x2a, 0x0e, 0xfa, 0x01, 0xc8, 0xb4, 0xed, \ + 0xff \ +} +/* END FILE */ + +/* This is taken from tests/data_files/server2-sha256.crt. */ +/* BEGIN FILE string macro TEST_SRV_CRT_RSA_SHA256_PEM tests/data_files/server2-sha256.crt */ +#define TEST_SRV_CRT_RSA_SHA256_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" \ + "MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ + "MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" \ + "A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" \ + "AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" \ + "owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" \ + "NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" \ + "tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" \ + "hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" \ + "HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" \ + "VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" \ + "FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQELBQADggEBAC465FJh\r\n" \ + "Pqel7zJngHIHJrqj/wVAxGAFOTF396XKATGAp+HRCqJ81Ry60CNK1jDzk8dv6M6U\r\n" \ + "HoS7RIFiM/9rXQCbJfiPD5xMTejZp5n5UYHAmxsxDaazfA5FuBhkfokKK6jD4Eq9\r\n" \ + "1C94xGKb6X4/VkaPF7cqoBBw/bHxawXc0UEPjqayiBpCYU/rJoVZgLqFVP7Px3sv\r\n" \ + "a1nOrNx8rPPI1hJ+ZOg8maiPTxHZnBVLakSSLQy/sWeWyazO1RnrbxjrbgQtYKz0\r\n" \ + "e3nwGpu1w13vfckFmUSBhHXH7AAS/HpKC4IH7G2GAk3+n8iSSN71sZzpxonQwVbo\r\n" \ + "pMZqLmbBm/7WPLc=\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This is taken from tests/data_files/server2-sha256.crt.der. */ +/* BEGIN FILE binary macro TEST_SRV_CRT_RSA_SHA256_DER tests/data_files/server2-sha256.crt.der */ +#define TEST_SRV_CRT_RSA_SHA256_DER { \ + 0x30, 0x82, 0x03, 0x37, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \ + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x0b, 0x30, \ + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, \ + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, \ + 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, \ + 0x04, 0x03, 0x0c, 0x10, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, \ + 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, \ + 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, 0x30, 0x36, \ + 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, \ + 0x34, 0x30, 0x36, 0x5a, 0x30, 0x34, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, \ + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, \ + 0x53, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, \ + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30, 0x82, \ + 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, \ + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, \ + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc1, 0x4d, 0xa3, 0xdd, 0xe7, \ + 0xcd, 0x1d, 0xd1, 0x04, 0xd7, 0x49, 0x72, 0xb8, 0x99, 0xac, 0x0e, 0x78, \ + 0xe4, 0x3a, 0x3c, 0x4a, 0xcf, 0x3a, 0x13, 0x16, 0xd0, 0x5a, 0xe4, 0xcd, \ + 0xa3, 0x00, 0x88, 0xa7, 0xee, 0x1e, 0x6b, 0x96, 0xa7, 0x52, 0xb4, 0x90, \ + 0xef, 0x2d, 0x72, 0x7a, 0x3e, 0x24, 0x9a, 0xfc, 0xb6, 0x34, 0xac, 0x24, \ + 0xf5, 0x77, 0xe0, 0x26, 0x64, 0x8c, 0x9c, 0xb0, 0x28, 0x7d, 0xa1, 0xda, \ + 0xea, 0x8c, 0xe6, 0xc9, 0x1c, 0x96, 0xbc, 0xfe, 0xc1, 0x04, 0x52, 0xb3, \ + 0x36, 0xd4, 0xa3, 0xfa, 0xe1, 0xb1, 0x76, 0xd8, 0x90, 0xc1, 0x61, 0xb4, \ + 0x66, 0x52, 0x36, 0xa2, 0x26, 0x53, 0xaa, 0xab, 0x74, 0x5e, 0x07, 0x7d, \ + 0x19, 0x82, 0xdb, 0x2a, 0xd8, 0x1f, 0xa0, 0xd9, 0x0d, 0x1c, 0x2d, 0x49, \ + 0x66, 0xf7, 0x5b, 0x25, 0x73, 0x46, 0xe8, 0x0b, 0x8a, 0x4f, 0x69, 0x0c, \ + 0xb5, 0x00, 0x90, 0xe1, 0xda, 0x82, 0x10, 0x66, 0x7d, 0xae, 0x54, 0x2b, \ + 0x8b, 0x65, 0x79, 0x91, 0xa1, 0xe2, 0x61, 0xc3, 0xcd, 0x40, 0x49, 0x08, \ + 0xee, 0x68, 0x0c, 0xf1, 0x8b, 0x86, 0xd2, 0x46, 0xbf, 0xd0, 0xb8, 0xaa, \ + 0x11, 0x03, 0x1e, 0x7f, 0x56, 0xa8, 0x1a, 0x1e, 0x44, 0x18, 0x0f, 0x0f, \ + 0x85, 0x8b, 0xda, 0x8b, 0x44, 0x5e, 0xe2, 0x18, 0xc6, 0x62, 0x2f, 0xc7, \ + 0x66, 0x8d, 0xfa, 0x5d, 0xd8, 0x7d, 0xf3, 0x27, 0x89, 0x29, 0x01, 0xc5, \ + 0x90, 0x0e, 0x3f, 0x27, 0xf1, 0x30, 0xc8, 0x4a, 0x0e, 0xef, 0xd6, 0xde, \ + 0xc7, 0xc7, 0x27, 0x6b, 0xc7, 0x05, 0x3d, 0x7a, 0xc4, 0x02, 0x3c, 0x9a, \ + 0x1d, 0x3e, 0x0f, 0xe8, 0x34, 0x98, 0x5b, 0xcb, 0x73, 0x4b, 0x52, 0x96, \ + 0xd8, 0x11, 0xa2, 0x2c, 0x80, 0x88, 0x69, 0x39, 0x5a, 0xd3, 0x0f, 0xb0, \ + 0xde, 0x59, 0x2f, 0x11, 0xc7, 0xf7, 0xea, 0x12, 0x01, 0x30, 0x97, 0x02, \ + 0x03, 0x01, 0x00, 0x01, 0xa3, 0x4d, 0x30, 0x4b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, \ + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa5, 0x05, 0xe8, 0x64, 0xb8, 0xdc, \ + 0xdf, 0x60, 0x0f, 0x50, 0x12, 0x4d, 0x60, 0xa8, 0x64, 0xaf, 0x4d, 0x8b, \ + 0x43, 0x93, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, \ + 0x16, 0x80, 0x14, 0xb4, 0x5a, 0xe4, 0xa5, 0xb3, 0xde, 0xd2, 0x52, 0xf6, \ + 0xb9, 0xd5, 0xa6, 0x95, 0x0f, 0xeb, 0x3e, 0xbc, 0xc7, 0xfd, 0xff, 0x30, \ + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, \ + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x2e, 0x3a, 0xe4, 0x52, 0x61, \ + 0x3e, 0xa7, 0xa5, 0xef, 0x32, 0x67, 0x80, 0x72, 0x07, 0x26, 0xba, 0xa3, \ + 0xff, 0x05, 0x40, 0xc4, 0x60, 0x05, 0x39, 0x31, 0x77, 0xf7, 0xa5, 0xca, \ + 0x01, 0x31, 0x80, 0xa7, 0xe1, 0xd1, 0x0a, 0xa2, 0x7c, 0xd5, 0x1c, 0xba, \ + 0xd0, 0x23, 0x4a, 0xd6, 0x30, 0xf3, 0x93, 0xc7, 0x6f, 0xe8, 0xce, 0x94, \ + 0x1e, 0x84, 0xbb, 0x44, 0x81, 0x62, 0x33, 0xff, 0x6b, 0x5d, 0x00, 0x9b, \ + 0x25, 0xf8, 0x8f, 0x0f, 0x9c, 0x4c, 0x4d, 0xe8, 0xd9, 0xa7, 0x99, 0xf9, \ + 0x51, 0x81, 0xc0, 0x9b, 0x1b, 0x31, 0x0d, 0xa6, 0xb3, 0x7c, 0x0e, 0x45, \ + 0xb8, 0x18, 0x64, 0x7e, 0x89, 0x0a, 0x2b, 0xa8, 0xc3, 0xe0, 0x4a, 0xbd, \ + 0xd4, 0x2f, 0x78, 0xc4, 0x62, 0x9b, 0xe9, 0x7e, 0x3f, 0x56, 0x46, 0x8f, \ + 0x17, 0xb7, 0x2a, 0xa0, 0x10, 0x70, 0xfd, 0xb1, 0xf1, 0x6b, 0x05, 0xdc, \ + 0xd1, 0x41, 0x0f, 0x8e, 0xa6, 0xb2, 0x88, 0x1a, 0x42, 0x61, 0x4f, 0xeb, \ + 0x26, 0x85, 0x59, 0x80, 0xba, 0x85, 0x54, 0xfe, 0xcf, 0xc7, 0x7b, 0x2f, \ + 0x6b, 0x59, 0xce, 0xac, 0xdc, 0x7c, 0xac, 0xf3, 0xc8, 0xd6, 0x12, 0x7e, \ + 0x64, 0xe8, 0x3c, 0x99, 0xa8, 0x8f, 0x4f, 0x11, 0xd9, 0x9c, 0x15, 0x4b, \ + 0x6a, 0x44, 0x92, 0x2d, 0x0c, 0xbf, 0xb1, 0x67, 0x96, 0xc9, 0xac, 0xce, \ + 0xd5, 0x19, 0xeb, 0x6f, 0x18, 0xeb, 0x6e, 0x04, 0x2d, 0x60, 0xac, 0xf4, \ + 0x7b, 0x79, 0xf0, 0x1a, 0x9b, 0xb5, 0xc3, 0x5d, 0xef, 0x7d, 0xc9, 0x05, \ + 0x99, 0x44, 0x81, 0x84, 0x75, 0xc7, 0xec, 0x00, 0x12, 0xfc, 0x7a, 0x4a, \ + 0x0b, 0x82, 0x07, 0xec, 0x6d, 0x86, 0x02, 0x4d, 0xfe, 0x9f, 0xc8, 0x92, \ + 0x48, 0xde, 0xf5, 0xb1, 0x9c, 0xe9, 0xc6, 0x89, 0xd0, 0xc1, 0x56, 0xe8, \ + 0xa4, 0xc6, 0x6a, 0x2e, 0x66, 0xc1, 0x9b, 0xfe, 0xd6, 0x3c, 0xb7 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/server2.crt. */ +/* BEGIN FILE string macro TEST_SRV_CRT_RSA_SHA1_PEM tests/data_files/server2.crt */ +#define TEST_SRV_CRT_RSA_SHA1_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ + "MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ + "MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" \ + "A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" \ + "AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" \ + "owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" \ + "NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" \ + "tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" \ + "hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" \ + "HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" \ + "VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" \ + "FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAJklg3Q4\r\n" \ + "cB7v7BzsxM/vLyKccO6op0/gZzM4ghuLq2Y32kl0sM6kSNUUmduuq3u/+GmUZN2A\r\n" \ + "O/7c+Hw7hDFEIvZk98aBGjCLqn3DmgHIv8ToQ67nellQxx2Uj309PdgjNi/r9HOc\r\n" \ + "KNAYPbBcg6MJGWWj2TI6vNaceios/DhOYx5V0j5nfqSJ/pnU0g9Ign2LAhgYpGJE\r\n" \ + "iEM9wW7hEMkwmk0h/sqZsrJsGH5YsF/VThSq/JVO1e2mZH2vruyZKJVBq+8tDNYp\r\n" \ + "HkK6tSyVYQhzIt3StMJWKMl/o5k2AYz6tSC164+1oG+ML3LWg8XrGKa91H4UOKap\r\n" \ + "Awgk0+4m0T25cNs=\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This is taken from tests/data_files/server2.crt.der. */ +/* BEGIN FILE binary macro TEST_SRV_CRT_RSA_SHA1_DER tests/data_files/server2.crt.der */ +#define TEST_SRV_CRT_RSA_SHA1_DER { \ + 0x30, 0x82, 0x03, 0x37, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \ + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x0b, 0x30, \ + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, \ + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, \ + 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, \ + 0x04, 0x03, 0x0c, 0x10, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, \ + 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, \ + 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, 0x30, 0x36, \ + 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, \ + 0x34, 0x30, 0x36, 0x5a, 0x30, 0x34, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, \ + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, \ + 0x53, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, \ + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30, 0x82, \ + 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, \ + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, \ + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc1, 0x4d, 0xa3, 0xdd, 0xe7, \ + 0xcd, 0x1d, 0xd1, 0x04, 0xd7, 0x49, 0x72, 0xb8, 0x99, 0xac, 0x0e, 0x78, \ + 0xe4, 0x3a, 0x3c, 0x4a, 0xcf, 0x3a, 0x13, 0x16, 0xd0, 0x5a, 0xe4, 0xcd, \ + 0xa3, 0x00, 0x88, 0xa7, 0xee, 0x1e, 0x6b, 0x96, 0xa7, 0x52, 0xb4, 0x90, \ + 0xef, 0x2d, 0x72, 0x7a, 0x3e, 0x24, 0x9a, 0xfc, 0xb6, 0x34, 0xac, 0x24, \ + 0xf5, 0x77, 0xe0, 0x26, 0x64, 0x8c, 0x9c, 0xb0, 0x28, 0x7d, 0xa1, 0xda, \ + 0xea, 0x8c, 0xe6, 0xc9, 0x1c, 0x96, 0xbc, 0xfe, 0xc1, 0x04, 0x52, 0xb3, \ + 0x36, 0xd4, 0xa3, 0xfa, 0xe1, 0xb1, 0x76, 0xd8, 0x90, 0xc1, 0x61, 0xb4, \ + 0x66, 0x52, 0x36, 0xa2, 0x26, 0x53, 0xaa, 0xab, 0x74, 0x5e, 0x07, 0x7d, \ + 0x19, 0x82, 0xdb, 0x2a, 0xd8, 0x1f, 0xa0, 0xd9, 0x0d, 0x1c, 0x2d, 0x49, \ + 0x66, 0xf7, 0x5b, 0x25, 0x73, 0x46, 0xe8, 0x0b, 0x8a, 0x4f, 0x69, 0x0c, \ + 0xb5, 0x00, 0x90, 0xe1, 0xda, 0x82, 0x10, 0x66, 0x7d, 0xae, 0x54, 0x2b, \ + 0x8b, 0x65, 0x79, 0x91, 0xa1, 0xe2, 0x61, 0xc3, 0xcd, 0x40, 0x49, 0x08, \ + 0xee, 0x68, 0x0c, 0xf1, 0x8b, 0x86, 0xd2, 0x46, 0xbf, 0xd0, 0xb8, 0xaa, \ + 0x11, 0x03, 0x1e, 0x7f, 0x56, 0xa8, 0x1a, 0x1e, 0x44, 0x18, 0x0f, 0x0f, \ + 0x85, 0x8b, 0xda, 0x8b, 0x44, 0x5e, 0xe2, 0x18, 0xc6, 0x62, 0x2f, 0xc7, \ + 0x66, 0x8d, 0xfa, 0x5d, 0xd8, 0x7d, 0xf3, 0x27, 0x89, 0x29, 0x01, 0xc5, \ + 0x90, 0x0e, 0x3f, 0x27, 0xf1, 0x30, 0xc8, 0x4a, 0x0e, 0xef, 0xd6, 0xde, \ + 0xc7, 0xc7, 0x27, 0x6b, 0xc7, 0x05, 0x3d, 0x7a, 0xc4, 0x02, 0x3c, 0x9a, \ + 0x1d, 0x3e, 0x0f, 0xe8, 0x34, 0x98, 0x5b, 0xcb, 0x73, 0x4b, 0x52, 0x96, \ + 0xd8, 0x11, 0xa2, 0x2c, 0x80, 0x88, 0x69, 0x39, 0x5a, 0xd3, 0x0f, 0xb0, \ + 0xde, 0x59, 0x2f, 0x11, 0xc7, 0xf7, 0xea, 0x12, 0x01, 0x30, 0x97, 0x02, \ + 0x03, 0x01, 0x00, 0x01, 0xa3, 0x4d, 0x30, 0x4b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, \ + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa5, 0x05, 0xe8, 0x64, 0xb8, 0xdc, \ + 0xdf, 0x60, 0x0f, 0x50, 0x12, 0x4d, 0x60, 0xa8, 0x64, 0xaf, 0x4d, 0x8b, \ + 0x43, 0x93, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, \ + 0x16, 0x80, 0x14, 0xb4, 0x5a, 0xe4, 0xa5, 0xb3, 0xde, 0xd2, 0x52, 0xf6, \ + 0xb9, 0xd5, 0xa6, 0x95, 0x0f, 0xeb, 0x3e, 0xbc, 0xc7, 0xfd, 0xff, 0x30, \ + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, \ + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x99, 0x25, 0x83, 0x74, 0x38, \ + 0x70, 0x1e, 0xef, 0xec, 0x1c, 0xec, 0xc4, 0xcf, 0xef, 0x2f, 0x22, 0x9c, \ + 0x70, 0xee, 0xa8, 0xa7, 0x4f, 0xe0, 0x67, 0x33, 0x38, 0x82, 0x1b, 0x8b, \ + 0xab, 0x66, 0x37, 0xda, 0x49, 0x74, 0xb0, 0xce, 0xa4, 0x48, 0xd5, 0x14, \ + 0x99, 0xdb, 0xae, 0xab, 0x7b, 0xbf, 0xf8, 0x69, 0x94, 0x64, 0xdd, 0x80, \ + 0x3b, 0xfe, 0xdc, 0xf8, 0x7c, 0x3b, 0x84, 0x31, 0x44, 0x22, 0xf6, 0x64, \ + 0xf7, 0xc6, 0x81, 0x1a, 0x30, 0x8b, 0xaa, 0x7d, 0xc3, 0x9a, 0x01, 0xc8, \ + 0xbf, 0xc4, 0xe8, 0x43, 0xae, 0xe7, 0x7a, 0x59, 0x50, 0xc7, 0x1d, 0x94, \ + 0x8f, 0x7d, 0x3d, 0x3d, 0xd8, 0x23, 0x36, 0x2f, 0xeb, 0xf4, 0x73, 0x9c, \ + 0x28, 0xd0, 0x18, 0x3d, 0xb0, 0x5c, 0x83, 0xa3, 0x09, 0x19, 0x65, 0xa3, \ + 0xd9, 0x32, 0x3a, 0xbc, 0xd6, 0x9c, 0x7a, 0x2a, 0x2c, 0xfc, 0x38, 0x4e, \ + 0x63, 0x1e, 0x55, 0xd2, 0x3e, 0x67, 0x7e, 0xa4, 0x89, 0xfe, 0x99, 0xd4, \ + 0xd2, 0x0f, 0x48, 0x82, 0x7d, 0x8b, 0x02, 0x18, 0x18, 0xa4, 0x62, 0x44, \ + 0x88, 0x43, 0x3d, 0xc1, 0x6e, 0xe1, 0x10, 0xc9, 0x30, 0x9a, 0x4d, 0x21, \ + 0xfe, 0xca, 0x99, 0xb2, 0xb2, 0x6c, 0x18, 0x7e, 0x58, 0xb0, 0x5f, 0xd5, \ + 0x4e, 0x14, 0xaa, 0xfc, 0x95, 0x4e, 0xd5, 0xed, 0xa6, 0x64, 0x7d, 0xaf, \ + 0xae, 0xec, 0x99, 0x28, 0x95, 0x41, 0xab, 0xef, 0x2d, 0x0c, 0xd6, 0x29, \ + 0x1e, 0x42, 0xba, 0xb5, 0x2c, 0x95, 0x61, 0x08, 0x73, 0x22, 0xdd, 0xd2, \ + 0xb4, 0xc2, 0x56, 0x28, 0xc9, 0x7f, 0xa3, 0x99, 0x36, 0x01, 0x8c, 0xfa, \ + 0xb5, 0x20, 0xb5, 0xeb, 0x8f, 0xb5, 0xa0, 0x6f, 0x8c, 0x2f, 0x72, 0xd6, \ + 0x83, 0xc5, 0xeb, 0x18, 0xa6, 0xbd, 0xd4, 0x7e, 0x14, 0x38, 0xa6, 0xa9, \ + 0x03, 0x08, 0x24, 0xd3, 0xee, 0x26, 0xd1, 0x3d, 0xb9, 0x70, 0xdb \ +} +/* END FILE */ + +/* This is taken from tests/data_files/server2.key. */ +/* BEGIN FILE string macro TEST_SRV_KEY_RSA_PEM tests/data_files/server2.key */ +#define TEST_SRV_KEY_RSA_PEM \ + "-----BEGIN RSA PRIVATE KEY-----\r\n" \ + "MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n" \ + "lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n" \ + "2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n" \ + "Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n" \ + "GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n" \ + "y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n" \ + "++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n" \ + "Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n" \ + "/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n" \ + "WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n" \ + "GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n" \ + "TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n" \ + "CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n" \ + "nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n" \ + "AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n" \ + "sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n" \ + "mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n" \ + "BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n" \ + "whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n" \ + "vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n" \ + "3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n" \ + "3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n" \ + "ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n" \ + "4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n" \ + "TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n" \ + "-----END RSA PRIVATE KEY-----\r\n" +/* END FILE */ + +/* This was generated from tests/data_files/server2.key.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_SRV_KEY_RSA_DER tests/data_files/server2.key.der */ +#define TEST_SRV_KEY_RSA_DER { \ + 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, \ + 0xc1, 0x4d, 0xa3, 0xdd, 0xe7, 0xcd, 0x1d, 0xd1, 0x04, 0xd7, 0x49, 0x72, \ + 0xb8, 0x99, 0xac, 0x0e, 0x78, 0xe4, 0x3a, 0x3c, 0x4a, 0xcf, 0x3a, 0x13, \ + 0x16, 0xd0, 0x5a, 0xe4, 0xcd, 0xa3, 0x00, 0x88, 0xa7, 0xee, 0x1e, 0x6b, \ + 0x96, 0xa7, 0x52, 0xb4, 0x90, 0xef, 0x2d, 0x72, 0x7a, 0x3e, 0x24, 0x9a, \ + 0xfc, 0xb6, 0x34, 0xac, 0x24, 0xf5, 0x77, 0xe0, 0x26, 0x64, 0x8c, 0x9c, \ + 0xb0, 0x28, 0x7d, 0xa1, 0xda, 0xea, 0x8c, 0xe6, 0xc9, 0x1c, 0x96, 0xbc, \ + 0xfe, 0xc1, 0x04, 0x52, 0xb3, 0x36, 0xd4, 0xa3, 0xfa, 0xe1, 0xb1, 0x76, \ + 0xd8, 0x90, 0xc1, 0x61, 0xb4, 0x66, 0x52, 0x36, 0xa2, 0x26, 0x53, 0xaa, \ + 0xab, 0x74, 0x5e, 0x07, 0x7d, 0x19, 0x82, 0xdb, 0x2a, 0xd8, 0x1f, 0xa0, \ + 0xd9, 0x0d, 0x1c, 0x2d, 0x49, 0x66, 0xf7, 0x5b, 0x25, 0x73, 0x46, 0xe8, \ + 0x0b, 0x8a, 0x4f, 0x69, 0x0c, 0xb5, 0x00, 0x90, 0xe1, 0xda, 0x82, 0x10, \ + 0x66, 0x7d, 0xae, 0x54, 0x2b, 0x8b, 0x65, 0x79, 0x91, 0xa1, 0xe2, 0x61, \ + 0xc3, 0xcd, 0x40, 0x49, 0x08, 0xee, 0x68, 0x0c, 0xf1, 0x8b, 0x86, 0xd2, \ + 0x46, 0xbf, 0xd0, 0xb8, 0xaa, 0x11, 0x03, 0x1e, 0x7f, 0x56, 0xa8, 0x1a, \ + 0x1e, 0x44, 0x18, 0x0f, 0x0f, 0x85, 0x8b, 0xda, 0x8b, 0x44, 0x5e, 0xe2, \ + 0x18, 0xc6, 0x62, 0x2f, 0xc7, 0x66, 0x8d, 0xfa, 0x5d, 0xd8, 0x7d, 0xf3, \ + 0x27, 0x89, 0x29, 0x01, 0xc5, 0x90, 0x0e, 0x3f, 0x27, 0xf1, 0x30, 0xc8, \ + 0x4a, 0x0e, 0xef, 0xd6, 0xde, 0xc7, 0xc7, 0x27, 0x6b, 0xc7, 0x05, 0x3d, \ + 0x7a, 0xc4, 0x02, 0x3c, 0x9a, 0x1d, 0x3e, 0x0f, 0xe8, 0x34, 0x98, 0x5b, \ + 0xcb, 0x73, 0x4b, 0x52, 0x96, 0xd8, 0x11, 0xa2, 0x2c, 0x80, 0x88, 0x69, \ + 0x39, 0x5a, 0xd3, 0x0f, 0xb0, 0xde, 0x59, 0x2f, 0x11, 0xc7, 0xf7, 0xea, \ + 0x12, 0x01, 0x30, 0x97, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, \ + 0x01, 0x00, 0x97, 0x47, 0x44, 0xbc, 0x10, 0x81, 0xc5, 0x18, 0xe4, 0x59, \ + 0xfb, 0xe0, 0x2d, 0x3a, 0x0e, 0x9e, 0x10, 0xdc, 0x43, 0xfb, 0x15, 0x6c, \ + 0xd1, 0xfd, 0x48, 0x78, 0x6c, 0xf9, 0xed, 0x38, 0xe8, 0xdd, 0x09, 0xd7, \ + 0x5f, 0xb5, 0x41, 0x64, 0xd7, 0x63, 0xfa, 0x9d, 0x44, 0x0a, 0xf8, 0x42, \ + 0x13, 0xf1, 0xbb, 0x5e, 0x79, 0x20, 0x53, 0x98, 0x4b, 0x65, 0x7f, 0x86, \ + 0x67, 0x48, 0xe4, 0xcf, 0xfb, 0x6a, 0x24, 0xe2, 0x34, 0xbd, 0x14, 0x9d, \ + 0x2c, 0x16, 0xe2, 0xa4, 0x79, 0xd6, 0xa2, 0xec, 0x81, 0x43, 0x87, 0xbf, \ + 0x03, 0x5c, 0x88, 0x25, 0xd9, 0x41, 0xb6, 0xa5, 0xf1, 0x27, 0x52, 0x84, \ + 0xfe, 0x2b, 0x6e, 0x1d, 0x16, 0xcd, 0x73, 0x88, 0xf8, 0x90, 0xbf, 0x19, \ + 0xfe, 0xbe, 0xa9, 0xbf, 0x09, 0xd3, 0x23, 0x43, 0xd2, 0xc7, 0x61, 0x2a, \ + 0xb3, 0x4e, 0x3c, 0x61, 0xd4, 0xbd, 0xd8, 0xb4, 0xfa, 0xa8, 0x0b, 0xf8, \ + 0x7e, 0x56, 0xcd, 0x0f, 0x13, 0x27, 0xda, 0xe6, 0x3b, 0xb3, 0x8c, 0x9c, \ + 0x4b, 0x84, 0x3c, 0xc3, 0x52, 0x57, 0x9c, 0x27, 0x9a, 0x02, 0x76, 0x26, \ + 0x59, 0x82, 0x39, 0xc3, 0x13, 0xbe, 0x6e, 0xf4, 0x44, 0x2d, 0x1d, 0x8c, \ + 0x73, 0x3e, 0x43, 0x99, 0x59, 0xcb, 0xf2, 0x34, 0x72, 0x9a, 0x5e, 0xa5, \ + 0xeb, 0x9f, 0x36, 0x6d, 0x2b, 0xf9, 0xa2, 0xe7, 0xd1, 0x78, 0x52, 0x1b, \ + 0xc8, 0xf6, 0x5b, 0x41, 0x69, 0x57, 0x81, 0x89, 0xe9, 0xbb, 0xa1, 0xde, \ + 0x19, 0x37, 0x3b, 0x13, 0x5c, 0xca, 0x61, 0x01, 0x86, 0xff, 0xdf, 0x83, \ + 0x41, 0x49, 0x7f, 0xd6, 0xf4, 0x2e, 0x08, 0xfa, 0x90, 0xc2, 0x7c, 0xb4, \ + 0xb5, 0x0a, 0x17, 0xdb, 0x0e, 0x6d, 0x75, 0x8a, 0x5d, 0x31, 0xd5, 0x66, \ + 0xfb, 0x39, 0x0b, 0xb5, 0xb6, 0xa3, 0xcd, 0xd4, 0xef, 0x88, 0x92, 0x5a, \ + 0x4d, 0x6c, 0xcb, 0xea, 0x5b, 0x79, 0x02, 0x81, 0x81, 0x00, 0xdf, 0x3a, \ + 0xf9, 0x25, 0x5e, 0x24, 0x37, 0x26, 0x40, 0x97, 0x2f, 0xe0, 0x4a, 0xba, \ + 0x52, 0x1b, 0x51, 0xaf, 0x84, 0x06, 0x32, 0x24, 0x0c, 0xcf, 0x44, 0xa8, \ + 0x77, 0xa7, 0xad, 0xb5, 0x8c, 0x58, 0xcc, 0xc8, 0x31, 0xb7, 0x0d, 0xbc, \ + 0x08, 0x8a, 0xe0, 0xa6, 0x8c, 0xc2, 0x73, 0xe5, 0x1a, 0x64, 0x92, 0xe8, \ + 0xed, 0x4c, 0x6f, 0x0b, 0xa6, 0xa7, 0xf3, 0x9a, 0xf5, 0x6f, 0x69, 0xca, \ + 0x3c, 0x22, 0xd0, 0x15, 0xa8, 0x20, 0x27, 0x41, 0xf8, 0x43, 0x42, 0x7f, \ + 0xb1, 0x93, 0xa1, 0x04, 0x85, 0xda, 0xa0, 0x1c, 0xd6, 0xc6, 0xf7, 0x8a, \ + 0x9e, 0xea, 0x5c, 0x78, 0xa7, 0x55, 0xc4, 0x6b, 0x05, 0x8b, 0xc0, 0x83, \ + 0xcb, 0xce, 0x83, 0x05, 0xf8, 0xb2, 0x16, 0x2b, 0xdf, 0x06, 0x3f, 0xb8, \ + 0xec, 0x16, 0xda, 0x43, 0x33, 0xc1, 0x8f, 0xb0, 0xb8, 0xac, 0xae, 0xd4, \ + 0x94, 0xb8, 0xda, 0x6f, 0x6a, 0xc3, 0x02, 0x81, 0x81, 0x00, 0xdd, 0xae, \ + 0x00, 0xcd, 0xa0, 0x72, 0x1a, 0x05, 0x8a, 0xee, 0x2f, 0xd4, 0x71, 0x4b, \ + 0xf0, 0x3e, 0xe5, 0xc1, 0xe1, 0x29, 0x8b, 0xa6, 0x67, 0x30, 0x98, 0xe7, \ + 0x12, 0xef, 0xdd, 0x12, 0x01, 0x90, 0x24, 0x58, 0xf0, 0x76, 0x92, 0xe7, \ + 0x3d, 0xbb, 0x23, 0xe1, 0xce, 0xf9, 0xa1, 0xd4, 0x38, 0x1b, 0x3f, 0x20, \ + 0xb3, 0x0f, 0x65, 0x6a, 0x8f, 0x55, 0x57, 0x36, 0xee, 0xb2, 0x84, 0x44, \ + 0xfc, 0x91, 0x88, 0xe1, 0xa4, 0xdd, 0x3b, 0x4a, 0x40, 0x4d, 0x7c, 0x86, \ + 0xed, 0xe1, 0xb5, 0x42, 0xef, 0xb9, 0x61, 0xcd, 0x58, 0x19, 0x77, 0x02, \ + 0xae, 0x58, 0x80, 0xdb, 0x13, 0x3d, 0xc7, 0x1f, 0x9d, 0xed, 0xff, 0xac, \ + 0x98, 0xfc, 0xcd, 0xf9, 0x62, 0x04, 0x83, 0x91, 0x89, 0x0d, 0x86, 0x43, \ + 0x8c, 0x0c, 0xc7, 0x1b, 0x90, 0x4d, 0xbe, 0x2f, 0xc5, 0x7c, 0xcd, 0x42, \ + 0xf5, 0xd3, 0xad, 0x8e, 0xfd, 0x9d, 0x02, 0x81, 0x80, 0x17, 0x4b, 0x79, \ + 0x2a, 0x6c, 0x1b, 0x8d, 0x61, 0xc1, 0x85, 0xc5, 0x6a, 0x3b, 0x82, 0x1c, \ + 0x05, 0x5b, 0xcd, 0xdc, 0x12, 0x25, 0x73, 0x5b, 0x9e, 0xd9, 0x84, 0x57, \ + 0x10, 0x39, 0x71, 0x63, 0x96, 0xf4, 0xaf, 0xc3, 0x78, 0x5d, 0xc7, 0x8c, \ + 0x80, 0xa9, 0x96, 0xd7, 0xc3, 0x87, 0x02, 0x96, 0x71, 0x7e, 0x5f, 0x2e, \ + 0x3c, 0x36, 0xae, 0x59, 0x92, 0xd7, 0x3a, 0x09, 0x78, 0xb9, 0xea, 0x6f, \ + 0xc2, 0x16, 0x42, 0xdc, 0x4b, 0x96, 0xad, 0x2c, 0xb2, 0x20, 0x23, 0x61, \ + 0x2d, 0x8d, 0xb5, 0x02, 0x1e, 0xe1, 0x6c, 0x81, 0x01, 0x3c, 0x5d, 0xcb, \ + 0xdd, 0x9b, 0x0e, 0xc0, 0x2f, 0x94, 0x12, 0xb2, 0xfe, 0x75, 0x75, 0x8b, \ + 0x74, 0x1e, 0x7a, 0x26, 0x0c, 0xb7, 0x81, 0x96, 0x81, 0x79, 0x6e, 0xdb, \ + 0xbc, 0x3a, 0xc4, 0x9e, 0x87, 0x09, 0x6e, 0xa0, 0xa6, 0xec, 0x8b, 0xa4, \ + 0x85, 0x71, 0xce, 0x04, 0xaf, 0x02, 0x81, 0x81, 0x00, 0xc2, 0xa7, 0x47, \ + 0x07, 0x48, 0x6a, 0xc8, 0xd4, 0xb3, 0x20, 0xe1, 0x98, 0xee, 0xff, 0x5a, \ + 0x6f, 0x30, 0x7a, 0xa5, 0x47, 0x40, 0xdc, 0x16, 0x62, 0x42, 0xf1, 0x2c, \ + 0xdc, 0xb8, 0xc7, 0x55, 0xde, 0x07, 0x3c, 0x9d, 0xb1, 0xd0, 0xdf, 0x02, \ + 0x82, 0xb0, 0x48, 0x58, 0xe1, 0x34, 0xab, 0xcf, 0xb4, 0x85, 0x23, 0x26, \ + 0x78, 0x4f, 0x7a, 0x59, 0x6f, 0xfb, 0x8c, 0x3d, 0xdf, 0x3d, 0x6c, 0x02, \ + 0x47, 0x9c, 0xe5, 0x5e, 0x49, 0xf1, 0x05, 0x0b, 0x1f, 0xbf, 0x48, 0x0f, \ + 0xdc, 0x10, 0xb9, 0x3d, 0x1d, 0x10, 0x77, 0x2a, 0x73, 0xf9, 0xdf, 0xbd, \ + 0xcd, 0xf3, 0x1f, 0xeb, 0x6e, 0x64, 0xca, 0x2b, 0x78, 0x4f, 0xf8, 0x73, \ + 0xc2, 0x10, 0xef, 0x79, 0x95, 0x33, 0x1e, 0x79, 0x35, 0x09, 0xff, 0x88, \ + 0x1b, 0xb4, 0x3e, 0x4c, 0xe1, 0x27, 0x2e, 0x75, 0x80, 0x58, 0x11, 0x03, \ + 0x21, 0x23, 0x96, 0x9a, 0xb5, 0x02, 0x81, 0x80, 0x05, 0x12, 0x64, 0x71, \ + 0x83, 0x00, 0x1c, 0xfe, 0xef, 0x83, 0xea, 0xdd, 0x2c, 0xc8, 0x2c, 0x00, \ + 0x62, 0x1e, 0x8f, 0x3a, 0xdb, 0x1c, 0xab, 0xd6, 0x34, 0x8b, 0xd1, 0xb2, \ + 0x5a, 0x4f, 0x3d, 0x37, 0x38, 0x02, 0xe0, 0xd7, 0x70, 0xc1, 0xb0, 0x47, \ + 0xe0, 0x08, 0x1a, 0x84, 0xec, 0x48, 0xc5, 0x7c, 0x76, 0x83, 0x12, 0x67, \ + 0xab, 0x7c, 0x9f, 0x90, 0x97, 0xc8, 0x8f, 0x07, 0xf4, 0xb3, 0x60, 0xf2, \ + 0x3f, 0x49, 0x18, 0xdb, 0x2e, 0x94, 0x6b, 0x53, 0x9e, 0xa2, 0x63, 0xde, \ + 0x63, 0xd9, 0xab, 0x21, 0x2e, 0x2d, 0x0a, 0xe0, 0xd0, 0xe8, 0xba, 0xc4, \ + 0x4c, 0x1e, 0xa5, 0xf5, 0x51, 0xa8, 0xc4, 0x92, 0xf8, 0x7f, 0x21, 0xe7, \ + 0x65, 0xbf, 0x0b, 0xe6, 0x01, 0xaf, 0x9c, 0x1d, 0x5b, 0x6c, 0x3f, 0x1c, \ + 0x2f, 0xa6, 0x0f, 0x68, 0x38, 0x8e, 0x85, 0xc4, 0x6c, 0x78, 0x2f, 0x6f, \ + 0x06, 0x21, 0x2e, 0x56 \ +} +/* END FILE */ + +/* + * Test client Certificates + * + * Test client certificates are defined for each choice + * of the following parameters: + * - PEM or DER encoding + * - RSA or EC key + * + * Things to add: + * - hash type + * - multiple EC curve types + */ + +/* This is taken from tests/data_files/cli2.crt. */ +/* BEGIN FILE string macro TEST_CLI_CRT_EC_PEM tests/data_files/cli2.crt */ +#define TEST_CLI_CRT_EC_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIIB3zCCAWOgAwIBAgIBDTAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw\r\n" \ + "DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJTU0wgVGVzdCBFQyBDQTAe\r\n" \ + "Fw0xOTAyMTAxNDQ0MDBaFw0yOTAyMTAxNDQ0MDBaMEExCzAJBgNVBAYTAk5MMREw\r\n" \ + "DwYDVQQKDAhQb2xhclNTTDEfMB0GA1UEAwwWUG9sYXJTU0wgVGVzdCBDbGllbnQg\r\n" \ + "MjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFflrrFz39Osu5O4gf8Sru7mU6zO\r\n" \ + "VVP2NA7MLuNjJQvfmOLzXGA2lsDVGBRw5X+f1UtFGOWwbNVc+JaPh3Cj5MejTTBL\r\n" \ + "MAkGA1UdEwQCMAAwHQYDVR0OBBYEFHoAX4Zk/OBd5REQO7LmO8QmP8/iMB8GA1Ud\r\n" \ + "IwQYMBaAFJ1tICRJAT8ry3i1Gbx+JMnb+zZ8MAwGCCqGSM49BAMCBQADaAAwZQIx\r\n" \ + "AMqme4DKMldUlplDET9Q6Eptre7uUWKhsLOF+zPkKDlfzpIkJYEFgcloDHGYw80u\r\n" \ + "IgIwNftyPXsabTqMM7iEHgVpX/GRozKklY9yQI/5eoA6gGW7Y+imuGR/oao5ySOb\r\n" \ + "a9Vk\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This is generated from tests/data_files/cli2.crt.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_CLI_CRT_EC_DER tests/data_files/cli2.crt.der */ +#define TEST_CLI_CRT_EC_DER { \ + 0x30, 0x82, 0x01, 0xdf, 0x30, 0x82, 0x01, 0x63, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x01, 0x0d, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, \ + 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, \ + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, \ + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, \ + 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, \ + 0x03, 0x0c, 0x13, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x20, \ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, \ + 0x17, 0x0d, 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, \ + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, \ + 0x34, 0x34, 0x34, 0x30, 0x30, 0x5a, 0x30, 0x41, 0x31, 0x0b, 0x30, 0x09, \ + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, \ + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, \ + 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, \ + 0x03, 0x0c, 0x16, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x20, \ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, \ + 0x32, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, \ + 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, \ + 0x03, 0x42, 0x00, 0x04, 0x57, 0xe5, 0xae, 0xb1, 0x73, 0xdf, 0xd3, 0xac, \ + 0xbb, 0x93, 0xb8, 0x81, 0xff, 0x12, 0xae, 0xee, 0xe6, 0x53, 0xac, 0xce, \ + 0x55, 0x53, 0xf6, 0x34, 0x0e, 0xcc, 0x2e, 0xe3, 0x63, 0x25, 0x0b, 0xdf, \ + 0x98, 0xe2, 0xf3, 0x5c, 0x60, 0x36, 0x96, 0xc0, 0xd5, 0x18, 0x14, 0x70, \ + 0xe5, 0x7f, 0x9f, 0xd5, 0x4b, 0x45, 0x18, 0xe5, 0xb0, 0x6c, 0xd5, 0x5c, \ + 0xf8, 0x96, 0x8f, 0x87, 0x70, 0xa3, 0xe4, 0xc7, 0xa3, 0x4d, 0x30, 0x4b, \ + 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, \ + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x7a, 0x00, \ + 0x5f, 0x86, 0x64, 0xfc, 0xe0, 0x5d, 0xe5, 0x11, 0x10, 0x3b, 0xb2, 0xe6, \ + 0x3b, 0xc4, 0x26, 0x3f, 0xcf, 0xe2, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, \ + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x9d, 0x6d, 0x20, 0x24, 0x49, \ + 0x01, 0x3f, 0x2b, 0xcb, 0x78, 0xb5, 0x19, 0xbc, 0x7e, 0x24, 0xc9, 0xdb, \ + 0xfb, 0x36, 0x7c, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, \ + 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, \ + 0x00, 0xca, 0xa6, 0x7b, 0x80, 0xca, 0x32, 0x57, 0x54, 0x96, 0x99, 0x43, \ + 0x11, 0x3f, 0x50, 0xe8, 0x4a, 0x6d, 0xad, 0xee, 0xee, 0x51, 0x62, 0xa1, \ + 0xb0, 0xb3, 0x85, 0xfb, 0x33, 0xe4, 0x28, 0x39, 0x5f, 0xce, 0x92, 0x24, \ + 0x25, 0x81, 0x05, 0x81, 0xc9, 0x68, 0x0c, 0x71, 0x98, 0xc3, 0xcd, 0x2e, \ + 0x22, 0x02, 0x30, 0x35, 0xfb, 0x72, 0x3d, 0x7b, 0x1a, 0x6d, 0x3a, 0x8c, \ + 0x33, 0xb8, 0x84, 0x1e, 0x05, 0x69, 0x5f, 0xf1, 0x91, 0xa3, 0x32, 0xa4, \ + 0x95, 0x8f, 0x72, 0x40, 0x8f, 0xf9, 0x7a, 0x80, 0x3a, 0x80, 0x65, 0xbb, \ + 0x63, 0xe8, 0xa6, 0xb8, 0x64, 0x7f, 0xa1, 0xaa, 0x39, 0xc9, 0x23, 0x9b, \ + 0x6b, 0xd5, 0x64 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/cli2.key. */ +/* BEGIN FILE string macro TEST_CLI_KEY_EC_PEM tests/data_files/cli2.key */ +#define TEST_CLI_KEY_EC_PEM \ + "-----BEGIN EC PRIVATE KEY-----\r\n" \ + "MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n" \ + "AwEHoUQDQgAEV+WusXPf06y7k7iB/xKu7uZTrM5VU/Y0Dswu42MlC9+Y4vNcYDaW\r\n" \ + "wNUYFHDlf5/VS0UY5bBs1Vz4lo+HcKPkxw==\r\n" \ + "-----END EC PRIVATE KEY-----\r\n" +/* END FILE */ + +/* This is generated from tests/data_files/cli2.key.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_CLI_KEY_EC_DER tests/data_files/cli2.key.der */ +#define TEST_CLI_KEY_EC_DER { \ + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xf6, 0xf7, 0x86, 0x64, 0xf1, \ + 0x67, 0x7f, 0xe6, 0x64, 0x8d, 0xef, 0xca, 0x4e, 0xe9, 0xdd, 0x4d, 0xf0, \ + 0x05, 0xff, 0x96, 0x22, 0x8a, 0x7a, 0x84, 0x38, 0x64, 0x17, 0x32, 0x61, \ + 0x98, 0xb7, 0x2a, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, \ + 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x57, 0xe5, 0xae, \ + 0xb1, 0x73, 0xdf, 0xd3, 0xac, 0xbb, 0x93, 0xb8, 0x81, 0xff, 0x12, 0xae, \ + 0xee, 0xe6, 0x53, 0xac, 0xce, 0x55, 0x53, 0xf6, 0x34, 0x0e, 0xcc, 0x2e, \ + 0xe3, 0x63, 0x25, 0x0b, 0xdf, 0x98, 0xe2, 0xf3, 0x5c, 0x60, 0x36, 0x96, \ + 0xc0, 0xd5, 0x18, 0x14, 0x70, 0xe5, 0x7f, 0x9f, 0xd5, 0x4b, 0x45, 0x18, \ + 0xe5, 0xb0, 0x6c, 0xd5, 0x5c, 0xf8, 0x96, 0x8f, 0x87, 0x70, 0xa3, 0xe4, \ + 0xc7 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/cli-rsa-sha256.crt. */ +/* BEGIN FILE string macro TEST_CLI_CRT_RSA_PEM tests/data_files/cli-rsa-sha256.crt */ +#define TEST_CLI_CRT_RSA_PEM \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" \ + "MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ + "MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" \ + "A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n" \ + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n" \ + "M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n" \ + "1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n" \ + "MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n" \ + "4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n" \ + "/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n" \ + "o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITAf\r\n" \ + "BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQsFAAOC\r\n" \ + "AQEAXidv1d4pLlBiKWED95rMycBdgDcgyNqJxakFkRfRyA2y1mlyTn7uBXRkNLY5\r\n" \ + "ZFzK82GCjk2Q2OD4RZSCPAJJqLpHHU34t71ciffvy2KK81YvrxczRhMAE64i+qna\r\n" \ + "yP3Td2XuWJR05PVPoSemsNELs9gWttdnYy3ce+EY2Y0n7Rsi7982EeLIAA7H6ca4\r\n" \ + "2Es/NUH//JZJT32OP0doMxeDRA+vplkKqTLLWf7dX26LIriBkBaRCgR5Yv9LBPFc\r\n" \ + "NOtpzu/LbrY7QFXKJMI+JXDudCsOn8KCmiA4d6Emisqfh3V3485l7HEQNcvLTxlD\r\n" \ + "6zDQyi0/ykYUYZkwQTK1N2Nvlw==\r\n" \ + "-----END CERTIFICATE-----\r\n" +/* END FILE */ + +/* This was generated from tests/data_files/cli-rsa-sha256.crt.der + using `xxd -i.` */ +/* BEGIN FILE binary macro TEST_CLI_CRT_RSA_DER tests/data_files/cli-rsa-sha256.crt.der */ +#define TEST_CLI_CRT_RSA_DER { \ + 0x30, 0x82, 0x03, 0x3f, 0x30, 0x82, 0x02, 0x27, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \ + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x0b, 0x30, \ + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, \ + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, \ + 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, \ + 0x04, 0x03, 0x0c, 0x10, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, \ + 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, \ + 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, 0x34, 0x30, 0x36, \ + 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x32, 0x31, 0x30, 0x31, 0x34, 0x34, \ + 0x34, 0x30, 0x36, 0x5a, 0x30, 0x3c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, \ + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, \ + 0x53, 0x4c, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, \ + 0x11, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6c, \ + 0x69, 0x65, 0x6e, 0x74, 0x20, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, \ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, \ + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, \ + 0x01, 0x01, 0x00, 0xc8, 0x74, 0xc4, 0xcc, 0xb9, 0xf9, 0xb5, 0x79, 0xe9, \ + 0x45, 0xd9, 0x14, 0x60, 0xb0, 0x7d, 0xbb, 0x93, 0xf2, 0x6b, 0x1e, 0x9f, \ + 0x33, 0xad, 0x0d, 0x8f, 0x8a, 0x3c, 0x56, 0x65, 0xe5, 0xdc, 0x44, 0xd9, \ + 0xcc, 0x66, 0x85, 0x07, 0xd5, 0xf8, 0x27, 0xb0, 0x4a, 0x35, 0xd0, 0x63, \ + 0x9e, 0x0a, 0x6e, 0x1b, 0xb7, 0xda, 0xf0, 0x7e, 0xab, 0xee, 0x0c, 0x10, \ + 0x93, 0x86, 0x49, 0x18, 0x34, 0xf3, 0xa8, 0x2a, 0xd2, 0x57, 0xf5, 0x2e, \ + 0xd4, 0x2f, 0x77, 0x29, 0x84, 0x61, 0x4d, 0x82, 0x50, 0x8f, 0xa7, 0x95, \ + 0x48, 0x70, 0xf5, 0x6e, 0x4d, 0xb2, 0xd5, 0x13, 0xc3, 0xd2, 0x1a, 0xed, \ + 0xe6, 0x43, 0xea, 0x42, 0x14, 0xeb, 0x74, 0xea, 0xc0, 0xed, 0x1f, 0xd4, \ + 0x57, 0x4e, 0xa9, 0xf3, 0xa8, 0xed, 0xd2, 0xe0, 0xc1, 0x30, 0x71, 0x30, \ + 0x32, 0x30, 0xd5, 0xd3, 0xf6, 0x08, 0xd0, 0x56, 0x4f, 0x46, 0x8e, 0xf2, \ + 0x5f, 0xf9, 0x3d, 0x67, 0x91, 0x88, 0x30, 0x2e, 0x42, 0xb2, 0xdf, 0x7d, \ + 0xfb, 0xe5, 0x0c, 0x77, 0xff, 0xec, 0x31, 0xc0, 0x78, 0x8f, 0xbf, 0xc2, \ + 0x7f, 0xca, 0xad, 0x6c, 0x21, 0xd6, 0x8d, 0xd9, 0x8b, 0x6a, 0x8e, 0x6f, \ + 0xe0, 0x9b, 0xf8, 0x10, 0x56, 0xcc, 0xb3, 0x8e, 0x13, 0x15, 0xe6, 0x34, \ + 0x04, 0x66, 0xc7, 0xee, 0xf9, 0x36, 0x0e, 0x6a, 0x95, 0xf6, 0x09, 0x9a, \ + 0x06, 0x67, 0xf4, 0x65, 0x71, 0xf8, 0xca, 0xa4, 0xb1, 0x25, 0xe0, 0xfe, \ + 0x3c, 0x8b, 0x35, 0x04, 0x67, 0xba, 0xe0, 0x4f, 0x76, 0x85, 0xfc, 0x7f, \ + 0xfc, 0x36, 0x6b, 0xb5, 0xe9, 0xcd, 0x2d, 0x03, 0x62, 0x4e, 0xb3, 0x3d, \ + 0x00, 0xcf, 0xaf, 0x76, 0xa0, 0x69, 0x56, 0x83, 0x6a, 0xd2, 0xa8, 0xd4, \ + 0xe7, 0x50, 0x71, 0xe6, 0xb5, 0x36, 0x05, 0x77, 0x05, 0x6d, 0x7b, 0xc8, \ + 0xe4, 0xc4, 0xfd, 0x4c, 0xd5, 0x21, 0x5f, 0x02, 0x03, 0x01, 0x00, 0x01, \ + 0xa3, 0x4d, 0x30, 0x4b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, \ + 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, \ + 0x04, 0x14, 0x71, 0xa1, 0x00, 0x73, 0x72, 0x40, 0x2f, 0x54, 0x76, 0x5e, \ + 0x33, 0xfc, 0x52, 0x8f, 0xbc, 0xf1, 0xdd, 0x6b, 0x46, 0x21, 0x30, 0x1f, \ + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb4, \ + 0x5a, 0xe4, 0xa5, 0xb3, 0xde, 0xd2, 0x52, 0xf6, 0xb9, 0xd5, 0xa6, 0x95, \ + 0x0f, 0xeb, 0x3e, 0xbc, 0xc7, 0xfd, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, \ + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, \ + 0x01, 0x01, 0x00, 0x5e, 0x27, 0x6f, 0xd5, 0xde, 0x29, 0x2e, 0x50, 0x62, \ + 0x29, 0x61, 0x03, 0xf7, 0x9a, 0xcc, 0xc9, 0xc0, 0x5d, 0x80, 0x37, 0x20, \ + 0xc8, 0xda, 0x89, 0xc5, 0xa9, 0x05, 0x91, 0x17, 0xd1, 0xc8, 0x0d, 0xb2, \ + 0xd6, 0x69, 0x72, 0x4e, 0x7e, 0xee, 0x05, 0x74, 0x64, 0x34, 0xb6, 0x39, \ + 0x64, 0x5c, 0xca, 0xf3, 0x61, 0x82, 0x8e, 0x4d, 0x90, 0xd8, 0xe0, 0xf8, \ + 0x45, 0x94, 0x82, 0x3c, 0x02, 0x49, 0xa8, 0xba, 0x47, 0x1d, 0x4d, 0xf8, \ + 0xb7, 0xbd, 0x5c, 0x89, 0xf7, 0xef, 0xcb, 0x62, 0x8a, 0xf3, 0x56, 0x2f, \ + 0xaf, 0x17, 0x33, 0x46, 0x13, 0x00, 0x13, 0xae, 0x22, 0xfa, 0xa9, 0xda, \ + 0xc8, 0xfd, 0xd3, 0x77, 0x65, 0xee, 0x58, 0x94, 0x74, 0xe4, 0xf5, 0x4f, \ + 0xa1, 0x27, 0xa6, 0xb0, 0xd1, 0x0b, 0xb3, 0xd8, 0x16, 0xb6, 0xd7, 0x67, \ + 0x63, 0x2d, 0xdc, 0x7b, 0xe1, 0x18, 0xd9, 0x8d, 0x27, 0xed, 0x1b, 0x22, \ + 0xef, 0xdf, 0x36, 0x11, 0xe2, 0xc8, 0x00, 0x0e, 0xc7, 0xe9, 0xc6, 0xb8, \ + 0xd8, 0x4b, 0x3f, 0x35, 0x41, 0xff, 0xfc, 0x96, 0x49, 0x4f, 0x7d, 0x8e, \ + 0x3f, 0x47, 0x68, 0x33, 0x17, 0x83, 0x44, 0x0f, 0xaf, 0xa6, 0x59, 0x0a, \ + 0xa9, 0x32, 0xcb, 0x59, 0xfe, 0xdd, 0x5f, 0x6e, 0x8b, 0x22, 0xb8, 0x81, \ + 0x90, 0x16, 0x91, 0x0a, 0x04, 0x79, 0x62, 0xff, 0x4b, 0x04, 0xf1, 0x5c, \ + 0x34, 0xeb, 0x69, 0xce, 0xef, 0xcb, 0x6e, 0xb6, 0x3b, 0x40, 0x55, 0xca, \ + 0x24, 0xc2, 0x3e, 0x25, 0x70, 0xee, 0x74, 0x2b, 0x0e, 0x9f, 0xc2, 0x82, \ + 0x9a, 0x20, 0x38, 0x77, 0xa1, 0x26, 0x8a, 0xca, 0x9f, 0x87, 0x75, 0x77, \ + 0xe3, 0xce, 0x65, 0xec, 0x71, 0x10, 0x35, 0xcb, 0xcb, 0x4f, 0x19, 0x43, \ + 0xeb, 0x30, 0xd0, 0xca, 0x2d, 0x3f, 0xca, 0x46, 0x14, 0x61, 0x99, 0x30, \ + 0x41, 0x32, 0xb5, 0x37, 0x63, 0x6f, 0x97 \ +} +/* END FILE */ + +/* This is taken from tests/data_files/cli-rsa.key. */ +/* BEGIN FILE string macro TEST_CLI_KEY_RSA_PEM tests/data_files/cli-rsa.key */ +#define TEST_CLI_KEY_RSA_PEM \ + "-----BEGIN RSA PRIVATE KEY-----\r\n" \ + "MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n" \ + "B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n" \ + "bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n" \ + "Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n" \ + "7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n" \ + "dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n" \ + "yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n" \ + "4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n" \ + "ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n" \ + "zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n" \ + "l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n" \ + "DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n" \ + "VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n" \ + "Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n" \ + "wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n" \ + "c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n" \ + "33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n" \ + "ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n" \ + "BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n" \ + "KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n" \ + "UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n" \ + "7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n" \ + "gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n" \ + "bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n" \ + "8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n" \ + "-----END RSA PRIVATE KEY-----\r\n"/* END FILE */ + +/* This was generated from tests/data_files/cli-rsa.key.der using `xxd -i`. */ +/* BEGIN FILE binary macro TEST_CLI_KEY_RSA_DER tests/data_files/cli-rsa.key.der */ +#define TEST_CLI_KEY_RSA_DER { \ + 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, \ + 0xc8, 0x74, 0xc4, 0xcc, 0xb9, 0xf9, 0xb5, 0x79, 0xe9, 0x45, 0xd9, 0x14, \ + 0x60, 0xb0, 0x7d, 0xbb, 0x93, 0xf2, 0x6b, 0x1e, 0x9f, 0x33, 0xad, 0x0d, \ + 0x8f, 0x8a, 0x3c, 0x56, 0x65, 0xe5, 0xdc, 0x44, 0xd9, 0xcc, 0x66, 0x85, \ + 0x07, 0xd5, 0xf8, 0x27, 0xb0, 0x4a, 0x35, 0xd0, 0x63, 0x9e, 0x0a, 0x6e, \ + 0x1b, 0xb7, 0xda, 0xf0, 0x7e, 0xab, 0xee, 0x0c, 0x10, 0x93, 0x86, 0x49, \ + 0x18, 0x34, 0xf3, 0xa8, 0x2a, 0xd2, 0x57, 0xf5, 0x2e, 0xd4, 0x2f, 0x77, \ + 0x29, 0x84, 0x61, 0x4d, 0x82, 0x50, 0x8f, 0xa7, 0x95, 0x48, 0x70, 0xf5, \ + 0x6e, 0x4d, 0xb2, 0xd5, 0x13, 0xc3, 0xd2, 0x1a, 0xed, 0xe6, 0x43, 0xea, \ + 0x42, 0x14, 0xeb, 0x74, 0xea, 0xc0, 0xed, 0x1f, 0xd4, 0x57, 0x4e, 0xa9, \ + 0xf3, 0xa8, 0xed, 0xd2, 0xe0, 0xc1, 0x30, 0x71, 0x30, 0x32, 0x30, 0xd5, \ + 0xd3, 0xf6, 0x08, 0xd0, 0x56, 0x4f, 0x46, 0x8e, 0xf2, 0x5f, 0xf9, 0x3d, \ + 0x67, 0x91, 0x88, 0x30, 0x2e, 0x42, 0xb2, 0xdf, 0x7d, 0xfb, 0xe5, 0x0c, \ + 0x77, 0xff, 0xec, 0x31, 0xc0, 0x78, 0x8f, 0xbf, 0xc2, 0x7f, 0xca, 0xad, \ + 0x6c, 0x21, 0xd6, 0x8d, 0xd9, 0x8b, 0x6a, 0x8e, 0x6f, 0xe0, 0x9b, 0xf8, \ + 0x10, 0x56, 0xcc, 0xb3, 0x8e, 0x13, 0x15, 0xe6, 0x34, 0x04, 0x66, 0xc7, \ + 0xee, 0xf9, 0x36, 0x0e, 0x6a, 0x95, 0xf6, 0x09, 0x9a, 0x06, 0x67, 0xf4, \ + 0x65, 0x71, 0xf8, 0xca, 0xa4, 0xb1, 0x25, 0xe0, 0xfe, 0x3c, 0x8b, 0x35, \ + 0x04, 0x67, 0xba, 0xe0, 0x4f, 0x76, 0x85, 0xfc, 0x7f, 0xfc, 0x36, 0x6b, \ + 0xb5, 0xe9, 0xcd, 0x2d, 0x03, 0x62, 0x4e, 0xb3, 0x3d, 0x00, 0xcf, 0xaf, \ + 0x76, 0xa0, 0x69, 0x56, 0x83, 0x6a, 0xd2, 0xa8, 0xd4, 0xe7, 0x50, 0x71, \ + 0xe6, 0xb5, 0x36, 0x05, 0x77, 0x05, 0x6d, 0x7b, 0xc8, 0xe4, 0xc4, 0xfd, \ + 0x4c, 0xd5, 0x21, 0x5f, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, \ + 0x00, 0x67, 0x4d, 0xb5, 0xf6, 0x03, 0x89, 0xaa, 0x7a, 0x6f, 0x3b, 0x2d, \ + 0xca, 0x10, 0xa2, 0x23, 0xc9, 0xbd, 0x4e, 0xda, 0xe1, 0x67, 0x0e, 0x0c, \ + 0x8a, 0xc6, 0x84, 0x68, 0xdf, 0xe5, 0x97, 0x75, 0xd2, 0x8d, 0xa3, 0x86, \ + 0xd9, 0xdb, 0xd5, 0xeb, 0x13, 0x19, 0x08, 0xc5, 0x7e, 0xe5, 0x37, 0x97, \ + 0x0c, 0x73, 0x80, 0x66, 0x76, 0x35, 0xf1, 0x88, 0xb5, 0xf2, 0xfc, 0xf3, \ + 0xe1, 0x4b, 0x76, 0x4e, 0x73, 0x45, 0xce, 0x2c, 0xc2, 0x10, 0x26, 0x0d, \ + 0x68, 0x0d, 0x9f, 0x49, 0x3d, 0xd6, 0x80, 0x89, 0xe7, 0xc5, 0x49, 0x15, \ + 0xdd, 0x85, 0xc0, 0xc8, 0xfe, 0x82, 0x37, 0x12, 0x5a, 0x0a, 0x6b, 0xf6, \ + 0x68, 0x0d, 0x32, 0x16, 0xbd, 0xa4, 0x15, 0x54, 0x9e, 0x68, 0xa1, 0xad, \ + 0xca, 0x6b, 0xe5, 0x8c, 0xda, 0x76, 0x35, 0x59, 0x2f, 0x9b, 0xb4, 0xe1, \ + 0xf1, 0xf0, 0x50, 0x04, 0xee, 0xc8, 0xec, 0x05, 0xe1, 0xcf, 0x8d, 0xe4, \ + 0xd2, 0x64, 0x7b, 0x5e, 0x63, 0xe0, 0x7b, 0x07, 0xbc, 0x02, 0x96, 0x4e, \ + 0x1b, 0x78, 0x6c, 0xb6, 0x43, 0x9a, 0x32, 0xf6, 0xd6, 0x02, 0xf5, 0x80, \ + 0xcc, 0x26, 0x6e, 0xa5, 0xd0, 0xe3, 0x65, 0x88, 0xce, 0x26, 0xa9, 0x40, \ + 0xe1, 0xe1, 0x00, 0xe0, 0x7f, 0x3f, 0xc3, 0xb1, 0x7c, 0xde, 0xbe, 0x42, \ + 0xba, 0x07, 0x81, 0x13, 0xc2, 0xe0, 0x11, 0x11, 0x23, 0x2c, 0xf8, 0xb2, \ + 0x7a, 0x3a, 0xd4, 0xe4, 0x7d, 0x5f, 0xb9, 0xb1, 0x18, 0xfa, 0x1d, 0x1d, \ + 0x97, 0x91, 0xd9, 0x04, 0x9e, 0xbc, 0xc9, 0xb4, 0xd7, 0x7d, 0x0e, 0x54, \ + 0xf6, 0x8f, 0xd0, 0x28, 0x0d, 0xdd, 0x77, 0x4b, 0x68, 0x04, 0x48, 0x61, \ + 0x75, 0x15, 0x03, 0x1b, 0x35, 0xad, 0x8e, 0xfc, 0x24, 0x11, 0x07, 0xea, \ + 0x17, 0x5a, 0xde, 0x19, 0x68, 0xff, 0xb6, 0x87, 0x7f, 0x80, 0x2a, 0x5f, \ + 0x0c, 0x58, 0xba, 0x5f, 0x41, 0x02, 0x81, 0x81, 0x00, 0xe3, 0x03, 0xaf, \ + 0xfe, 0x98, 0xd2, 0x0b, 0x7b, 0x72, 0xe9, 0x3b, 0x8e, 0xbc, 0xa5, 0xf6, \ + 0xac, 0xe5, 0x22, 0x06, 0xb2, 0xd7, 0x5e, 0xfd, 0x89, 0x4b, 0x16, 0x67, \ + 0x32, 0x83, 0x22, 0x58, 0x8e, 0x62, 0xa4, 0xb4, 0x2d, 0xf9, 0x16, 0x13, \ + 0x54, 0xf6, 0x9f, 0x2f, 0xf9, 0xbb, 0x0e, 0x7e, 0x8c, 0x6f, 0x08, 0xda, \ + 0xc8, 0xe9, 0x1c, 0x66, 0x10, 0x70, 0x93, 0x90, 0x8d, 0xcf, 0x90, 0x3a, \ + 0x43, 0x89, 0x49, 0xeb, 0x83, 0x2a, 0xfe, 0x5a, 0x87, 0xce, 0x74, 0x42, \ + 0x41, 0x0d, 0x8c, 0x73, 0x51, 0xbc, 0x7b, 0x20, 0xc5, 0xfd, 0xf6, 0x0b, \ + 0x65, 0xed, 0xa9, 0x2e, 0xfc, 0x0f, 0xf5, 0x50, 0xf9, 0x8d, 0x37, 0x36, \ + 0x9a, 0x20, 0xdf, 0xc3, 0xe3, 0x27, 0xbc, 0x98, 0x72, 0xc1, 0x14, 0x4b, \ + 0x71, 0xe9, 0x83, 0x14, 0xff, 0x24, 0xe2, 0x14, 0x15, 0xb6, 0x6f, 0x0f, \ + 0x32, 0x9d, 0xd9, 0x98, 0xd1, 0x02, 0x81, 0x81, 0x00, 0xe2, 0x0c, 0xfb, \ + 0xc3, 0x33, 0x9b, 0x47, 0x88, 0x27, 0xf2, 0x26, 0xde, 0xeb, 0x5e, 0xee, \ + 0x40, 0xf6, 0x63, 0x5b, 0x35, 0x23, 0xf5, 0xd5, 0x07, 0x61, 0xdf, 0xa2, \ + 0x9f, 0x58, 0x30, 0x04, 0x22, 0x2b, 0xb4, 0xd9, 0xda, 0x46, 0x7f, 0x48, \ + 0xf5, 0x4f, 0xd0, 0xea, 0xd7, 0xa0, 0x45, 0x8a, 0x62, 0x8b, 0x8c, 0xac, \ + 0x73, 0x5e, 0xfa, 0x36, 0x65, 0x3e, 0xba, 0x6c, 0xba, 0x5e, 0x6b, 0x92, \ + 0x29, 0x5e, 0x6a, 0x0f, 0xd6, 0xd2, 0xa5, 0x95, 0x86, 0xda, 0x72, 0xc5, \ + 0x9e, 0xc9, 0x6b, 0x37, 0x5e, 0x4b, 0x9b, 0x77, 0xe1, 0x67, 0x1a, 0x1e, \ + 0x30, 0xd8, 0x41, 0x68, 0x40, 0xd3, 0x9c, 0xb4, 0xf6, 0xeb, 0x2a, 0x22, \ + 0xdf, 0x78, 0x29, 0xd2, 0x64, 0x92, 0x5b, 0x2f, 0x78, 0x64, 0x4a, 0xa2, \ + 0xa6, 0x6b, 0x3e, 0x50, 0xb1, 0x7a, 0xb1, 0x8d, 0x59, 0xb4, 0x55, 0xba, \ + 0xb6, 0x91, 0x85, 0xa3, 0x2f, 0x02, 0x81, 0x80, 0x10, 0x1e, 0x19, 0xe7, \ + 0xbc, 0x97, 0xe5, 0x22, 0xcd, 0xa4, 0xcb, 0x8a, 0xb5, 0xd0, 0x1e, 0xb4, \ + 0x65, 0xcc, 0x45, 0xa7, 0x7a, 0xed, 0x0e, 0x99, 0x29, 0xd0, 0x9c, 0x61, \ + 0x14, 0xb8, 0x62, 0x8b, 0x31, 0x6b, 0xba, 0x33, 0x2d, 0x65, 0x28, 0xd8, \ + 0x36, 0x6e, 0x54, 0xec, 0xa9, 0x20, 0x3d, 0x51, 0xe1, 0x2c, 0x42, 0xc4, \ + 0x52, 0xf0, 0xa6, 0x3a, 0x72, 0x93, 0xb7, 0x86, 0xa9, 0xfe, 0xf6, 0x74, \ + 0x07, 0x12, 0x4d, 0x7b, 0x51, 0x99, 0x1f, 0x7a, 0x56, 0xe9, 0x20, 0x2f, \ + 0x18, 0x34, 0x29, 0x97, 0xdb, 0x06, 0xee, 0xeb, 0xbf, 0xbd, 0x31, 0x4f, \ + 0xfa, 0x50, 0xb1, 0xba, 0x49, 0xb3, 0xc4, 0x1d, 0x03, 0xae, 0xb0, 0xdc, \ + 0xbe, 0x8a, 0xc4, 0x90, 0xa3, 0x28, 0x9b, 0xb6, 0x42, 0x09, 0x1b, 0xd6, \ + 0x29, 0x9b, 0x19, 0xe9, 0x87, 0x87, 0xd9, 0x9f, 0x35, 0x05, 0xab, 0x91, \ + 0x8f, 0x6d, 0x7c, 0x91, 0x02, 0x81, 0x81, 0x00, 0x94, 0x57, 0xf0, 0xe0, \ + 0x28, 0xfd, 0xbd, 0xf3, 0x9c, 0x43, 0x4d, 0x3e, 0xfd, 0x37, 0x4f, 0x23, \ + 0x52, 0x8d, 0xe1, 0x4c, 0xfe, 0x4c, 0x55, 0x80, 0x82, 0xba, 0x3f, 0xfe, \ + 0x51, 0xe1, 0x30, 0xd5, 0x3b, 0xd9, 0x73, 0x1d, 0xcb, 0x25, 0xbc, 0xbb, \ + 0x3f, 0xa5, 0xda, 0x77, 0xa6, 0xb5, 0xfc, 0x1a, 0xaf, 0x79, 0xa1, 0xb2, \ + 0x14, 0xa2, 0x1f, 0x10, 0x52, 0x1a, 0x05, 0x40, 0x48, 0xb6, 0x4f, 0x34, \ + 0xd6, 0xc0, 0xc3, 0xa4, 0x36, 0x98, 0x73, 0x88, 0x0b, 0xd3, 0x45, 0xdc, \ + 0xee, 0x51, 0x6e, 0x04, 0x73, 0x99, 0x93, 0x12, 0x58, 0x96, 0xcb, 0x39, \ + 0x42, 0xb1, 0xa9, 0xb8, 0xe1, 0x25, 0xf5, 0x9c, 0x14, 0xb7, 0x92, 0x2b, \ + 0x14, 0xb0, 0x5d, 0x61, 0xa2, 0xaa, 0x34, 0x7c, 0xcd, 0x54, 0x2d, 0x69, \ + 0x08, 0xf7, 0xdb, 0xfc, 0x9c, 0x87, 0xe8, 0x3a, 0xf6, 0x1d, 0x4c, 0x6a, \ + 0x83, 0x15, 0x30, 0x01, 0x02, 0x81, 0x81, 0x00, 0x9c, 0x53, 0xa1, 0xb6, \ + 0x2f, 0xc0, 0x06, 0xf5, 0xdf, 0x5c, 0xd1, 0x4a, 0x4e, 0xc8, 0xbd, 0x6d, \ + 0x32, 0xf1, 0x5e, 0xe5, 0x3b, 0x70, 0xd0, 0xa8, 0xe5, 0x41, 0x57, 0x6c, \ + 0x87, 0x53, 0x0f, 0xeb, 0x28, 0xa0, 0x62, 0x8f, 0x43, 0x62, 0xec, 0x2e, \ + 0x6c, 0x71, 0x55, 0x5b, 0x6a, 0xf4, 0x74, 0x14, 0xea, 0x7a, 0x03, 0xf6, \ + 0xfc, 0xa4, 0xce, 0xc4, 0xac, 0xda, 0x1d, 0xf0, 0xb5, 0xa9, 0xfd, 0x11, \ + 0x18, 0x3b, 0x14, 0xa0, 0x90, 0x8d, 0x26, 0xb7, 0x75, 0x73, 0x0a, 0x02, \ + 0x2c, 0x6f, 0x0f, 0xd8, 0x41, 0x78, 0xc3, 0x73, 0x81, 0xac, 0xaa, 0xaf, \ + 0xf2, 0xee, 0x32, 0xb5, 0x8d, 0x05, 0xf9, 0x59, 0x5a, 0x9e, 0x3e, 0x65, \ + 0x9b, 0x74, 0xda, 0xa0, 0x74, 0x95, 0x17, 0x5f, 0x8d, 0x58, 0xfc, 0x8e, \ + 0x4e, 0x2c, 0x1e, 0xbc, 0x81, 0x02, 0x18, 0xac, 0x12, 0xc6, 0xf9, 0x64, \ + 0x8b, 0x87, 0xc3, 0x00 \ +} +/* END FILE */ + +/* + * + * Test certificates and keys as C variables + * + */ + +/* + * CA + */ + +const char mbedtls_test_ca_crt_ec_pem[] = TEST_CA_CRT_EC_PEM; +const char mbedtls_test_ca_key_ec_pem[] = TEST_CA_KEY_EC_PEM; +const char mbedtls_test_ca_pwd_ec_pem[] = TEST_CA_PWD_EC_PEM; +const char mbedtls_test_ca_key_rsa_pem[] = TEST_CA_KEY_RSA_PEM; +const char mbedtls_test_ca_pwd_rsa_pem[] = TEST_CA_PWD_RSA_PEM; +const char mbedtls_test_ca_crt_rsa_sha1_pem[] = TEST_CA_CRT_RSA_SHA1_PEM; +const char mbedtls_test_ca_crt_rsa_sha256_pem[] = TEST_CA_CRT_RSA_SHA256_PEM; + +const unsigned char mbedtls_test_ca_crt_ec_der[] = TEST_CA_CRT_EC_DER; +const unsigned char mbedtls_test_ca_key_ec_der[] = TEST_CA_KEY_EC_DER; +const unsigned char mbedtls_test_ca_key_rsa_der[] = TEST_CA_KEY_RSA_DER; +const unsigned char mbedtls_test_ca_crt_rsa_sha1_der[] = + TEST_CA_CRT_RSA_SHA1_DER; +const unsigned char mbedtls_test_ca_crt_rsa_sha256_der[] = + TEST_CA_CRT_RSA_SHA256_DER; + +const size_t mbedtls_test_ca_crt_ec_pem_len = + sizeof( mbedtls_test_ca_crt_ec_pem ); +const size_t mbedtls_test_ca_key_ec_pem_len = + sizeof( mbedtls_test_ca_key_ec_pem ); +const size_t mbedtls_test_ca_pwd_ec_pem_len = + sizeof( mbedtls_test_ca_pwd_ec_pem ) - 1; +const size_t mbedtls_test_ca_key_rsa_pem_len = + sizeof( mbedtls_test_ca_key_rsa_pem ); +const size_t mbedtls_test_ca_pwd_rsa_pem_len = + sizeof( mbedtls_test_ca_pwd_rsa_pem ) - 1; +const size_t mbedtls_test_ca_crt_rsa_sha1_pem_len = + sizeof( mbedtls_test_ca_crt_rsa_sha1_pem ); +const size_t mbedtls_test_ca_crt_rsa_sha256_pem_len = + sizeof( mbedtls_test_ca_crt_rsa_sha256_pem ); + +const size_t mbedtls_test_ca_crt_ec_der_len = + sizeof( mbedtls_test_ca_crt_ec_der ); +const size_t mbedtls_test_ca_key_ec_der_len = + sizeof( mbedtls_test_ca_key_ec_der ); +const size_t mbedtls_test_ca_pwd_ec_der_len = 0; +const size_t mbedtls_test_ca_key_rsa_der_len = + sizeof( mbedtls_test_ca_key_rsa_der ); +const size_t mbedtls_test_ca_pwd_rsa_der_len = 0; +const size_t mbedtls_test_ca_crt_rsa_sha1_der_len = + sizeof( mbedtls_test_ca_crt_rsa_sha1_der ); +const size_t mbedtls_test_ca_crt_rsa_sha256_der_len = + sizeof( mbedtls_test_ca_crt_rsa_sha256_der ); + +/* + * Server + */ + +const char mbedtls_test_srv_crt_ec_pem[] = TEST_SRV_CRT_EC_PEM; +const char mbedtls_test_srv_key_ec_pem[] = TEST_SRV_KEY_EC_PEM; +const char mbedtls_test_srv_pwd_ec_pem[] = ""; +const char mbedtls_test_srv_key_rsa_pem[] = TEST_SRV_KEY_RSA_PEM; +const char mbedtls_test_srv_pwd_rsa_pem[] = ""; +const char mbedtls_test_srv_crt_rsa_sha1_pem[] = TEST_SRV_CRT_RSA_SHA1_PEM; +const char mbedtls_test_srv_crt_rsa_sha256_pem[] = TEST_SRV_CRT_RSA_SHA256_PEM; + +const unsigned char mbedtls_test_srv_crt_ec_der[] = TEST_SRV_CRT_EC_DER; +const unsigned char mbedtls_test_srv_key_ec_der[] = TEST_SRV_KEY_EC_DER; +const unsigned char mbedtls_test_srv_key_rsa_der[] = TEST_SRV_KEY_RSA_DER; +const unsigned char mbedtls_test_srv_crt_rsa_sha1_der[] = + TEST_SRV_CRT_RSA_SHA1_DER; +const unsigned char mbedtls_test_srv_crt_rsa_sha256_der[] = + TEST_SRV_CRT_RSA_SHA256_DER; + +const size_t mbedtls_test_srv_crt_ec_pem_len = + sizeof( mbedtls_test_srv_crt_ec_pem ); +const size_t mbedtls_test_srv_key_ec_pem_len = + sizeof( mbedtls_test_srv_key_ec_pem ); +const size_t mbedtls_test_srv_pwd_ec_pem_len = + sizeof( mbedtls_test_srv_pwd_ec_pem ) - 1; +const size_t mbedtls_test_srv_key_rsa_pem_len = + sizeof( mbedtls_test_srv_key_rsa_pem ); +const size_t mbedtls_test_srv_pwd_rsa_pem_len = + sizeof( mbedtls_test_srv_pwd_rsa_pem ) - 1; +const size_t mbedtls_test_srv_crt_rsa_sha1_pem_len = + sizeof( mbedtls_test_srv_crt_rsa_sha1_pem ); +const size_t mbedtls_test_srv_crt_rsa_sha256_pem_len = + sizeof( mbedtls_test_srv_crt_rsa_sha256_pem ); + +const size_t mbedtls_test_srv_crt_ec_der_len = + sizeof( mbedtls_test_srv_crt_ec_der ); +const size_t mbedtls_test_srv_key_ec_der_len = + sizeof( mbedtls_test_srv_key_ec_der ); +const size_t mbedtls_test_srv_pwd_ec_der_len = 0; +const size_t mbedtls_test_srv_key_rsa_der_len = + sizeof( mbedtls_test_srv_key_rsa_der ); +const size_t mbedtls_test_srv_pwd_rsa_der_len = 0; +const size_t mbedtls_test_srv_crt_rsa_sha1_der_len = + sizeof( mbedtls_test_srv_crt_rsa_sha1_der ); +const size_t mbedtls_test_srv_crt_rsa_sha256_der_len = + sizeof( mbedtls_test_srv_crt_rsa_sha256_der ); + +/* + * Client + */ + +const char mbedtls_test_cli_crt_ec_pem[] = TEST_CLI_CRT_EC_PEM; +const char mbedtls_test_cli_key_ec_pem[] = TEST_CLI_KEY_EC_PEM; +const char mbedtls_test_cli_pwd_ec_pem[] = ""; +const char mbedtls_test_cli_key_rsa_pem[] = TEST_CLI_KEY_RSA_PEM; +const char mbedtls_test_cli_pwd_rsa_pem[] = ""; +const char mbedtls_test_cli_crt_rsa_pem[] = TEST_CLI_CRT_RSA_PEM; + +const unsigned char mbedtls_test_cli_crt_ec_der[] = TEST_CLI_CRT_EC_DER; +const unsigned char mbedtls_test_cli_key_ec_der[] = TEST_CLI_KEY_EC_DER; +const unsigned char mbedtls_test_cli_key_rsa_der[] = TEST_CLI_KEY_RSA_DER; +const unsigned char mbedtls_test_cli_crt_rsa_der[] = TEST_CLI_CRT_RSA_DER; + +const size_t mbedtls_test_cli_crt_ec_pem_len = + sizeof( mbedtls_test_cli_crt_ec_pem ); +const size_t mbedtls_test_cli_key_ec_pem_len = + sizeof( mbedtls_test_cli_key_ec_pem ); +const size_t mbedtls_test_cli_pwd_ec_pem_len = + sizeof( mbedtls_test_cli_pwd_ec_pem ) - 1; +const size_t mbedtls_test_cli_key_rsa_pem_len = + sizeof( mbedtls_test_cli_key_rsa_pem ); +const size_t mbedtls_test_cli_pwd_rsa_pem_len = + sizeof( mbedtls_test_cli_pwd_rsa_pem ) - 1; +const size_t mbedtls_test_cli_crt_rsa_pem_len = + sizeof( mbedtls_test_cli_crt_rsa_pem ); + +const size_t mbedtls_test_cli_crt_ec_der_len = + sizeof( mbedtls_test_cli_crt_ec_der ); +const size_t mbedtls_test_cli_key_ec_der_len = + sizeof( mbedtls_test_cli_key_ec_der ); +const size_t mbedtls_test_cli_key_rsa_der_len = + sizeof( mbedtls_test_cli_key_rsa_der ); +const size_t mbedtls_test_cli_crt_rsa_der_len = + sizeof( mbedtls_test_cli_crt_rsa_der ); + +/* + * + * Definitions of test CRTs without specification of all parameters, choosing + * them automatically according to the config. For example, mbedtls_test_ca_crt + * is one of mbedtls_test_ca_crt_{rsa|ec}_{sha1|sha256}_{pem|der}. + * + */ + +/* + * Dispatch between PEM and DER according to config + */ + +#if defined(MBEDTLS_PEM_PARSE_C) + +/* PEM encoded test CA certificates and keys */ + +#define TEST_CA_KEY_RSA TEST_CA_KEY_RSA_PEM +#define TEST_CA_PWD_RSA TEST_CA_PWD_RSA_PEM +#define TEST_CA_CRT_RSA_SHA256 TEST_CA_CRT_RSA_SHA256_PEM +#define TEST_CA_CRT_RSA_SHA1 TEST_CA_CRT_RSA_SHA1_PEM +#define TEST_CA_KEY_EC TEST_CA_KEY_EC_PEM +#define TEST_CA_PWD_EC TEST_CA_PWD_EC_PEM +#define TEST_CA_CRT_EC TEST_CA_CRT_EC_PEM + +/* PEM encoded test server certificates and keys */ + +#define TEST_SRV_KEY_RSA TEST_SRV_KEY_RSA_PEM +#define TEST_SRV_PWD_RSA "" +#define TEST_SRV_CRT_RSA_SHA256 TEST_SRV_CRT_RSA_SHA256_PEM +#define TEST_SRV_CRT_RSA_SHA1 TEST_SRV_CRT_RSA_SHA1_PEM +#define TEST_SRV_KEY_EC TEST_SRV_KEY_EC_PEM +#define TEST_SRV_PWD_EC "" +#define TEST_SRV_CRT_EC TEST_SRV_CRT_EC_PEM + +/* PEM encoded test client certificates and keys */ + +#define TEST_CLI_KEY_RSA TEST_CLI_KEY_RSA_PEM +#define TEST_CLI_PWD_RSA "" +#define TEST_CLI_CRT_RSA TEST_CLI_CRT_RSA_PEM +#define TEST_CLI_KEY_EC TEST_CLI_KEY_EC_PEM +#define TEST_CLI_PWD_EC "" +#define TEST_CLI_CRT_EC TEST_CLI_CRT_EC_PEM + +#else /* MBEDTLS_PEM_PARSE_C */ + +/* DER encoded test CA certificates and keys */ + +#define TEST_CA_KEY_RSA TEST_CA_KEY_RSA_DER +#define TEST_CA_PWD_RSA "" +#define TEST_CA_CRT_RSA_SHA256 TEST_CA_CRT_RSA_SHA256_DER +#define TEST_CA_CRT_RSA_SHA1 TEST_CA_CRT_RSA_SHA1_DER +#define TEST_CA_KEY_EC TEST_CA_KEY_EC_DER +#define TEST_CA_PWD_EC "" +#define TEST_CA_CRT_EC TEST_CA_CRT_EC_DER + +/* DER encoded test server certificates and keys */ + +#define TEST_SRV_KEY_RSA TEST_SRV_KEY_RSA_DER +#define TEST_SRV_PWD_RSA "" +#define TEST_SRV_CRT_RSA_SHA256 TEST_SRV_CRT_RSA_SHA256_DER +#define TEST_SRV_CRT_RSA_SHA1 TEST_SRV_CRT_RSA_SHA1_DER +#define TEST_SRV_KEY_EC TEST_SRV_KEY_EC_DER +#define TEST_SRV_PWD_EC "" +#define TEST_SRV_CRT_EC TEST_SRV_CRT_EC_DER + +/* DER encoded test client certificates and keys */ + +#define TEST_CLI_KEY_RSA TEST_CLI_KEY_RSA_DER +#define TEST_CLI_PWD_RSA "" +#define TEST_CLI_CRT_RSA TEST_CLI_CRT_RSA_DER +#define TEST_CLI_KEY_EC TEST_CLI_KEY_EC_DER +#define TEST_CLI_PWD_EC "" +#define TEST_CLI_CRT_EC TEST_CLI_CRT_EC_DER + +#endif /* MBEDTLS_PEM_PARSE_C */ + +const char mbedtls_test_ca_key_rsa[] = TEST_CA_KEY_RSA; +const char mbedtls_test_ca_pwd_rsa[] = TEST_CA_PWD_RSA; +const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256; +const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1; +const char mbedtls_test_ca_key_ec[] = TEST_CA_KEY_EC; +const char mbedtls_test_ca_pwd_ec[] = TEST_CA_PWD_EC; +const char mbedtls_test_ca_crt_ec[] = TEST_CA_CRT_EC; + +const char mbedtls_test_srv_key_rsa[] = TEST_SRV_KEY_RSA; +const char mbedtls_test_srv_pwd_rsa[] = TEST_SRV_PWD_RSA; +const char mbedtls_test_srv_crt_rsa_sha256[] = TEST_SRV_CRT_RSA_SHA256; +const char mbedtls_test_srv_crt_rsa_sha1[] = TEST_SRV_CRT_RSA_SHA1; +const char mbedtls_test_srv_key_ec[] = TEST_SRV_KEY_EC; +const char mbedtls_test_srv_pwd_ec[] = TEST_SRV_PWD_EC; +const char mbedtls_test_srv_crt_ec[] = TEST_SRV_CRT_EC; + +const char mbedtls_test_cli_key_rsa[] = TEST_CLI_KEY_RSA; +const char mbedtls_test_cli_pwd_rsa[] = TEST_CLI_PWD_RSA; +const char mbedtls_test_cli_crt_rsa[] = TEST_CLI_CRT_RSA; +const char mbedtls_test_cli_key_ec[] = TEST_CLI_KEY_EC; +const char mbedtls_test_cli_pwd_ec[] = TEST_CLI_PWD_EC; +const char mbedtls_test_cli_crt_ec[] = TEST_CLI_CRT_EC; + +const size_t mbedtls_test_ca_key_rsa_len = + sizeof( mbedtls_test_ca_key_rsa ); +const size_t mbedtls_test_ca_pwd_rsa_len = + sizeof( mbedtls_test_ca_pwd_rsa ) - 1; +const size_t mbedtls_test_ca_crt_rsa_sha256_len = + sizeof( mbedtls_test_ca_crt_rsa_sha256 ); +const size_t mbedtls_test_ca_crt_rsa_sha1_len = + sizeof( mbedtls_test_ca_crt_rsa_sha1 ); +const size_t mbedtls_test_ca_key_ec_len = + sizeof( mbedtls_test_ca_key_ec ); +const size_t mbedtls_test_ca_pwd_ec_len = + sizeof( mbedtls_test_ca_pwd_ec ) - 1; +const size_t mbedtls_test_ca_crt_ec_len = + sizeof( mbedtls_test_ca_crt_ec ); + +const size_t mbedtls_test_srv_key_rsa_len = + sizeof( mbedtls_test_srv_key_rsa ); +const size_t mbedtls_test_srv_pwd_rsa_len = + sizeof( mbedtls_test_srv_pwd_rsa ) -1; +const size_t mbedtls_test_srv_crt_rsa_sha256_len = + sizeof( mbedtls_test_srv_crt_rsa_sha256 ); +const size_t mbedtls_test_srv_crt_rsa_sha1_len = + sizeof( mbedtls_test_srv_crt_rsa_sha1 ); +const size_t mbedtls_test_srv_key_ec_len = + sizeof( mbedtls_test_srv_key_ec ); +const size_t mbedtls_test_srv_pwd_ec_len = + sizeof( mbedtls_test_srv_pwd_ec ) - 1; +const size_t mbedtls_test_srv_crt_ec_len = + sizeof( mbedtls_test_srv_crt_ec ); + +const size_t mbedtls_test_cli_key_rsa_len = + sizeof( mbedtls_test_cli_key_rsa ); +const size_t mbedtls_test_cli_pwd_rsa_len = + sizeof( mbedtls_test_cli_pwd_rsa ) - 1; +const size_t mbedtls_test_cli_crt_rsa_len = + sizeof( mbedtls_test_cli_crt_rsa ); +const size_t mbedtls_test_cli_key_ec_len = + sizeof( mbedtls_test_cli_key_ec ); +const size_t mbedtls_test_cli_pwd_ec_len = + sizeof( mbedtls_test_cli_pwd_ec ) - 1; +const size_t mbedtls_test_cli_crt_ec_len = + sizeof( mbedtls_test_cli_crt_ec ); + +/* + * Dispatch between SHA-1 and SHA-256 + */ #if defined(MBEDTLS_SHA256_C) -#define TEST_CA_CRT_RSA_SHA256 \ -"-----BEGIN CERTIFICATE-----\r\n" \ -"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" \ -"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ -"MTcwNTA0MTY1NzAxWhcNMjcwNTA1MTY1NzAxWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ -"A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ -"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ -"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ -"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ -"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ -"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ -"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ -"gZUwgZIwHQYDVR0OBBYEFLRa5KWz3tJS9rnVppUP6z68x/3/MGMGA1UdIwRcMFqA\r\n" \ -"FLRa5KWz3tJS9rnVppUP6z68x/3/oT+kPTA7MQswCQYDVQQGEwJOTDERMA8GA1UE\r\n" \ -"CgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0GCAQAwDAYDVR0T\r\n" \ -"BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAHK/HHrTZMnnVMpde1io+voAtql7j\r\n" \ -"4sRhLrjD7o3THtwRbDa2diCvpq0Sq23Ng2LMYoXsOxoL/RQK3iN7UKxV3MKPEr0w\r\n" \ -"XQS+kKQqiT2bsfrjnWMVHZtUOMpm6FNqcdGm/Rss3vKda2lcKl8kUnq/ylc1+QbB\r\n" \ -"G6A6tUvQcr2ZyWfVg+mM5XkhTrOOXus2OLikb4WwEtJTJRNE0f+yPODSUz0/vT57\r\n" \ -"ApH0CnB80bYJshYHPHHymOtleAB8KSYtqm75g/YNobjnjB6cm4HkW3OZRVIl6fYY\r\n" \ -"n20NRVA1Vjs6GAROr4NqW4k/+LofY9y0LLDE+p0oIEKXIsIvhPr39swxSA==\r\n" \ -"-----END CERTIFICATE-----\r\n" - -const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA_SHA256; -const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); -#define TEST_CA_CRT_RSA_SOME - -static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256; +#define TEST_CA_CRT_RSA TEST_CA_CRT_RSA_SHA256 +#define TEST_SRV_CRT_RSA TEST_SRV_CRT_RSA_SHA256 +#else +#define TEST_CA_CRT_RSA TEST_CA_CRT_RSA_SHA1 +#define TEST_SRV_CRT_RSA TEST_SRV_CRT_RSA_SHA1 +#endif /* MBEDTLS_SHA256_C */ -#endif +const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA; +const char mbedtls_test_srv_crt_rsa[] = TEST_SRV_CRT_RSA; -#if !defined(TEST_CA_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C) -#define TEST_CA_CRT_RSA_SHA1 \ -"-----BEGIN CERTIFICATE-----\r\n" \ -"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ -"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ -"MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ -"A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ -"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ -"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ -"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ -"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ -"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ -"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ -"gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH\r\n" \ -"/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV\r\n" \ -"BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz\r\n" \ -"dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ\r\n" \ -"SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H\r\n" \ -"DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF\r\n" \ -"pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf\r\n" \ -"m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ\r\n" \ -"7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n" \ -"-----END CERTIFICATE-----\r\n" - -#if !defined (TEST_CA_CRT_RSA_SOME) -const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA_SHA1; -const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); -#endif +const size_t mbedtls_test_ca_crt_rsa_len = + sizeof( mbedtls_test_ca_crt_rsa ); +const size_t mbedtls_test_srv_crt_rsa_len = + sizeof( mbedtls_test_srv_crt_rsa ); -static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1; +/* + * Dispatch between RSA and EC + */ -#endif +#if defined(MBEDTLS_RSA_C) + +#define TEST_CA_KEY TEST_CA_KEY_RSA +#define TEST_CA_PWD TEST_CA_PWD_RSA +#define TEST_CA_CRT TEST_CA_CRT_RSA + +#define TEST_SRV_KEY TEST_SRV_KEY_RSA +#define TEST_SRV_PWD TEST_SRV_PWD_RSA +#define TEST_SRV_CRT TEST_SRV_CRT_RSA + +#define TEST_CLI_KEY TEST_CLI_KEY_RSA +#define TEST_CLI_PWD TEST_CLI_PWD_RSA +#define TEST_CLI_CRT TEST_CLI_CRT_RSA + +#else /* no RSA, so assume ECDSA */ + +#define TEST_CA_KEY TEST_CA_KEY_EC +#define TEST_CA_PWD TEST_CA_PWD_EC +#define TEST_CA_CRT TEST_CA_CRT_EC + +#define TEST_SRV_KEY TEST_SRV_KEY_EC +#define TEST_SRV_PWD TEST_SRV_PWD_EC +#define TEST_SRV_CRT TEST_SRV_CRT_EC + +#define TEST_CLI_KEY TEST_CLI_KEY_EC +#define TEST_CLI_PWD TEST_CLI_PWD_EC +#define TEST_CLI_CRT TEST_CLI_CRT_EC -const char mbedtls_test_ca_key_rsa[] = -"-----BEGIN RSA PRIVATE KEY-----\r\n" -"Proc-Type: 4,ENCRYPTED\r\n" -"DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n" -"\r\n" -"9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n" -"7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n" -"Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n" -"PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n" -"GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n" -"gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n" -"QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n" -"PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n" -"vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n" -"WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n" -"JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n" -"KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n" -"Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n" -"9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n" -"iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n" -"tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n" -"P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n" -"1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n" -"nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n" -"X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n" -"rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n" -"L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n" -"I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n" -"wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n" -"P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n" -"-----END RSA PRIVATE KEY-----\r\n"; -const size_t mbedtls_test_ca_key_rsa_len = sizeof( mbedtls_test_ca_key_rsa ); - -const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest"; -const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; - -const char mbedtls_test_srv_crt_rsa[] = -"-----BEGIN CERTIFICATE-----\r\n" -"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" -"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" -"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" -"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" -"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" -"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" -"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" -"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" -"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" -"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" -"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" -"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAJxnXClY\r\n" -"oHkbp70cqBrsGXLybA74czbO5RdLEgFs7rHVS9r+c293luS/KdliLScZqAzYVylw\r\n" -"UfRWvKMoWhHYKp3dEIS4xTXk6/5zXxhv9Rw8SGc8qn6vITHk1S1mPevtekgasY5Y\r\n" -"iWQuM3h4YVlRH3HHEMAD1TnAexfXHHDFQGe+Bd1iAbz1/sH9H8l4StwX6egvTK3M\r\n" -"wXRwkKkvjKaEDA9ATbZx0mI8LGsxSuCqe9r9dyjmttd47J1p1Rulz3CLzaRcVIuS\r\n" -"RRQfaD8neM9c1S/iJ/amTVqJxA1KOdOS5780WhPfSArA+g4qAmSjelc3p4wWpha8\r\n" -"zhuYwjVuX6JHG0c=\r\n" -"-----END CERTIFICATE-----\r\n"; -const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa ); - -const char mbedtls_test_srv_key_rsa[] = -"-----BEGIN RSA PRIVATE KEY-----\r\n" -"MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n" -"lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n" -"2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n" -"Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n" -"GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n" -"y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n" -"++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n" -"Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n" -"/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n" -"WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n" -"GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n" -"TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n" -"CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n" -"nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n" -"AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n" -"sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n" -"mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n" -"BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n" -"whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n" -"vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n" -"3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n" -"3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n" -"ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n" -"4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n" -"TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n" -"-----END RSA PRIVATE KEY-----\r\n"; -const size_t mbedtls_test_srv_key_rsa_len = sizeof( mbedtls_test_srv_key_rsa ); - -const char mbedtls_test_cli_crt_rsa[] = -"-----BEGIN CERTIFICATE-----\r\n" -"MIIDhTCCAm2gAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" -"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" -"MTcwNTA1MTMwNzU5WhcNMjcwNTA2MTMwNzU5WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" -"A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n" -"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n" -"M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n" -"1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n" -"MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n" -"4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n" -"/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n" -"o4GSMIGPMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITBjBgNVHSMEXDBa\r\n" -"gBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNV\r\n" -"BAoMCFBvbGFyU1NMMRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBggEAMAkGA1Ud\r\n" -"EwQCMAAwDQYJKoZIhvcNAQELBQADggEBAC7yO786NvcHpK8UovKIG9cB32oSQQom\r\n" -"LoR0eHDRzdqEkoq7yGZufHFiRAAzbMqJfogRtxlrWAeB4y/jGaMBV25IbFOIcH2W\r\n" -"iCEaMMbG+VQLKNvuC63kmw/Zewc9ThM6Pa1Hcy0axT0faf1B/U01j0FIcw/6mTfK\r\n" -"D8w48OIwc1yr0JtutCVjig5DC0yznGMt32RyseOLcUe+lfq005v2PAiCozr5X8rE\r\n" -"ofGZpiM2NqRPePgYy+Vc75Zk28xkRQq1ncprgQb3S4vTsZdScpM9hLf+eMlrgqlj\r\n" -"c5PLSkXBeLE5+fedkyfTaLxxQlgCpuoOhKBm04/R1pWNzUHyqagjO9Q=\r\n" -"-----END CERTIFICATE-----\r\n"; -const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa ); - -const char mbedtls_test_cli_key_rsa[] = -"-----BEGIN RSA PRIVATE KEY-----\r\n" -"MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n" -"B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n" -"bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n" -"Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n" -"7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n" -"dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n" -"yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n" -"4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n" -"ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n" -"zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n" -"l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n" -"DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n" -"VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n" -"Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n" -"wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n" -"c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n" -"33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n" -"ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n" -"BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n" -"KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n" -"UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n" -"7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n" -"gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n" -"bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n" -"8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n" -"-----END RSA PRIVATE KEY-----\r\n"; -const size_t mbedtls_test_cli_key_rsa_len = sizeof( mbedtls_test_cli_key_rsa ); #endif /* MBEDTLS_RSA_C */ -#if defined(MBEDTLS_PEM_PARSE_C) -/* Concatenation of all available CA certificates */ -const char mbedtls_test_cas_pem[] = -#ifdef TEST_CA_CRT_RSA_SHA1 - TEST_CA_CRT_RSA_SHA1 -#endif -#ifdef TEST_CA_CRT_RSA_SHA256 - TEST_CA_CRT_RSA_SHA256 -#endif -#ifdef TEST_CA_CRT_EC - TEST_CA_CRT_EC -#endif - ""; -const size_t mbedtls_test_cas_pem_len = sizeof( mbedtls_test_cas_pem ); -#endif +/* API stability forces us to declare + * mbedtls_test_{ca|srv|cli}_{key|pwd|crt} + * as pointers. */ +static const char test_ca_key[] = TEST_CA_KEY; +static const char test_ca_pwd[] = TEST_CA_PWD; +static const char test_ca_crt[] = TEST_CA_CRT; + +static const char test_srv_key[] = TEST_SRV_KEY; +static const char test_srv_pwd[] = TEST_SRV_PWD; +static const char test_srv_crt[] = TEST_SRV_CRT; + +static const char test_cli_key[] = TEST_CLI_KEY; +static const char test_cli_pwd[] = TEST_CLI_PWD; +static const char test_cli_crt[] = TEST_CLI_CRT; + +const char *mbedtls_test_ca_key = test_ca_key; +const char *mbedtls_test_ca_pwd = test_ca_pwd; +const char *mbedtls_test_ca_crt = test_ca_crt; + +const char *mbedtls_test_srv_key = test_srv_key; +const char *mbedtls_test_srv_pwd = test_srv_pwd; +const char *mbedtls_test_srv_crt = test_srv_crt; + +const char *mbedtls_test_cli_key = test_cli_key; +const char *mbedtls_test_cli_pwd = test_cli_pwd; +const char *mbedtls_test_cli_crt = test_cli_crt; + +const size_t mbedtls_test_ca_key_len = + sizeof( test_ca_key ); +const size_t mbedtls_test_ca_pwd_len = + sizeof( test_ca_pwd ) - 1; +const size_t mbedtls_test_ca_crt_len = + sizeof( test_ca_crt ); -/* List of all available CA certificates */ +const size_t mbedtls_test_srv_key_len = + sizeof( test_srv_key ); +const size_t mbedtls_test_srv_pwd_len = + sizeof( test_srv_pwd ) - 1; +const size_t mbedtls_test_srv_crt_len = + sizeof( test_srv_crt ); + +const size_t mbedtls_test_cli_key_len = + sizeof( test_cli_key ); +const size_t mbedtls_test_cli_pwd_len = + sizeof( test_cli_pwd ) - 1; +const size_t mbedtls_test_cli_crt_len = + sizeof( test_cli_crt ); + +/* + * + * Lists of certificates + * + */ + +/* List of CAs in PEM or DER, depending on config */ const char * mbedtls_test_cas[] = { -#if defined(TEST_CA_CRT_RSA_SHA1) +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_SHA1_C) mbedtls_test_ca_crt_rsa_sha1, #endif -#if defined(TEST_CA_CRT_RSA_SHA256) +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_SHA256_C) mbedtls_test_ca_crt_rsa_sha256, #endif #if defined(MBEDTLS_ECDSA_C) @@ -356,10 +1689,10 @@ const char * mbedtls_test_cas[] = { NULL }; const size_t mbedtls_test_cas_len[] = { -#if defined(TEST_CA_CRT_RSA_SHA1) +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_SHA1_C) sizeof( mbedtls_test_ca_crt_rsa_sha1 ), #endif -#if defined(TEST_CA_CRT_RSA_SHA256) +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_SHA256_C) sizeof( mbedtls_test_ca_crt_rsa_sha256 ), #endif #if defined(MBEDTLS_ECDSA_C) @@ -368,36 +1701,53 @@ const size_t mbedtls_test_cas_len[] = { 0 }; +/* List of all available CA certificates in DER format */ +const unsigned char * mbedtls_test_cas_der[] = { #if defined(MBEDTLS_RSA_C) -const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_rsa; /* SHA1 or SHA256 */ -const char *mbedtls_test_ca_key = mbedtls_test_ca_key_rsa; -const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_rsa; -const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_rsa; -const char *mbedtls_test_srv_key = mbedtls_test_srv_key_rsa; -const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_rsa; -const char *mbedtls_test_cli_key = mbedtls_test_cli_key_rsa; -const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_rsa ); -const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_rsa ); -const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; -const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_rsa ); -const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_rsa ); -const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_rsa ); -const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_rsa ); -#else /* ! MBEDTLS_RSA_C, so MBEDTLS_ECDSA_C */ -const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_ec; -const char *mbedtls_test_ca_key = mbedtls_test_ca_key_ec; -const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_ec; -const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_ec; -const char *mbedtls_test_srv_key = mbedtls_test_srv_key_ec; -const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_ec; -const char *mbedtls_test_cli_key = mbedtls_test_cli_key_ec; -const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_ec ); -const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_ec ); -const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; -const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_ec ); -const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_ec ); -const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_ec ); -const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_ec ); +#if defined(MBEDTLS_SHA256_C) + mbedtls_test_ca_crt_rsa_sha256_der, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA1_C) + mbedtls_test_ca_crt_rsa_sha1_der, +#endif /* MBEDTLS_SHA1_C */ #endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECDSA_C) + mbedtls_test_ca_crt_ec_der, +#endif /* MBEDTLS_ECDSA_C */ + NULL +}; + +const size_t mbedtls_test_cas_der_len[] = { +#if defined(MBEDTLS_RSA_C) +#if defined(MBEDTLS_SHA256_C) + sizeof( mbedtls_test_ca_crt_rsa_sha256_der ), +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA1_C) + sizeof( mbedtls_test_ca_crt_rsa_sha1_der ), +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECDSA_C) + sizeof( mbedtls_test_ca_crt_ec_der ), +#endif /* MBEDTLS_ECDSA_C */ + 0 +}; + +/* Concatenation of all available CA certificates in PEM format */ +#if defined(MBEDTLS_PEM_PARSE_C) +const char mbedtls_test_cas_pem[] = +#if defined(MBEDTLS_RSA_C) +#if defined(MBEDTLS_SHA256_C) + TEST_CA_CRT_RSA_SHA256_PEM +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA1_C) + TEST_CA_CRT_RSA_SHA1_PEM +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECDSA_C) + TEST_CA_CRT_EC_PEM +#endif /* MBEDTLS_ECDSA_C */ + ""; +const size_t mbedtls_test_cas_pem_len = sizeof( mbedtls_test_cas_pem ); +#endif /* MBEDTLS_PEM_PARSE_C */ #endif /* MBEDTLS_CERTS_C */ diff --git a/app/mbedtls/library/chacha20.c b/app/mbedtls/library/chacha20.c new file mode 100644 index 0000000000..8a3610f0e0 --- /dev/null +++ b/app/mbedtls/library/chacha20.c @@ -0,0 +1,570 @@ +/** + * \file chacha20.c + * + * \brief ChaCha20 cipher. + * + * \author Daniel King + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CHACHA20_C) + +#include "mbedtls/chacha20.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CHACHA20_ALT) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define CHACHA20_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) +#define CHACHA20_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define BYTES_TO_U32_LE( data, offset ) \ + ( (uint32_t) (data)[offset] \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \ + ) + +#define ROTL32( value, amount ) \ + ( (uint32_t) ( (value) << (amount) ) | ( (value) >> ( 32 - (amount) ) ) ) + +#define CHACHA20_CTR_INDEX ( 12U ) + +#define CHACHA20_BLOCK_SIZE_BYTES ( 4U * 16U ) + +/** + * \brief ChaCha20 quarter round operation. + * + * The quarter round is defined as follows (from RFC 7539): + * 1. a += b; d ^= a; d <<<= 16; + * 2. c += d; b ^= c; b <<<= 12; + * 3. a += b; d ^= a; d <<<= 8; + * 4. c += d; b ^= c; b <<<= 7; + * + * \param state ChaCha20 state to modify. + * \param a The index of 'a' in the state. + * \param b The index of 'b' in the state. + * \param c The index of 'c' in the state. + * \param d The index of 'd' in the state. + */ +static inline void chacha20_quarter_round( uint32_t state[16], + size_t a, + size_t b, + size_t c, + size_t d ) +{ + /* a += b; d ^= a; d <<<= 16; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32( state[d], 16 ); + + /* c += d; b ^= c; b <<<= 12 */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32( state[b], 12 ); + + /* a += b; d ^= a; d <<<= 8; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32( state[d], 8 ); + + /* c += d; b ^= c; b <<<= 7; */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32( state[b], 7 ); +} + +/** + * \brief Perform the ChaCha20 inner block operation. + * + * This function performs two rounds: the column round and the + * diagonal round. + * + * \param state The ChaCha20 state to update. + */ +static void chacha20_inner_block( uint32_t state[16] ) +{ + chacha20_quarter_round( state, 0, 4, 8, 12 ); + chacha20_quarter_round( state, 1, 5, 9, 13 ); + chacha20_quarter_round( state, 2, 6, 10, 14 ); + chacha20_quarter_round( state, 3, 7, 11, 15 ); + + chacha20_quarter_round( state, 0, 5, 10, 15 ); + chacha20_quarter_round( state, 1, 6, 11, 12 ); + chacha20_quarter_round( state, 2, 7, 8, 13 ); + chacha20_quarter_round( state, 3, 4, 9, 14 ); +} + +/** + * \brief Generates a keystream block. + * + * \param initial_state The initial ChaCha20 state (key, nonce, counter). + * \param keystream Generated keystream bytes are written to this buffer. + */ +static void chacha20_block( const uint32_t initial_state[16], + unsigned char keystream[64] ) +{ + uint32_t working_state[16]; + size_t i; + + memcpy( working_state, + initial_state, + CHACHA20_BLOCK_SIZE_BYTES ); + + for( i = 0U; i < 10U; i++ ) + chacha20_inner_block( working_state ); + + working_state[ 0] += initial_state[ 0]; + working_state[ 1] += initial_state[ 1]; + working_state[ 2] += initial_state[ 2]; + working_state[ 3] += initial_state[ 3]; + working_state[ 4] += initial_state[ 4]; + working_state[ 5] += initial_state[ 5]; + working_state[ 6] += initial_state[ 6]; + working_state[ 7] += initial_state[ 7]; + working_state[ 8] += initial_state[ 8]; + working_state[ 9] += initial_state[ 9]; + working_state[10] += initial_state[10]; + working_state[11] += initial_state[11]; + working_state[12] += initial_state[12]; + working_state[13] += initial_state[13]; + working_state[14] += initial_state[14]; + working_state[15] += initial_state[15]; + + for( i = 0U; i < 16; i++ ) + { + size_t offset = i * 4U; + + keystream[offset ] = (unsigned char)( working_state[i] ); + keystream[offset + 1U] = (unsigned char)( working_state[i] >> 8 ); + keystream[offset + 2U] = (unsigned char)( working_state[i] >> 16 ); + keystream[offset + 3U] = (unsigned char)( working_state[i] >> 24 ); + } + + mbedtls_platform_zeroize( working_state, sizeof( working_state ) ); +} + +void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx ) +{ + CHACHA20_VALIDATE( ctx != NULL ); + + mbedtls_platform_zeroize( ctx->state, sizeof( ctx->state ) ); + mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; +} + +void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx ) +{ + if( ctx != NULL ) + { + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_chacha20_context ) ); + } +} + +int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx, + const unsigned char key[32] ) +{ + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( key != NULL ); + + /* ChaCha20 constants - the string "expand 32-byte k" */ + ctx->state[0] = 0x61707865; + ctx->state[1] = 0x3320646e; + ctx->state[2] = 0x79622d32; + ctx->state[3] = 0x6b206574; + + /* Set key */ + ctx->state[4] = BYTES_TO_U32_LE( key, 0 ); + ctx->state[5] = BYTES_TO_U32_LE( key, 4 ); + ctx->state[6] = BYTES_TO_U32_LE( key, 8 ); + ctx->state[7] = BYTES_TO_U32_LE( key, 12 ); + ctx->state[8] = BYTES_TO_U32_LE( key, 16 ); + ctx->state[9] = BYTES_TO_U32_LE( key, 20 ); + ctx->state[10] = BYTES_TO_U32_LE( key, 24 ); + ctx->state[11] = BYTES_TO_U32_LE( key, 28 ); + + return( 0 ); +} + +int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx, + const unsigned char nonce[12], + uint32_t counter ) +{ + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( nonce != NULL ); + + /* Counter */ + ctx->state[12] = counter; + + /* Nonce */ + ctx->state[13] = BYTES_TO_U32_LE( nonce, 0 ); + ctx->state[14] = BYTES_TO_U32_LE( nonce, 4 ); + ctx->state[15] = BYTES_TO_U32_LE( nonce, 8 ); + + mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; + + return( 0 ); +} + +int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output ) +{ + size_t offset = 0U; + size_t i; + + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( size == 0 || input != NULL ); + CHACHA20_VALIDATE_RET( size == 0 || output != NULL ); + + /* Use leftover keystream bytes, if available */ + while( size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES ) + { + output[offset] = input[offset] + ^ ctx->keystream8[ctx->keystream_bytes_used]; + + ctx->keystream_bytes_used++; + offset++; + size--; + } + + /* Process full blocks */ + while( size >= CHACHA20_BLOCK_SIZE_BYTES ) + { + /* Generate new keystream block and increment counter */ + chacha20_block( ctx->state, ctx->keystream8 ); + ctx->state[CHACHA20_CTR_INDEX]++; + + for( i = 0U; i < 64U; i += 8U ) + { + output[offset + i ] = input[offset + i ] ^ ctx->keystream8[i ]; + output[offset + i+1] = input[offset + i+1] ^ ctx->keystream8[i+1]; + output[offset + i+2] = input[offset + i+2] ^ ctx->keystream8[i+2]; + output[offset + i+3] = input[offset + i+3] ^ ctx->keystream8[i+3]; + output[offset + i+4] = input[offset + i+4] ^ ctx->keystream8[i+4]; + output[offset + i+5] = input[offset + i+5] ^ ctx->keystream8[i+5]; + output[offset + i+6] = input[offset + i+6] ^ ctx->keystream8[i+6]; + output[offset + i+7] = input[offset + i+7] ^ ctx->keystream8[i+7]; + } + + offset += CHACHA20_BLOCK_SIZE_BYTES; + size -= CHACHA20_BLOCK_SIZE_BYTES; + } + + /* Last (partial) block */ + if( size > 0U ) + { + /* Generate new keystream block and increment counter */ + chacha20_block( ctx->state, ctx->keystream8 ); + ctx->state[CHACHA20_CTR_INDEX]++; + + for( i = 0U; i < size; i++) + { + output[offset + i] = input[offset + i] ^ ctx->keystream8[i]; + } + + ctx->keystream_bytes_used = size; + + } + + return( 0 ); +} + +int mbedtls_chacha20_crypt( const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t data_len, + const unsigned char* input, + unsigned char* output ) +{ + mbedtls_chacha20_context ctx; + int ret; + + CHACHA20_VALIDATE_RET( key != NULL ); + CHACHA20_VALIDATE_RET( nonce != NULL ); + CHACHA20_VALIDATE_RET( data_len == 0 || input != NULL ); + CHACHA20_VALIDATE_RET( data_len == 0 || output != NULL ); + + mbedtls_chacha20_init( &ctx ); + + ret = mbedtls_chacha20_setkey( &ctx, key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chacha20_starts( &ctx, nonce, counter ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chacha20_update( &ctx, data_len, input, output ); + +cleanup: + mbedtls_chacha20_free( &ctx ); + return( ret ); +} + +#endif /* !MBEDTLS_CHACHA20_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } +}; + +static const unsigned char test_nonces[2][12] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02 + } +}; + +static const uint32_t test_counters[2] = +{ + 0U, + 1U +}; + +static const unsigned char test_input[2][375] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, + 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, + 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, + 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f + } +}; + +static const unsigned char test_output[2][375] = +{ + { + 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, + 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, + 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, + 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, + 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, + 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, + 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, + 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86 + }, + { + 0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde, + 0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70, + 0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd, + 0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec, + 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15, + 0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05, + 0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f, + 0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d, + 0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa, + 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e, + 0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7, + 0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50, + 0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05, + 0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c, + 0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05, + 0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a, + 0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0, + 0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66, + 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4, + 0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d, + 0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91, + 0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28, + 0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87, + 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b, + 0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2, + 0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f, + 0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76, + 0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c, + 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b, + 0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84, + 0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd, + 0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b, + 0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe, + 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0, + 0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80, + 0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f, + 0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3, + 0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62, + 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91, + 0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6, + 0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64, + 0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85, + 0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41, + 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab, + 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba, + 0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd, + 0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21 + } +}; + +static const size_t test_lengths[2] = +{ + 64U, + 375U +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_chacha20_self_test( int verbose ) +{ + unsigned char output[381]; + unsigned i; + int ret; + + for( i = 0U; i < 2U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ChaCha20 test %u ", i ); + + ret = mbedtls_chacha20_crypt( test_keys[i], + test_nonces[i], + test_counters[i], + test_lengths[i], + test_input[i], + output ); + + ASSERT( 0 == ret, ( "error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( output, test_output[i], test_lengths[i] ), + ( "failed (output)\n" ) ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* !MBEDTLS_CHACHA20_C */ diff --git a/app/mbedtls/library/chachapoly.c b/app/mbedtls/library/chachapoly.c new file mode 100644 index 0000000000..dc643dd618 --- /dev/null +++ b/app/mbedtls/library/chachapoly.c @@ -0,0 +1,540 @@ +/** + * \file chachapoly.c + * + * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539. + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + +#include "mbedtls/chachapoly.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CHACHAPOLY_ALT) + +/* Parameter validation macros */ +#define CHACHAPOLY_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA ) +#define CHACHAPOLY_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define CHACHAPOLY_STATE_INIT ( 0 ) +#define CHACHAPOLY_STATE_AAD ( 1 ) +#define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */ +#define CHACHAPOLY_STATE_FINISHED ( 3 ) + +/** + * \brief Adds nul bytes to pad the AAD for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx ) +{ + uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U ); + unsigned char zeroes[15]; + + if( partial_block_len == 0U ) + return( 0 ); + + memset( zeroes, 0, sizeof( zeroes ) ); + + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len ) ); +} + +/** + * \brief Adds nul bytes to pad the ciphertext for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx ) +{ + uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U ); + unsigned char zeroes[15]; + + if( partial_block_len == 0U ) + return( 0 ); + + memset( zeroes, 0, sizeof( zeroes ) ); + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len ) ); +} + +void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx ) +{ + CHACHAPOLY_VALIDATE( ctx != NULL ); + + mbedtls_chacha20_init( &ctx->chacha20_ctx ); + mbedtls_poly1305_init( &ctx->poly1305_ctx ); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_chacha20_free( &ctx->chacha20_ctx ); + mbedtls_poly1305_free( &ctx->poly1305_ctx ); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx, + const unsigned char key[32] ) +{ + int ret; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( key != NULL ); + + ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key ); + + return( ret ); +} + +int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode ) +{ + int ret; + unsigned char poly1305_key[64]; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + + /* Set counter = 0, will be update to 1 when generating Poly1305 key */ + ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U ); + if( ret != 0 ) + goto cleanup; + + /* Generate the Poly1305 key by getting the ChaCha20 keystream output with + * counter = 0. This is the same as encrypting a buffer of zeroes. + * Only the first 256-bits (32 bytes) of the key is used for Poly1305. + * The other 256 bits are discarded. + */ + memset( poly1305_key, 0, sizeof( poly1305_key ) ); + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ), + poly1305_key, poly1305_key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key ); + + if( ret == 0 ) + { + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_AAD; + ctx->mode = mode; + } + +cleanup: + mbedtls_platform_zeroize( poly1305_key, 64U ); + return( ret ); +} + +int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len ) +{ + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + + if( ctx->state != CHACHAPOLY_STATE_AAD ) + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + + ctx->aad_len += aad_len; + + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) ); +} + +int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL ); + + if( ( ctx->state != CHACHAPOLY_STATE_AAD ) && + ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) ) + { + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + } + + if( ctx->state == CHACHAPOLY_STATE_AAD ) + { + ctx->state = CHACHAPOLY_STATE_CIPHERTEXT; + + ret = chachapoly_pad_aad( ctx ); + if( ret != 0 ) + return( ret ); + } + + ctx->ciphertext_len += len; + + if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT ) + { + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len ); + if( ret != 0 ) + return( ret ); + } + else /* DECRYPT */ + { + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output ); + if( ret != 0 ) + return( ret ); + } + + return( 0 ); +} + +int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, + unsigned char mac[16] ) +{ + int ret; + unsigned char len_block[16]; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( mac != NULL ); + + if( ctx->state == CHACHAPOLY_STATE_INIT ) + { + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + } + + if( ctx->state == CHACHAPOLY_STATE_AAD ) + { + ret = chachapoly_pad_aad( ctx ); + if( ret != 0 ) + return( ret ); + } + else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT ) + { + ret = chachapoly_pad_ciphertext( ctx ); + if( ret != 0 ) + return( ret ); + } + + ctx->state = CHACHAPOLY_STATE_FINISHED; + + /* The lengths of the AAD and ciphertext are processed by + * Poly1305 as the final 128-bit block, encoded as little-endian integers. + */ + len_block[ 0] = (unsigned char)( ctx->aad_len ); + len_block[ 1] = (unsigned char)( ctx->aad_len >> 8 ); + len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 ); + len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 ); + len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 ); + len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 ); + len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 ); + len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 ); + len_block[ 8] = (unsigned char)( ctx->ciphertext_len ); + len_block[ 9] = (unsigned char)( ctx->ciphertext_len >> 8 ); + len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 ); + len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 ); + len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 ); + len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 ); + len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 ); + len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 ); + + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac ); + + return( ret ); +} + +static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx, + mbedtls_chachapoly_mode_t mode, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ) +{ + int ret; + + ret = mbedtls_chachapoly_starts( ctx, nonce, mode ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_update( ctx, length, input, output ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_finish( ctx, tag ); + +cleanup: + return( ret ); +} + +int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ) +{ + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + CHACHAPOLY_VALIDATE_RET( tag != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL ); + + return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT, + length, nonce, aad, aad_len, + input, output, tag ) ); +} + +int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char check_tag[16]; + size_t i; + int diff; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + CHACHAPOLY_VALIDATE_RET( tag != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL ); + + if( ( ret = chachapoly_crypt_and_tag( ctx, + MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce, + aad, aad_len, input, output, check_tag ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < sizeof( check_tag ); i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_platform_zeroize( output, length ); + return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_CHACHAPOLY_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_key[1][32] = +{ + { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + } +}; + +static const unsigned char test_nonce[1][12] = +{ + { + 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */ + } +}; + +static const unsigned char test_aad[1][12] = +{ + { + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7 + } +}; + +static const size_t test_aad_len[1] = +{ + 12U +}; + +static const unsigned char test_input[1][114] = +{ + { + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, + 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, + 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, + 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, + 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, + 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e + } +}; + +static const unsigned char test_output[1][114] = +{ + { + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, + 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, + 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, + 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, + 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, + 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, + 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, + 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16 + } +}; + +static const size_t test_input_len[1] = +{ + 114U +}; + +static const unsigned char test_mac[1][16] = +{ + { + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, + 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 + } +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_chachapoly_self_test( int verbose ) +{ + mbedtls_chachapoly_context ctx; + unsigned i; + int ret; + unsigned char output[200]; + unsigned char mac[16]; + + for( i = 0U; i < 1U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ChaCha20-Poly1305 test %u ", i ); + + mbedtls_chachapoly_init( &ctx ); + + ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] ); + ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) ); + + ret = mbedtls_chachapoly_encrypt_and_tag( &ctx, + test_input_len[i], + test_nonce[i], + test_aad[i], + test_aad_len[i], + test_input[i], + output, + mac ); + + ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ), + ( "failure (wrong output)\n" ) ); + + ASSERT( 0 == memcmp( mac, test_mac[i], 16U ), + ( "failure (wrong MAC)\n" ) ); + + mbedtls_chachapoly_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CHACHAPOLY_C */ diff --git a/app/mbedtls/library/cipher.c b/app/mbedtls/library/cipher.c index bd39e4f097..273997577b 100644 --- a/app/mbedtls/library/cipher.c +++ b/app/mbedtls/library/cipher.c @@ -33,10 +33,15 @@ #include "mbedtls/cipher.h" #include "mbedtls/cipher_internal.h" +#include "mbedtls/platform_util.h" #include #include +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + #if defined(MBEDTLS_GCM_C) #include "mbedtls/gcm.h" #endif @@ -45,6 +50,10 @@ #include "mbedtls/ccm.h" #endif +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + #if defined(MBEDTLS_CMAC_C) #include "mbedtls/cmac.h" #endif @@ -56,10 +65,30 @@ #define mbedtls_free free #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +#define CIPHER_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ) +#define CIPHER_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/* Compare the contents of two buffers in constant time. + * Returns 0 if the contents are bitwise identical, otherwise returns + * a non-zero value. + * This is currently only used by GCM and ChaCha20+Poly1305. + */ +static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len ) +{ + const unsigned char *p1 = (const unsigned char*) v1; + const unsigned char *p2 = (const unsigned char*) v2; + size_t i; + unsigned char diff; + + for( diff = 0, i = 0; i < len; i++ ) + diff |= p1[i] ^ p2[i]; + + return( (int)diff ); } +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ static int supported_init = 0; @@ -126,6 +155,7 @@ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_ciph void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) { + CIPHER_VALIDATE( ctx != NULL ); memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); } @@ -137,7 +167,8 @@ void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) #if defined(MBEDTLS_CMAC_C) if( ctx->cmac_ctx ) { - mbedtls_zeroize( ctx->cmac_ctx, sizeof( mbedtls_cmac_context_t ) ); + mbedtls_platform_zeroize( ctx->cmac_ctx, + sizeof( mbedtls_cmac_context_t ) ); mbedtls_free( ctx->cmac_ctx ); } #endif @@ -145,12 +176,13 @@ void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) if( ctx->cipher_ctx ) ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); - mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); + mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); } int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) { - if( NULL == cipher_info || NULL == ctx ) + CIPHER_VALIDATE_RET( ctx != NULL ); + if( cipher_info == NULL ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); @@ -174,10 +206,16 @@ int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_in return( 0 ); } -int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, - int key_bitlen, const mbedtls_operation_t operation ) +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, + const unsigned char *key, + int key_bitlen, + const mbedtls_operation_t operation ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( key != NULL ); + CIPHER_VALIDATE_RET( operation == MBEDTLS_ENCRYPT || + operation == MBEDTLS_DECRYPT ); + if( ctx->cipher_info == NULL ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && @@ -190,34 +228,34 @@ int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *k ctx->operation = operation; /* - * For CFB and CTR mode always use the encryption key schedule + * For OFB, CFB and CTR mode always use the encryption key schedule */ if( MBEDTLS_ENCRYPT == operation || MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_OFB == ctx->cipher_info->mode || MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) { - return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, - ctx->key_bitlen ); + return( ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, + ctx->key_bitlen ) ); } if( MBEDTLS_DECRYPT == operation ) - return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, - ctx->key_bitlen ); + return( ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, + ctx->key_bitlen ) ); return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, - const unsigned char *iv, size_t iv_len ) + const unsigned char *iv, + size_t iv_len ) { size_t actual_iv_size; - if( NULL == ctx || NULL == ctx->cipher_info ) - return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); - else if( NULL == iv && iv_len != 0 ) - return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); - if( NULL == iv && iv_len == 0 ) - ctx->iv_size = 0; + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); /* avoid buffer overflow in ctx->iv */ if( iv_len > MBEDTLS_MAX_IV_LENGTH ) @@ -233,6 +271,19 @@ int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, if( actual_iv_size > iv_len ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } + +#if defined(MBEDTLS_CHACHA20_C) + if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20 ) + { + if ( 0 != mbedtls_chacha20_starts( (mbedtls_chacha20_context*)ctx->cipher_ctx, + iv, + 0U ) ) /* Initial counter value */ + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + } +#endif + if ( actual_iv_size != 0 ) { memcpy( ctx->iv, iv, actual_iv_size ); @@ -244,7 +295,8 @@ int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + CIPHER_VALIDATE_RET( ctx != NULL ); + if( ctx->cipher_info == NULL ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); ctx->unprocessed_len = 0; @@ -252,33 +304,60 @@ int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) return( 0 ); } -#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, const unsigned char *ad, size_t ad_len ) { - if( NULL == ctx || NULL == ctx->cipher_info ) + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); + if( ctx->cipher_info == NULL ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); +#if defined(MBEDTLS_GCM_C) if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) { - return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, - ctx->iv, ctx->iv_size, ad, ad_len ); + return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, + ctx->iv, ctx->iv_size, ad, ad_len ) ); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + int result; + mbedtls_chachapoly_mode_t mode; + + mode = ( ctx->operation == MBEDTLS_ENCRYPT ) + ? MBEDTLS_CHACHAPOLY_ENCRYPT + : MBEDTLS_CHACHAPOLY_DECRYPT; + + result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ctx->iv, + mode ); + if ( result != 0 ) + return( result ); + + return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ad, ad_len ) ); } +#endif return( 0 ); } -#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen ) { int ret; - size_t block_size = 0; + size_t block_size; - if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) - { + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + if( ctx->cipher_info == NULL ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); - } *olen = 0; block_size = mbedtls_cipher_get_block_size( ctx ); @@ -303,14 +382,23 @@ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *i if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) { *olen = ilen; - return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, - output ); + return( mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, + output ) ); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) + { + *olen = ilen; + return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ilen, input, output ) ); } #endif if ( 0 == block_size ) { - return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT ); } if( input == output && @@ -373,7 +461,7 @@ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *i { if( 0 == block_size ) { - return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT ); } /* Encryption: only cache partial blocks @@ -429,6 +517,21 @@ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *i } #endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) + if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + #if defined(MBEDTLS_CIPHER_MODE_CTR) if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) { @@ -445,6 +548,27 @@ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *i } #endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) + if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS ) + { + if( ctx->unprocessed_len > 0 ) { + /* We can only process an entire data unit at a time. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ); + if( ret != 0 ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + #if defined(MBEDTLS_CIPHER_MODE_STREAM) if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) { @@ -638,19 +762,30 @@ static int get_no_padding( unsigned char *input, size_t input_len, int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen ) { - if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + if( ctx->cipher_info == NULL ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); *olen = 0; if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_OFB == ctx->cipher_info->mode || MBEDTLS_MODE_CTR == ctx->cipher_info->mode || MBEDTLS_MODE_GCM == ctx->cipher_info->mode || + MBEDTLS_MODE_XTS == ctx->cipher_info->mode || MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) { return( 0 ); } + if ( ( MBEDTLS_CIPHER_CHACHA20 == ctx->cipher_info->type ) || + ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) ) + { + return( 0 ); + } + if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) { if( ctx->unprocessed_len != 0 ) @@ -700,8 +835,8 @@ int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, /* Set output size for decryption */ if( MBEDTLS_DECRYPT == ctx->operation ) - return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), - olen ); + return( ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), + olen ) ); /* Set output size for encryption */ *olen = mbedtls_cipher_get_block_size( ctx ); @@ -715,10 +850,12 @@ int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, } #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) -int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ) +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, + mbedtls_cipher_padding_t mode ) { - if( NULL == ctx || - MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) + CIPHER_VALIDATE_RET( ctx != NULL ); + + if( NULL == ctx->cipher_info || MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } @@ -762,18 +899,35 @@ int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_ciph } #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ -#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, unsigned char *tag, size_t tag_len ) { - if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag ) + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + if( ctx->cipher_info == NULL ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); if( MBEDTLS_ENCRYPT != ctx->operation ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); +#if defined(MBEDTLS_GCM_C) if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) - return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len ); + return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, + tag, tag_len ) ); +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* Don't allow truncated MAC for Poly1305 */ + if ( tag_len != 16U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + tag ) ); + } +#endif return( 0 ); } @@ -781,20 +935,22 @@ int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, const unsigned char *tag, size_t tag_len ) { + unsigned char check_tag[16]; int ret; - if( NULL == ctx || NULL == ctx->cipher_info || - MBEDTLS_DECRYPT != ctx->operation ) + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_DECRYPT != ctx->operation ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } +#if defined(MBEDTLS_GCM_C) if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) { - unsigned char check_tag[16]; - size_t i; - int diff; - if( tag_len > sizeof( check_tag ) ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); @@ -805,18 +961,38 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, } /* Check the tag in "constant-time" */ - for( diff = 0, i = 0; i < tag_len; i++ ) - diff |= tag[i] ^ check_tag[i]; + if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* Don't allow truncated MAC for Poly1305 */ + if ( tag_len != sizeof( check_tag ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); - if( diff != 0 ) + ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + check_tag ); + if ( ret != 0 ) + { + return( ret ); + } + + /* Check the tag in "constant-time" */ + if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); return( 0 ); } +#endif /* MBEDTLS_CHACHAPOLY_C */ return( 0 ); } -#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ /* * Packet-oriented wrapper for non-AEAD modes @@ -829,6 +1005,12 @@ int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, int ret; size_t finish_olen; + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) return( ret ); @@ -857,6 +1039,14 @@ int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen, unsigned char *tag, size_t tag_len ) { + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv != NULL ); + CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + #if defined(MBEDTLS_GCM_C) if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) { @@ -875,6 +1065,21 @@ int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, tag, tag_len ) ); } #endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ( ( iv_len != ctx->cipher_info->iv_size ) || + ( tag_len != 16U ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = ilen; + return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx, + ilen, iv, ad, ad_len, input, output, tag ) ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); } @@ -889,6 +1094,14 @@ int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen, const unsigned char *tag, size_t tag_len ) { + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv != NULL ); + CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + #if defined(MBEDTLS_GCM_C) if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) { @@ -921,6 +1134,28 @@ int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, return( ret ); } #endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + int ret; + + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ( ( iv_len != ctx->cipher_info->iv_size ) || + ( tag_len != 16U ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = ilen; + ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen, + iv, ad, ad_len, tag, input, output ); + + if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); } diff --git a/app/mbedtls/library/cipher_wrap.c b/app/mbedtls/library/cipher_wrap.c index dbc5d3fe48..6dd8c5d3a9 100644 --- a/app/mbedtls/library/cipher_wrap.c +++ b/app/mbedtls/library/cipher_wrap.c @@ -33,6 +33,10 @@ #include "mbedtls/cipher_internal.h" +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + #if defined(MBEDTLS_AES_C) #include "mbedtls/aes.h" #endif @@ -45,6 +49,10 @@ #include "mbedtls/camellia.h" #endif +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/aria.h" +#endif + #if defined(MBEDTLS_DES_C) #include "mbedtls/des.h" #endif @@ -53,6 +61,10 @@ #include "mbedtls/blowfish.h" #endif +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + #if defined(MBEDTLS_GCM_C) #include "mbedtls/gcm.h" #endif @@ -138,6 +150,15 @@ static int aes_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, } #endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static int aes_crypt_ofb_wrap( void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ofb( (mbedtls_aes_context *) ctx, length, iv_off, + iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + #if defined(MBEDTLS_CIPHER_MODE_CTR) static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block, @@ -148,6 +169,33 @@ static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, } #endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int aes_crypt_xts_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + int mode; + + switch( operation ) + { + case MBEDTLS_ENCRYPT: + mode = MBEDTLS_AES_ENCRYPT; + break; + case MBEDTLS_DECRYPT: + mode = MBEDTLS_AES_DECRYPT; + break; + default: + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return mbedtls_aes_crypt_xts( xts_ctx, mode, length, + data_unit, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_bitlen ) { @@ -187,9 +235,15 @@ static const mbedtls_cipher_base_t aes_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) aes_crypt_cfb128_wrap, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + aes_crypt_ofb_wrap, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) aes_crypt_ctr_wrap, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -302,6 +356,41 @@ static const mbedtls_cipher_info_t aes_256_cfb128_info = { }; #endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static const mbedtls_cipher_info_t aes_128_ofb_info = { + MBEDTLS_CIPHER_AES_128_OFB, + MBEDTLS_MODE_OFB, + 128, + "AES-128-OFB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ofb_info = { + MBEDTLS_CIPHER_AES_192_OFB, + MBEDTLS_MODE_OFB, + 192, + "AES-192-OFB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ofb_info = { + MBEDTLS_CIPHER_AES_256_OFB, + MBEDTLS_MODE_OFB, + 256, + "AES-256-OFB", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + #if defined(MBEDTLS_CIPHER_MODE_CTR) static const mbedtls_cipher_info_t aes_128_ctr_info = { MBEDTLS_CIPHER_AES_128_CTR, @@ -337,6 +426,92 @@ static const mbedtls_cipher_info_t aes_256_ctr_info = { }; #endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int xts_aes_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return( mbedtls_aes_xts_setkey_enc( xts_ctx, key, key_bitlen ) ); +} + +static int xts_aes_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return( mbedtls_aes_xts_setkey_dec( xts_ctx, key, key_bitlen ) ); +} + +static void *xts_aes_ctx_alloc( void ) +{ + mbedtls_aes_xts_context *xts_ctx = mbedtls_calloc( 1, sizeof( *xts_ctx ) ); + + if( xts_ctx != NULL ) + mbedtls_aes_xts_init( xts_ctx ); + + return( xts_ctx ); +} + +static void xts_aes_ctx_free( void *ctx ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + + if( xts_ctx == NULL ) + return; + + mbedtls_aes_xts_free( xts_ctx ); + mbedtls_free( xts_ctx ); +} + +static const mbedtls_cipher_base_t xts_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + aes_crypt_xts_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + xts_aes_setkey_enc_wrap, + xts_aes_setkey_dec_wrap, + xts_aes_ctx_alloc, + xts_aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_xts_info = { + MBEDTLS_CIPHER_AES_128_XTS, + MBEDTLS_MODE_XTS, + 256, + "AES-128-XTS", + 16, + 0, + 16, + &xts_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_xts_info = { + MBEDTLS_CIPHER_AES_256_XTS, + MBEDTLS_MODE_XTS, + 512, + "AES-256-XTS", + 16, + 0, + 16, + &xts_aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + #if defined(MBEDTLS_GCM_C) static int gcm_aes_setkey_wrap( void *ctx, const unsigned char *key, unsigned int key_bitlen ) @@ -354,9 +529,15 @@ static const mbedtls_cipher_base_t gcm_aes_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -417,9 +598,15 @@ static const mbedtls_cipher_base_t ccm_aes_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -544,9 +731,15 @@ static const mbedtls_cipher_base_t camellia_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) camellia_crypt_cfb128_wrap, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) camellia_crypt_ctr_wrap, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -711,9 +904,15 @@ static const mbedtls_cipher_base_t gcm_camellia_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -774,9 +973,15 @@ static const mbedtls_cipher_base_t ccm_camellia_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -822,6 +1027,382 @@ static const mbedtls_cipher_info_t camellia_256_ccm_info = { #endif /* MBEDTLS_CAMELLIA_C */ +#if defined(MBEDTLS_ARIA_C) + +static int aria_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + (void) operation; + return mbedtls_aria_crypt_ecb( (mbedtls_aria_context *) ctx, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aria_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_cbc( (mbedtls_aria_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aria_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_cfb128( (mbedtls_aria_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aria_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_ctr( (mbedtls_aria_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int aria_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aria_setkey_dec( (mbedtls_aria_context *) ctx, key, key_bitlen ); +} + +static int aria_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aria_setkey_enc( (mbedtls_aria_context *) ctx, key, key_bitlen ); +} + +static void * aria_ctx_alloc( void ) +{ + mbedtls_aria_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_aria_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_aria_init( ctx ); + + return( ctx ); +} + +static void aria_ctx_free( void *ctx ) +{ + mbedtls_aria_free( (mbedtls_aria_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + aria_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aria_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aria_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aria_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aria_setkey_enc_wrap, + aria_setkey_dec_wrap, + aria_ctx_alloc, + aria_ctx_free +}; + +static const mbedtls_cipher_info_t aria_128_ecb_info = { + MBEDTLS_CIPHER_ARIA_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "ARIA-128-ECB", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ecb_info = { + MBEDTLS_CIPHER_ARIA_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "ARIA-192-ECB", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ecb_info = { + MBEDTLS_CIPHER_ARIA_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "ARIA-256-ECB", + 16, + 0, + 16, + &aria_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aria_128_cbc_info = { + MBEDTLS_CIPHER_ARIA_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "ARIA-128-CBC", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_cbc_info = { + MBEDTLS_CIPHER_ARIA_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "ARIA-192-CBC", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_cbc_info = { + MBEDTLS_CIPHER_ARIA_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "ARIA-256-CBC", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aria_128_cfb128_info = { + MBEDTLS_CIPHER_ARIA_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "ARIA-128-CFB128", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_cfb128_info = { + MBEDTLS_CIPHER_ARIA_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "ARIA-192-CFB128", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_cfb128_info = { + MBEDTLS_CIPHER_ARIA_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "ARIA-256-CFB128", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aria_128_ctr_info = { + MBEDTLS_CIPHER_ARIA_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "ARIA-128-CTR", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ctr_info = { + MBEDTLS_CIPHER_ARIA_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "ARIA-192-CTR", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ctr_info = { + MBEDTLS_CIPHER_ARIA_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "ARIA-256-CTR", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aria_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aria_setkey_wrap, + gcm_aria_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_gcm_info = { + MBEDTLS_CIPHER_ARIA_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "ARIA-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; + +static const mbedtls_cipher_info_t aria_192_gcm_info = { + MBEDTLS_CIPHER_ARIA_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "ARIA-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; + +static const mbedtls_cipher_info_t aria_256_gcm_info = { + MBEDTLS_CIPHER_ARIA_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "ARIA-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aria_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aria_setkey_wrap, + ccm_aria_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_ccm_info = { + MBEDTLS_CIPHER_ARIA_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "ARIA-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ccm_info = { + MBEDTLS_CIPHER_ARIA_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "ARIA-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ccm_info = { + MBEDTLS_CIPHER_ARIA_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "ARIA-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_ARIA_C */ + #if defined(MBEDTLS_DES_C) static int des_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, @@ -950,9 +1531,15 @@ static const mbedtls_cipher_base_t des_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -995,9 +1582,15 @@ static const mbedtls_cipher_base_t des_ede_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -1040,9 +1633,15 @@ static const mbedtls_cipher_base_t des_ede3_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -1149,9 +1748,15 @@ static const mbedtls_cipher_base_t blowfish_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) blowfish_crypt_cfb64_wrap, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) blowfish_crypt_ctr_wrap, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) NULL, #endif @@ -1259,9 +1864,15 @@ static const mbedtls_cipher_base_t arc4_base_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) arc4_crypt_stream_wrap, #endif @@ -1283,6 +1894,162 @@ static const mbedtls_cipher_info_t arc4_128_info = { }; #endif /* MBEDTLS_ARC4_C */ +#if defined(MBEDTLS_CHACHA20_C) + +static int chacha20_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + if( key_bitlen != 256U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if ( 0 != mbedtls_chacha20_setkey( (mbedtls_chacha20_context*)ctx, key ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( 0 ); +} + +static int chacha20_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + + ret = mbedtls_chacha20_update( ctx, length, input, output ); + if( ret == MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( ret ); +} + +static void * chacha20_ctx_alloc( void ) +{ + mbedtls_chacha20_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_chacha20_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_chacha20_init( ctx ); + + return( ctx ); +} + +static void chacha20_ctx_free( void *ctx ) +{ + mbedtls_chacha20_free( (mbedtls_chacha20_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t chacha20_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + chacha20_stream_wrap, +#endif + chacha20_setkey_wrap, + chacha20_setkey_wrap, + chacha20_ctx_alloc, + chacha20_ctx_free +}; +static const mbedtls_cipher_info_t chacha20_info = { + MBEDTLS_CIPHER_CHACHA20, + MBEDTLS_MODE_STREAM, + 256, + "CHACHA20", + 12, + 0, + 1, + &chacha20_base_info +}; +#endif /* MBEDTLS_CHACHA20_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + +static int chachapoly_setkey_wrap( void *ctx, + const unsigned char *key, + unsigned int key_bitlen ) +{ + if( key_bitlen != 256U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if ( 0 != mbedtls_chachapoly_setkey( (mbedtls_chachapoly_context*)ctx, key ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( 0 ); +} + +static void * chachapoly_ctx_alloc( void ) +{ + mbedtls_chachapoly_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_chachapoly_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_chachapoly_init( ctx ); + + return( ctx ); +} + +static void chachapoly_ctx_free( void *ctx ) +{ + mbedtls_chachapoly_free( (mbedtls_chachapoly_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t chachapoly_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + chachapoly_setkey_wrap, + chachapoly_setkey_wrap, + chachapoly_ctx_alloc, + chachapoly_ctx_free +}; +static const mbedtls_cipher_info_t chachapoly_info = { + MBEDTLS_CIPHER_CHACHA20_POLY1305, + MBEDTLS_MODE_CHACHAPOLY, + 256, + "CHACHA20-POLY1305", + 12, + 0, + 1, + &chachapoly_base_info +}; +#endif /* MBEDTLS_CHACHAPOLY_C */ + #if defined(MBEDTLS_CIPHER_NULL_CIPHER) static int null_crypt_stream( void *ctx, size_t length, const unsigned char *input, @@ -1322,9 +2089,15 @@ static const mbedtls_cipher_base_t null_base_info = { #if defined(MBEDTLS_CIPHER_MODE_CFB) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) NULL, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif #if defined(MBEDTLS_CIPHER_MODE_STREAM) null_crypt_stream, #endif @@ -1362,11 +2135,20 @@ const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] = { MBEDTLS_CIPHER_AES_192_CFB128, &aes_192_cfb128_info }, { MBEDTLS_CIPHER_AES_256_CFB128, &aes_256_cfb128_info }, #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + { MBEDTLS_CIPHER_AES_128_OFB, &aes_128_ofb_info }, + { MBEDTLS_CIPHER_AES_192_OFB, &aes_192_ofb_info }, + { MBEDTLS_CIPHER_AES_256_OFB, &aes_256_ofb_info }, +#endif #if defined(MBEDTLS_CIPHER_MODE_CTR) { MBEDTLS_CIPHER_AES_128_CTR, &aes_128_ctr_info }, { MBEDTLS_CIPHER_AES_192_CTR, &aes_192_ctr_info }, { MBEDTLS_CIPHER_AES_256_CTR, &aes_256_ctr_info }, #endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + { MBEDTLS_CIPHER_AES_128_XTS, &aes_128_xts_info }, + { MBEDTLS_CIPHER_AES_256_XTS, &aes_256_xts_info }, +#endif #if defined(MBEDTLS_GCM_C) { MBEDTLS_CIPHER_AES_128_GCM, &aes_128_gcm_info }, { MBEDTLS_CIPHER_AES_192_GCM, &aes_192_gcm_info }, @@ -1427,6 +2209,37 @@ const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] = #endif #endif /* MBEDTLS_CAMELLIA_C */ +#if defined(MBEDTLS_ARIA_C) + { MBEDTLS_CIPHER_ARIA_128_ECB, &aria_128_ecb_info }, + { MBEDTLS_CIPHER_ARIA_192_ECB, &aria_192_ecb_info }, + { MBEDTLS_CIPHER_ARIA_256_ECB, &aria_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_ARIA_128_CBC, &aria_128_cbc_info }, + { MBEDTLS_CIPHER_ARIA_192_CBC, &aria_192_cbc_info }, + { MBEDTLS_CIPHER_ARIA_256_CBC, &aria_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_ARIA_128_CFB128, &aria_128_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_192_CFB128, &aria_192_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_256_CFB128, &aria_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_ARIA_128_CTR, &aria_128_ctr_info }, + { MBEDTLS_CIPHER_ARIA_192_CTR, &aria_192_ctr_info }, + { MBEDTLS_CIPHER_ARIA_256_CTR, &aria_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_ARIA_128_GCM, &aria_128_gcm_info }, + { MBEDTLS_CIPHER_ARIA_192_GCM, &aria_192_gcm_info }, + { MBEDTLS_CIPHER_ARIA_256_GCM, &aria_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_ARIA_128_CCM, &aria_128_ccm_info }, + { MBEDTLS_CIPHER_ARIA_192_CCM, &aria_192_ccm_info }, + { MBEDTLS_CIPHER_ARIA_256_CCM, &aria_256_ccm_info }, +#endif +#endif /* MBEDTLS_ARIA_C */ + #if defined(MBEDTLS_DES_C) { MBEDTLS_CIPHER_DES_ECB, &des_ecb_info }, { MBEDTLS_CIPHER_DES_EDE_ECB, &des_ede_ecb_info }, @@ -1438,6 +2251,14 @@ const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] = #endif #endif /* MBEDTLS_DES_C */ +#if defined(MBEDTLS_CHACHA20_C) + { MBEDTLS_CIPHER_CHACHA20, &chacha20_info }, +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + { MBEDTLS_CIPHER_CHACHA20_POLY1305, &chachapoly_info }, +#endif + #if defined(MBEDTLS_CIPHER_NULL_CIPHER) { MBEDTLS_CIPHER_NULL, &null_cipher_info }, #endif /* MBEDTLS_CIPHER_NULL_CIPHER */ diff --git a/app/mbedtls/library/cmac.c b/app/mbedtls/library/cmac.c index 9a73faa6d5..5d101e1c7d 100644 --- a/app/mbedtls/library/cmac.c +++ b/app/mbedtls/library/cmac.c @@ -49,6 +49,7 @@ #if defined(MBEDTLS_CMAC_C) #include "mbedtls/cmac.h" +#include "mbedtls/platform_util.h" #include @@ -67,11 +68,6 @@ #if !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} - /* * Multiplication by u in the Galois field of GF(2^n) * @@ -144,7 +140,7 @@ static int cmac_generate_subkeys( mbedtls_cipher_context_t *ctx, unsigned char L[MBEDTLS_CIPHER_BLKSIZE_MAX]; size_t olen, block_size; - mbedtls_zeroize( L, sizeof( L ) ); + mbedtls_platform_zeroize( L, sizeof( L ) ); block_size = ctx->cipher_info->block_size; @@ -162,7 +158,7 @@ static int cmac_generate_subkeys( mbedtls_cipher_context_t *ctx, goto exit; exit: - mbedtls_zeroize( L, sizeof( L ) ); + mbedtls_platform_zeroize( L, sizeof( L ) ); return( ret ); } @@ -238,7 +234,7 @@ int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, ctx->cmac_ctx = cmac_ctx; - mbedtls_zeroize( cmac_ctx->state, sizeof( cmac_ctx->state ) ); + mbedtls_platform_zeroize( cmac_ctx->state, sizeof( cmac_ctx->state ) ); return 0; } @@ -330,8 +326,8 @@ int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, block_size = ctx->cipher_info->block_size; state = cmac_ctx->state; - mbedtls_zeroize( K1, sizeof( K1 ) ); - mbedtls_zeroize( K2, sizeof( K2 ) ); + mbedtls_platform_zeroize( K1, sizeof( K1 ) ); + mbedtls_platform_zeroize( K2, sizeof( K2 ) ); cmac_generate_subkeys( ctx, K1, K2 ); last_block = cmac_ctx->unprocessed_block; @@ -361,14 +357,14 @@ int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, exit: /* Wipe the generated keys on the stack, and any other transients to avoid * side channel leakage */ - mbedtls_zeroize( K1, sizeof( K1 ) ); - mbedtls_zeroize( K2, sizeof( K2 ) ); + mbedtls_platform_zeroize( K1, sizeof( K1 ) ); + mbedtls_platform_zeroize( K2, sizeof( K2 ) ); cmac_ctx->unprocessed_len = 0; - mbedtls_zeroize( cmac_ctx->unprocessed_block, - sizeof( cmac_ctx->unprocessed_block ) ); + mbedtls_platform_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); - mbedtls_zeroize( state, MBEDTLS_CIPHER_BLKSIZE_MAX ); + mbedtls_platform_zeroize( state, MBEDTLS_CIPHER_BLKSIZE_MAX ); return( ret ); } @@ -383,10 +379,10 @@ int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ) /* Reset the internal state */ cmac_ctx->unprocessed_len = 0; - mbedtls_zeroize( cmac_ctx->unprocessed_block, - sizeof( cmac_ctx->unprocessed_block ) ); - mbedtls_zeroize( cmac_ctx->state, - sizeof( cmac_ctx->state ) ); + mbedtls_platform_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + mbedtls_platform_zeroize( cmac_ctx->state, + sizeof( cmac_ctx->state ) ); return( 0 ); } @@ -466,7 +462,7 @@ int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_length, output ); exit: - mbedtls_zeroize( int_key, sizeof( int_key ) ); + mbedtls_platform_zeroize( int_key, sizeof( int_key ) ); return( ret ); } diff --git a/app/mbedtls/library/ctr_drbg.c b/app/mbedtls/library/ctr_drbg.c index d7a94840cc..32b34e462a 100644 --- a/app/mbedtls/library/ctr_drbg.c +++ b/app/mbedtls/library/ctr_drbg.c @@ -33,6 +33,7 @@ #if defined(MBEDTLS_CTR_DRBG_C) #include "mbedtls/ctr_drbg.h" +#include "mbedtls/platform_util.h" #include @@ -49,11 +50,6 @@ #endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_SELF_TEST */ -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * CTR_DRBG context initialization */ @@ -66,56 +62,6 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ) #endif } -/* - * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow - * NIST tests to succeed (which require known length fixed entropy) - */ -int mbedtls_ctr_drbg_seed_entropy_len( - mbedtls_ctr_drbg_context *ctx, - int (*f_entropy)(void *, unsigned char *, size_t), - void *p_entropy, - const unsigned char *custom, - size_t len, - size_t entropy_len ) -{ - int ret; - unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; - - memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE ); - - mbedtls_aes_init( &ctx->aes_ctx ); - - ctx->f_entropy = f_entropy; - ctx->p_entropy = p_entropy; - - ctx->entropy_len = entropy_len; - ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL; - - /* - * Initialize with an empty key - */ - if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) - { - return( ret ); - } - - if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) - { - return( ret ); - } - return( 0 ); -} - -int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, - int (*f_entropy)(void *, unsigned char *, size_t), - void *p_entropy, - const unsigned char *custom, - size_t len ) -{ - return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len, - MBEDTLS_CTR_DRBG_ENTROPY_LEN ) ); -} - void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ) { if( ctx == NULL ) @@ -125,7 +71,7 @@ void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ) mbedtls_mutex_free( &ctx->mutex ); #endif mbedtls_aes_free( &ctx->aes_ctx ); - mbedtls_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) ); } void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance ) @@ -245,21 +191,29 @@ static int block_cipher_df( unsigned char *output, /* * tidy up the stack */ - mbedtls_zeroize( buf, sizeof( buf ) ); - mbedtls_zeroize( tmp, sizeof( tmp ) ); - mbedtls_zeroize( key, sizeof( key ) ); - mbedtls_zeroize( chain, sizeof( chain ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( chain, sizeof( chain ) ); if( 0 != ret ) { /* * wipe partial seed from memory */ - mbedtls_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN ); + mbedtls_platform_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN ); } return( ret ); } +/* CTR_DRBG_Update (SP 800-90A §10.2.1.2) + * ctr_drbg_update_internal(ctx, provided_data) + * implements + * CTR_DRBG_Update(provided_data, Key, V) + * with inputs and outputs + * ctx->aes_ctx = Key + * ctx->counter = V + */ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] ) { @@ -299,10 +253,22 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE ); exit: - mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); return( ret ); } +/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) + * mbedtls_ctr_drbg_update(ctx, additional, add_len) + * implements + * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string, + * security_strength) -> initial_working_state + * with inputs + * ctx->counter = all-bits-0 + * ctx->aes_ctx = context from all-bits-0 key + * additional[:add_len] = entropy_input || nonce || personalization_string + * and with outputs + * ctx = initial_working_state + */ int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, const unsigned char *additional, size_t add_len ) @@ -319,11 +285,11 @@ int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, goto exit; exit: - mbedtls_zeroize( add_input, sizeof( add_input ) ); + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); return( ret ); } -/* Deprecated function, kept for backward compatibility. */ +#if !defined(MBEDTLS_DEPRECATED_REMOVED) void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, const unsigned char *additional, size_t add_len ) @@ -334,7 +300,20 @@ void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; (void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len ); } - +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/* CTR_DRBG_Reseed with derivation function (SP 800-90A §10.2.1.4.2) + * mbedtls_ctr_drbg_reseed(ctx, additional, len) + * implements + * CTR_DRBG_Reseed(working_state, entropy_input, additional_input) + * -> new_working_state + * with inputs + * ctx contains working_state + * additional[:len] = additional_input + * and entropy_input comes from calling ctx->f_entropy + * and with output + * ctx contains new_working_state + */ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, const unsigned char *additional, size_t len ) { @@ -382,10 +361,86 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, ctx->reseed_counter = 1; exit: - mbedtls_zeroize( seed, sizeof( seed ) ); + mbedtls_platform_zeroize( seed, sizeof( seed ) ); return( ret ); } +/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) + * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len) + * implements + * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string, + * security_strength) -> initial_working_state + * with inputs + * custom[:len] = nonce || personalization_string + * where entropy_input comes from f_entropy for ctx->entropy_len bytes + * and with outputs + * ctx = initial_working_state + */ +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + int ret; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + + memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE ); + + mbedtls_aes_init( &ctx->aes_ctx ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + if( ctx->entropy_len == 0 ) + ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN; + ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL; + + /* + * Initialize with an empty key + */ + if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +/* Backward compatibility wrapper */ +int mbedtls_ctr_drbg_seed_entropy_len( + mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), void *p_entropy, + const unsigned char *custom, size_t len, + size_t entropy_len ) +{ + mbedtls_ctr_drbg_set_entropy_len( ctx, entropy_len ); + return( mbedtls_ctr_drbg_seed( ctx, f_entropy, p_entropy, custom, len ) ); +} + +/* CTR_DRBG_Generate with derivation function (SP 800-90A §10.2.1.5.2) + * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len) + * implements + * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len]) + * -> working_state_after_reseed + * if required, then + * CTR_DRBG_Generate(working_state_after_reseed, + * requested_number_of_bits, additional_input) + * -> status, returned_bits, new_working_state + * with inputs + * ctx contains working_state + * requested_number_of_bits = 8 * output_len + * additional[:add_len] = additional_input + * and entropy_input comes from calling ctx->f_entropy + * and with outputs + * status = SUCCESS (this function does the reseed internally) + * returned_bits = output[:output_len] + * ctx contains new_working_state + */ int mbedtls_ctr_drbg_random_with_add( void *p_rng, unsigned char *output, size_t output_len, const unsigned char *additional, size_t add_len ) @@ -455,8 +510,8 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, ctx->reseed_counter++; exit: - mbedtls_zeroize( add_input, sizeof( add_input ) ); - mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); return( 0 ); } @@ -499,7 +554,7 @@ int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char ret = 0; exit: - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); fclose( f ); return( ret ); @@ -508,35 +563,36 @@ int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) { int ret = 0; - FILE *f; + FILE *f = NULL; size_t n; unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + unsigned char c; if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); - fseek( f, 0, SEEK_END ); - n = (size_t) ftell( f ); - fseek( f, 0, SEEK_SET ); - - if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) { - fclose( f ); - return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + goto exit; } - - if( fread( buf, 1, n, f ) != n ) + if( n == 0 || ferror( f ) ) + { ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; - else - ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n ); - + goto exit; + } fclose( f ); + f = NULL; - mbedtls_zeroize( buf, sizeof( buf ) ); + ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n ); +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + if( f != NULL ) + fclose( f ); if( ret != 0 ) return( ret ); - return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); } #endif /* MBEDTLS_FS_IO */ @@ -617,8 +673,11 @@ int mbedtls_ctr_drbg_self_test( int verbose ) mbedtls_printf( " CTR_DRBG (PR = TRUE) : " ); test_offset = 0; - CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, - (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) ); + mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 ); + CHK( mbedtls_ctr_drbg_seed( &ctx, + ctr_drbg_self_test_entropy, + (void *) entropy_source_pr, + nonce_pers_pr, 16 ) ); mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); @@ -638,8 +697,11 @@ int mbedtls_ctr_drbg_self_test( int verbose ) mbedtls_ctr_drbg_init( &ctx ); test_offset = 0; - CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, - (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) ); + mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 ); + CHK( mbedtls_ctr_drbg_seed( &ctx, + ctr_drbg_self_test_entropy, + (void *) entropy_source_nopr, + nonce_pers_nopr, 16 ) ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); diff --git a/app/mbedtls/library/debug.c b/app/mbedtls/library/debug.c index da80950984..9e711c1385 100644 --- a/app/mbedtls/library/debug.c +++ b/app/mbedtls/library/debug.c @@ -86,8 +86,13 @@ void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, char str[DEBUG_BUF_SIZE]; int ret; - if( NULL == ssl || NULL == ssl->conf || NULL == ssl->conf->f_dbg || level > debug_threshold ) + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { return; + } va_start( argp, format ); #if defined(_WIN32) @@ -121,8 +126,13 @@ void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level, { char str[DEBUG_BUF_SIZE]; - if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { return; + } /* * With non-blocking I/O and examples that just retry immediately, @@ -146,8 +156,13 @@ void mbedtls_debug_print_buf( const mbedtls_ssl_context *ssl, int level, char txt[17]; size_t i, idx = 0; - if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { return; + } mbedtls_snprintf( str + idx, sizeof( str ) - idx, "dumping '%s' (%u bytes)\n", text, (unsigned int) len ); @@ -199,8 +214,13 @@ void mbedtls_debug_print_ecp( const mbedtls_ssl_context *ssl, int level, { char str[DEBUG_BUF_SIZE]; - if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { return; + } mbedtls_snprintf( str, sizeof( str ), "%s(X)", text ); mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->X ); @@ -219,8 +239,14 @@ void mbedtls_debug_print_mpi( const mbedtls_ssl_context *ssl, int level, int j, k, zeros = 1; size_t i, n, idx = 0; - if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || X == NULL || level > debug_threshold ) + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + NULL == X || + level > debug_threshold ) + { return; + } for( n = X->n - 1; n > 0; n-- ) if( X->p[n] != 0 ) @@ -345,8 +371,14 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, char str[DEBUG_BUF_SIZE]; int i = 0; - if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || crt == NULL || level > debug_threshold ) + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + NULL == crt || + level > debug_threshold ) + { return; + } while( crt != NULL ) { @@ -365,4 +397,54 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, } #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_ECDH_C) +static void mbedtls_debug_printf_ecdh_internal( const mbedtls_ssl_context *ssl, + int level, const char *file, + int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + const mbedtls_ecdh_context* ctx = ecdh; +#else + const mbedtls_ecdh_context_mbed* ctx = &ecdh->ctx.mbed_ecdh; +#endif + + switch( attr ) + { + case MBEDTLS_DEBUG_ECDH_Q: + mbedtls_debug_print_ecp( ssl, level, file, line, "ECDH: Q", + &ctx->Q ); + break; + case MBEDTLS_DEBUG_ECDH_QP: + mbedtls_debug_print_ecp( ssl, level, file, line, "ECDH: Qp", + &ctx->Qp ); + break; + case MBEDTLS_DEBUG_ECDH_Z: + mbedtls_debug_print_mpi( ssl, level, file, line, "ECDH: z", + &ctx->z ); + break; + default: + break; + } +} + +void mbedtls_debug_printf_ecdh( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + mbedtls_debug_printf_ecdh_internal( ssl, level, file, line, ecdh, attr ); +#else + switch( ecdh->var ) + { + default: + mbedtls_debug_printf_ecdh_internal( ssl, level, file, line, ecdh, + attr ); + } +#endif +} +#endif /* MBEDTLS_ECDH_C */ + #endif /* MBEDTLS_DEBUG_C */ diff --git a/app/mbedtls/library/des.c b/app/mbedtls/library/des.c index 09f95cfc3b..8a33d82e50 100644 --- a/app/mbedtls/library/des.c +++ b/app/mbedtls/library/des.c @@ -34,6 +34,7 @@ #if defined(MBEDTLS_DES_C) #include "mbedtls/des.h" +#include "mbedtls/platform_util.h" #include @@ -48,11 +49,6 @@ #if !defined(MBEDTLS_DES_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} - /* * 32-bit integer manipulation macros (big endian) */ @@ -261,50 +257,57 @@ static const uint32_t RHs[16] = /* * Initial Permutation macro */ -#define DES_IP(X,Y) \ -{ \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ - X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ -} +#define DES_IP(X,Y) \ + do \ + { \ + T = (((X) >> 4) ^ (Y)) & 0x0F0F0F0F; (Y) ^= T; (X) ^= (T << 4); \ + T = (((X) >> 16) ^ (Y)) & 0x0000FFFF; (Y) ^= T; (X) ^= (T << 16); \ + T = (((Y) >> 2) ^ (X)) & 0x33333333; (X) ^= T; (Y) ^= (T << 2); \ + T = (((Y) >> 8) ^ (X)) & 0x00FF00FF; (X) ^= T; (Y) ^= (T << 8); \ + (Y) = (((Y) << 1) | ((Y) >> 31)) & 0xFFFFFFFF; \ + T = ((X) ^ (Y)) & 0xAAAAAAAA; (Y) ^= T; (X) ^= T; \ + (X) = (((X) << 1) | ((X) >> 31)) & 0xFFFFFFFF; \ + } while( 0 ) /* * Final Permutation macro */ -#define DES_FP(X,Y) \ -{ \ - X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ - Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ -} +#define DES_FP(X,Y) \ + do \ + { \ + (X) = (((X) << 31) | ((X) >> 1)) & 0xFFFFFFFF; \ + T = ((X) ^ (Y)) & 0xAAAAAAAA; (X) ^= T; (Y) ^= T; \ + (Y) = (((Y) << 31) | ((Y) >> 1)) & 0xFFFFFFFF; \ + T = (((Y) >> 8) ^ (X)) & 0x00FF00FF; (X) ^= T; (Y) ^= (T << 8); \ + T = (((Y) >> 2) ^ (X)) & 0x33333333; (X) ^= T; (Y) ^= (T << 2); \ + T = (((X) >> 16) ^ (Y)) & 0x0000FFFF; (Y) ^= T; (X) ^= (T << 16); \ + T = (((X) >> 4) ^ (Y)) & 0x0F0F0F0F; (Y) ^= T; (X) ^= (T << 4); \ + } while( 0 ) /* * DES round macro */ -#define DES_ROUND(X,Y) \ -{ \ - T = *SK++ ^ X; \ - Y ^= SB8[ (T ) & 0x3F ] ^ \ - SB6[ (T >> 8) & 0x3F ] ^ \ - SB4[ (T >> 16) & 0x3F ] ^ \ - SB2[ (T >> 24) & 0x3F ]; \ - \ - T = *SK++ ^ ((X << 28) | (X >> 4)); \ - Y ^= SB7[ (T ) & 0x3F ] ^ \ - SB5[ (T >> 8) & 0x3F ] ^ \ - SB3[ (T >> 16) & 0x3F ] ^ \ - SB1[ (T >> 24) & 0x3F ]; \ -} - -#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } +#define DES_ROUND(X,Y) \ + do \ + { \ + T = *SK++ ^ (X); \ + (Y) ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ (((X) << 28) | ((X) >> 4)); \ + (Y) ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ + } while( 0 ) + +#define SWAP(a,b) \ + do \ + { \ + uint32_t t = (a); (a) = (b); (b) = t; t = 0; \ + } while( 0 ) void mbedtls_des_init( mbedtls_des_context *ctx ) { @@ -316,7 +319,7 @@ void mbedtls_des_free( mbedtls_des_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_des_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_des_context ) ); } void mbedtls_des3_init( mbedtls_des3_context *ctx ) @@ -329,7 +332,7 @@ void mbedtls_des3_free( mbedtls_des3_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_des3_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_des3_context ) ); } static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, @@ -553,7 +556,7 @@ int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, uint32_t sk[96]; des3_set2key( ctx->sk, sk, key ); - mbedtls_zeroize( sk, sizeof( sk ) ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); return( 0 ); } @@ -567,7 +570,7 @@ int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, uint32_t sk[96]; des3_set2key( sk, ctx->sk, key ); - mbedtls_zeroize( sk, sizeof( sk ) ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); return( 0 ); } @@ -604,7 +607,7 @@ int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, uint32_t sk[96]; des3_set3key( ctx->sk, sk, key ); - mbedtls_zeroize( sk, sizeof( sk ) ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); return( 0 ); } @@ -618,7 +621,7 @@ int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, uint32_t sk[96]; des3_set3key( sk, ctx->sk, key ); - mbedtls_zeroize( sk, sizeof( sk ) ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); return( 0 ); } diff --git a/app/mbedtls/library/dhm.c b/app/mbedtls/library/dhm.c index 28ac31003c..8255632a99 100644 --- a/app/mbedtls/library/dhm.c +++ b/app/mbedtls/library/dhm.c @@ -36,6 +36,7 @@ #if defined(MBEDTLS_DHM_C) #include "mbedtls/dhm.h" +#include "mbedtls/platform_util.h" #include @@ -58,10 +59,11 @@ #endif #if !defined(MBEDTLS_DHM_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} + +#define DHM_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA ) +#define DHM_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) /* * helper to validate the mbedtls_mpi size and import it @@ -124,6 +126,7 @@ static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) { + DHM_VALIDATE( ctx != NULL ); memset( ctx, 0, sizeof( mbedtls_dhm_context ) ); } @@ -135,6 +138,9 @@ int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, const unsigned char *end ) { int ret; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( p != NULL && *p != NULL ); + DHM_VALIDATE_RET( end != NULL ); if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || @@ -160,6 +166,10 @@ int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, int ret, count = 0; size_t n1, n2, n3; unsigned char *p; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( output != NULL ); + DHM_VALIDATE_RET( olen != NULL ); + DHM_VALIDATE_RET( f_rng != NULL ); if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); @@ -230,9 +240,9 @@ int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx, const mbedtls_mpi *G ) { int ret; - - if( ctx == NULL || P == NULL || G == NULL ) - return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( P != NULL ); + DHM_VALIDATE_RET( G != NULL ); if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 || ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 ) @@ -251,8 +261,10 @@ int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, const unsigned char *input, size_t ilen ) { int ret; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( input != NULL ); - if( ctx == NULL || ilen < 1 || ilen > ctx->len ) + if( ilen < 1 || ilen > ctx->len ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) @@ -270,8 +282,11 @@ int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, void *p_rng ) { int ret, count = 0; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( output != NULL ); + DHM_VALIDATE_RET( f_rng != NULL ); - if( ctx == NULL || olen < 1 || olen > ctx->len ) + if( olen < 1 || olen > ctx->len ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) @@ -383,8 +398,11 @@ int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, { int ret; mbedtls_mpi GYb; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( output != NULL ); + DHM_VALIDATE_RET( olen != NULL ); - if( ctx == NULL || output_size < ctx->len ) + if( output_size < ctx->len ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) @@ -431,13 +449,21 @@ int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, */ void mbedtls_dhm_free( mbedtls_dhm_context *ctx ) { - mbedtls_mpi_free( &ctx->pX ); mbedtls_mpi_free( &ctx->Vf ); - mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->RP ); - mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY ); - mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); - mbedtls_mpi_free( &ctx->G ); mbedtls_mpi_free( &ctx->P ); - - mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->pX ); + mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->Vi ); + mbedtls_mpi_free( &ctx->RP ); + mbedtls_mpi_free( &ctx->K ); + mbedtls_mpi_free( &ctx->GY ); + mbedtls_mpi_free( &ctx->GX ); + mbedtls_mpi_free( &ctx->X ); + mbedtls_mpi_free( &ctx->G ); + mbedtls_mpi_free( &ctx->P ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); } #if defined(MBEDTLS_ASN1_PARSE_C) @@ -452,7 +478,12 @@ int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, unsigned char *p, *end; #if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_context pem; +#endif /* MBEDTLS_PEM_PARSE_C */ + + DHM_VALIDATE_RET( dhm != NULL ); + DHM_VALIDATE_RET( dhmin != NULL ); +#if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_init( &pem ); /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ @@ -575,7 +606,7 @@ static int load_file( const char *path, unsigned char **buf, size_t *n ) { fclose( f ); - mbedtls_zeroize( *buf, *n + 1 ); + mbedtls_platform_zeroize( *buf, *n + 1 ); mbedtls_free( *buf ); return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); @@ -599,13 +630,15 @@ int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) int ret; size_t n; unsigned char *buf; + DHM_VALIDATE_RET( dhm != NULL ); + DHM_VALIDATE_RET( path != NULL ); if( ( ret = load_file( path, &buf, &n ) ) != 0 ) return( ret ); ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); - mbedtls_zeroize( buf, n ); + mbedtls_platform_zeroize( buf, n ); mbedtls_free( buf ); return( ret ); @@ -616,12 +649,28 @@ int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) #if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PEM_PARSE_C) static const char mbedtls_test_dhm_params[] = "-----BEGIN DH PARAMETERS-----\r\n" "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" "-----END DH PARAMETERS-----\r\n"; +#else /* MBEDTLS_PEM_PARSE_C */ +static const char mbedtls_test_dhm_params[] = { + 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44, + 0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d, + 0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3, + 0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1, + 0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18, + 0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a, + 0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1, + 0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6, + 0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64, + 0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8, + 0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f, + 0x49, 0x75, 0xb3, 0x02, 0x01, 0x02 }; +#endif /* MBEDTLS_PEM_PARSE_C */ static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); diff --git a/app/mbedtls/library/ecdh.c b/app/mbedtls/library/ecdh.c index 61380b6936..c5726877d5 100644 --- a/app/mbedtls/library/ecdh.c +++ b/app/mbedtls/library/ecdh.c @@ -35,41 +35,92 @@ #if defined(MBEDTLS_ECDH_C) #include "mbedtls/ecdh.h" +#include "mbedtls/platform_util.h" #include +/* Parameter validation macros based on platform_util.h */ +#define ECDH_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECDH_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed; +#endif + +static mbedtls_ecp_group_id mbedtls_ecdh_grp_id( + const mbedtls_ecdh_context *ctx ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ctx->grp.id ); +#else + return( ctx->grp_id ); +#endif +} + #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) /* - * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair + * Generate public key (restartable version) + * + * Note: this internal function relies on its caller preserving the value of + * the output parameter 'd' across continuation calls. This would not be + * acceptable for a public function but is OK here as we control call sites. + */ +static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + + /* If multiplication is in progress, we already generated a privkey */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx == NULL || rs_ctx->rsm == NULL ) +#endif + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G, + f_rng, p_rng, rs_ctx ) ); + +cleanup: + return( ret ); +} + +/* + * Generate public key */ int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); + ECDH_VALIDATE_RET( grp != NULL ); + ECDH_VALIDATE_RET( d != NULL ); + ECDH_VALIDATE_RET( Q != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) ); } -#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */ +#endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */ #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) /* * Compute shared secret (SEC1 3.3.1) */ -int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, +static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *z, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) { int ret; mbedtls_ecp_point P; mbedtls_ecp_point_init( &P ); - /* - * Make sure Q is a valid pubkey before using it - */ - MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); - - MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q, + f_rng, p_rng, rs_ctx ) ); if( mbedtls_ecp_is_zero( &P ) ) { @@ -84,71 +135,250 @@ int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, return( ret ); } -#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ + +/* + * Compute shared secret (SEC1 3.3.1) + */ +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ECDH_VALIDATE_RET( grp != NULL ); + ECDH_VALIDATE_RET( Q != NULL ); + ECDH_VALIDATE_RET( d != NULL ); + ECDH_VALIDATE_RET( z != NULL ); + return( ecdh_compute_shared_restartable( grp, z, Q, d, + f_rng, p_rng, NULL ) ); +} +#endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ + +static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx ) +{ + mbedtls_ecp_group_init( &ctx->grp ); + mbedtls_mpi_init( &ctx->d ); + mbedtls_ecp_point_init( &ctx->Q ); + mbedtls_ecp_point_init( &ctx->Qp ); + mbedtls_mpi_init( &ctx->z ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_init( &ctx->rs ); +#endif +} /* * Initialize context */ void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) { + ECDH_VALIDATE( ctx != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + ecdh_init_internal( ctx ); + mbedtls_ecp_point_init( &ctx->Vi ); + mbedtls_ecp_point_init( &ctx->Vf ); + mbedtls_mpi_init( &ctx->_d ); +#else memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); + + ctx->var = MBEDTLS_ECDH_VARIANT_NONE; +#endif + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; +#if defined(MBEDTLS_ECP_RESTARTABLE) + ctx->restart_enabled = 0; +#endif +} + +static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx, + mbedtls_ecp_group_id grp_id ) +{ + int ret; + + ret = mbedtls_ecp_group_load( &ctx->grp, grp_id ); + if( ret != 0 ) + { + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } + + return( 0 ); } /* - * Free context + * Setup context */ -void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id ) { - if( ctx == NULL ) - return; + ECDH_VALIDATE_RET( ctx != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_setup_internal( ctx, grp_id ) ); +#else + switch( grp_id ) + { + default: + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0; + ctx->grp_id = grp_id; + ecdh_init_internal( &ctx->ctx.mbed_ecdh ); + return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) ); + } +#endif +} +static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx ) +{ mbedtls_ecp_group_free( &ctx->grp ); + mbedtls_mpi_free( &ctx->d ); mbedtls_ecp_point_free( &ctx->Q ); mbedtls_ecp_point_free( &ctx->Qp ); - mbedtls_ecp_point_free( &ctx->Vi ); - mbedtls_ecp_point_free( &ctx->Vf ); - mbedtls_mpi_free( &ctx->d ); mbedtls_mpi_free( &ctx->z ); - mbedtls_mpi_free( &ctx->_d ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_free( &ctx->rs ); +#endif } +#if defined(MBEDTLS_ECP_RESTARTABLE) /* - * Setup and write the ServerKeyExhange parameters (RFC 4492) - * struct { - * ECParameters curve_params; - * ECPoint public; - * } ServerECDHParams; + * Enable restartable operations for context */ -int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx ) +{ + ECDH_VALIDATE( ctx != NULL ); + + ctx->restart_enabled = 1; +} +#endif + +/* + * Free context + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + mbedtls_ecp_point_free( &ctx->Vi ); + mbedtls_ecp_point_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->_d ); + ecdh_free_internal( ctx ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + ecdh_free_internal( &ctx->ctx.mbed_ecdh ); + break; + default: + break; + } + + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + ctx->var = MBEDTLS_ECDH_VARIANT_NONE; + ctx->grp_id = MBEDTLS_ECP_DP_NONE; +#endif +} + +static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) { int ret; size_t grp_len, pt_len; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif - if( ctx == NULL || ctx->grp.pbits == 0 ) + if( ctx->grp.pbits == 0 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); - if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) - != 0 ) +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ - if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) ) - != 0 ) + if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, + blen ) ) != 0 ) return( ret ); buf += grp_len; blen -= grp_len; - if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, - &pt_len, buf, blen ) ) != 0 ) + if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, + &pt_len, buf, blen ) ) != 0 ) return( ret ); *olen = grp_len + pt_len; return( 0 ); } +/* + * Setup and write the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, + end - *buf ) ); +} + /* * Read the ServerKeyExhange parameters (RFC 4492) * struct { @@ -157,31 +387,43 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, * } ServerECDHParams; */ int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, - const unsigned char **buf, const unsigned char *end ) + const unsigned char **buf, + const unsigned char *end ) { int ret; - - if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) + mbedtls_ecp_group_id grp_id; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( *buf != NULL ); + ECDH_VALIDATE_RET( end != NULL ); + + if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) ) + != 0 ) return( ret ); - if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) - != 0 ) + if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 ) return( ret ); - return( 0 ); +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_params_internal( ctx, buf, end ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh, + buf, end ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif } -/* - * Get parameters from a keypair - */ -int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, - mbedtls_ecdh_side side ) +static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) { int ret; - if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ) - return( ret ); - /* If it's not our key, just import the public part as Qp */ if( side == MBEDTLS_ECDH_THEIRS ) return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); @@ -198,39 +440,129 @@ int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypai } /* - * Setup and export the client public value + * Get parameters from a keypair */ -int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) { int ret; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( key != NULL ); + ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS || + side == MBEDTLS_ECDH_THEIRS ); - if( ctx == NULL || ctx->grp.pbits == 0 ) + if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE ) + { + /* This is the first call to get_params(). Set up the context + * for use with the group. */ + if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 ) + return( ret ); + } + else + { + /* This is not the first call to get_params(). Check that the + * current key's group is the same as the context's, which was set + * from the first key's group. */ + if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_get_params_internal( ctx, key, side ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh, + key, side ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx->grp.pbits == 0 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); - if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) - != 0 ) +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ - return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, - olen, buf, blen ); + return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen, + buf, blen ); } /* - * Parse and import the client's public value + * Setup and export the client public value */ -int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, - const unsigned char *buf, size_t blen ) +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char *buf, size_t blen ) { int ret; const unsigned char *p = buf; - if( ctx == NULL ) - return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); - - if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, blen ) ) != 0 ) + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, + blen ) ) != 0 ) return( ret ); if( (size_t)( p - buf ) != blen ) @@ -240,23 +572,66 @@ int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, } /* - * Derive and export the shared secret + * Parse and import the client's public value */ -int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_public_internal( ctx, buf, blen ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh, + buf, blen ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, unsigned char *buf, + size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) { int ret; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif - if( ctx == NULL ) + if( ctx == NULL || ctx->grp.pbits == 0 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); - if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, - f_rng, p_rng ) ) != 0 ) +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp, + &ctx->d, f_rng, p_rng, + rs_ctx ) ) != 0 ) + { + return( ret ); + } +#else + if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, + &ctx->d, f_rng, p_rng ) ) != 0 ) { return( ret ); } +#endif /* MBEDTLS_ECP_RESTARTABLE */ if( mbedtls_mpi_size( &ctx->z ) > blen ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); @@ -265,4 +640,37 @@ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); } +/* + * Derive and export the shared secret + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng, + restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf, + blen, f_rng, p_rng, + restart_enabled ) ); + default: + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } +#endif +} + #endif /* MBEDTLS_ECDH_C */ diff --git a/app/mbedtls/library/ecdsa.c b/app/mbedtls/library/ecdsa.c index 17a88bdd29..2b4800642d 100644 --- a/app/mbedtls/library/ecdsa.c +++ b/app/mbedtls/library/ecdsa.c @@ -42,6 +42,186 @@ #include "mbedtls/hmac_drbg.h" #endif +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/platform_util.h" + +/* Parameter validation macros based on platform_util.h */ +#define ECDSA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECDSA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/* + * Sub-context for ecdsa_verify() + */ +struct mbedtls_ecdsa_restart_ver +{ + mbedtls_mpi u1, u2; /* intermediate values */ + enum { /* what to do next? */ + ecdsa_ver_init = 0, /* getting started */ + ecdsa_ver_muladd, /* muladd step */ + } state; +}; + +/* + * Init verify restart sub-context + */ +static void ecdsa_restart_ver_init( mbedtls_ecdsa_restart_ver_ctx *ctx ) +{ + mbedtls_mpi_init( &ctx->u1 ); + mbedtls_mpi_init( &ctx->u2 ); + ctx->state = ecdsa_ver_init; +} + +/* + * Free the components of a verify restart sub-context + */ +static void ecdsa_restart_ver_free( mbedtls_ecdsa_restart_ver_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->u1 ); + mbedtls_mpi_free( &ctx->u2 ); + + ecdsa_restart_ver_init( ctx ); +} + +/* + * Sub-context for ecdsa_sign() + */ +struct mbedtls_ecdsa_restart_sig +{ + int sign_tries; + int key_tries; + mbedtls_mpi k; /* per-signature random */ + mbedtls_mpi r; /* r value */ + enum { /* what to do next? */ + ecdsa_sig_init = 0, /* getting started */ + ecdsa_sig_mul, /* doing ecp_mul() */ + ecdsa_sig_modn, /* mod N computations */ + } state; +}; + +/* + * Init verify sign sub-context + */ +static void ecdsa_restart_sig_init( mbedtls_ecdsa_restart_sig_ctx *ctx ) +{ + ctx->sign_tries = 0; + ctx->key_tries = 0; + mbedtls_mpi_init( &ctx->k ); + mbedtls_mpi_init( &ctx->r ); + ctx->state = ecdsa_sig_init; +} + +/* + * Free the components of a sign restart sub-context + */ +static void ecdsa_restart_sig_free( mbedtls_ecdsa_restart_sig_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->k ); + mbedtls_mpi_free( &ctx->r ); +} + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Sub-context for ecdsa_sign_det() + */ +struct mbedtls_ecdsa_restart_det +{ + mbedtls_hmac_drbg_context rng_ctx; /* DRBG state */ + enum { /* what to do next? */ + ecdsa_det_init = 0, /* getting started */ + ecdsa_det_sign, /* make signature */ + } state; +}; + +/* + * Init verify sign_det sub-context + */ +static void ecdsa_restart_det_init( mbedtls_ecdsa_restart_det_ctx *ctx ) +{ + mbedtls_hmac_drbg_init( &ctx->rng_ctx ); + ctx->state = ecdsa_det_init; +} + +/* + * Free the components of a sign_det restart sub-context + */ +static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_hmac_drbg_free( &ctx->rng_ctx ); + + ecdsa_restart_det_init( ctx ); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +#define ECDSA_RS_ECP ( rs_ctx == NULL ? NULL : &rs_ctx->ecp ) + +/* Utility macro for checking and updating ops budget */ +#define ECDSA_BUDGET( ops ) \ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, ECDSA_RS_ECP, ops ) ); + +/* Call this when entering a function that needs its own sub-context */ +#define ECDSA_RS_ENTER( SUB ) do { \ + /* reset ops count for this call if top-level */ \ + if( rs_ctx != NULL && rs_ctx->ecp.depth++ == 0 ) \ + rs_ctx->ecp.ops_done = 0; \ + \ + /* set up our own sub-context if needed */ \ + if( mbedtls_ecp_restart_is_enabled() && \ + rs_ctx != NULL && rs_ctx->SUB == NULL ) \ + { \ + rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \ + if( rs_ctx->SUB == NULL ) \ + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \ + \ + ecdsa_restart_## SUB ##_init( rs_ctx->SUB ); \ + } \ +} while( 0 ) + +/* Call this when leaving a function that needs its own sub-context */ +#define ECDSA_RS_LEAVE( SUB ) do { \ + /* clear our sub-context when not in progress (done or error) */ \ + if( rs_ctx != NULL && rs_ctx->SUB != NULL && \ + ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \ + { \ + ecdsa_restart_## SUB ##_free( rs_ctx->SUB ); \ + mbedtls_free( rs_ctx->SUB ); \ + rs_ctx->SUB = NULL; \ + } \ + \ + if( rs_ctx != NULL ) \ + rs_ctx->ecp.depth--; \ +} while( 0 ) + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define ECDSA_RS_ECP NULL + +#define ECDSA_BUDGET( ops ) /* no-op; for compatibility */ + +#define ECDSA_RS_ENTER( SUB ) (void) rs_ctx +#define ECDSA_RS_LEAVE( SUB ) (void) rs_ctx + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + /* * Derive a suitable integer for group grp from a buffer of length len * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 @@ -70,13 +250,19 @@ static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x, * Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) */ -int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, +static int ecdsa_sign_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int (*f_rng_blind)(void *, unsigned char *, size_t), + void *p_rng_blind, + mbedtls_ecdsa_restart_ctx *rs_ctx ) { - int ret, key_tries, sign_tries, blind_tries; + int ret, key_tries, sign_tries; + int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries; mbedtls_ecp_point R; mbedtls_mpi k, e, t; + mbedtls_mpi *pk = &k, *pr = r; /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ if( grp->N.p == NULL ) @@ -89,26 +275,74 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, mbedtls_ecp_point_init( &R ); mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); - sign_tries = 0; + ECDSA_RS_ENTER( sig ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + { + /* redirect to our context */ + p_sign_tries = &rs_ctx->sig->sign_tries; + p_key_tries = &rs_ctx->sig->key_tries; + pk = &rs_ctx->sig->k; + pr = &rs_ctx->sig->r; + + /* jump to current step */ + if( rs_ctx->sig->state == ecdsa_sig_mul ) + goto mul; + if( rs_ctx->sig->state == ecdsa_sig_modn ) + goto modn; + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + *p_sign_tries = 0; do { + if( *p_sign_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + /* * Steps 1-3: generate a suitable ephemeral keypair * and set r = xR mod n */ - key_tries = 0; + *p_key_tries = 0; do { - MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); - - if( key_tries++ > 10 ) + if( *p_key_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } + + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + rs_ctx->sig->state = ecdsa_sig_mul; + +mul: +#endif + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G, + f_rng_blind, + p_rng_blind, + ECDSA_RS_ECP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) ); } - while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); + while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + rs_ctx->sig->state = ecdsa_sig_modn; + +modn: +#endif + /* + * Accounting for everything up to the end of the loop + * (step 6, but checking now avoids saving e and t) + */ + ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 ); /* * Step 5: derive MPI from hashed message @@ -119,57 +353,71 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, * Generate a random value to blind inv_mod in next step, * avoiding a potential timing leak. */ - blind_tries = 0; - do - { - size_t n_size = ( grp->nbits + 7 ) / 8; - MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); - - /* See mbedtls_ecp_gen_keypair() */ - if( ++blind_tries > 30 ) - return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); - } - while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 || - mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 ); + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng_blind, + p_rng_blind ) ); /* * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n */ - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); - - if( sign_tries++ > 10 ) - { - ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; - goto cleanup; - } } while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + mbedtls_mpi_copy( r, pr ); +#endif + cleanup: mbedtls_ecp_point_free( &R ); mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); + ECDSA_RS_LEAVE( sig ); + return( ret ); } -#endif /* MBEDTLS_ECDSA_SIGN_ALT */ + +/* + * Compute ECDSA signature of a hashed message + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + ECDSA_VALIDATE_RET( grp != NULL ); + ECDSA_VALIDATE_RET( r != NULL ); + ECDSA_VALIDATE_RET( s != NULL ); + ECDSA_VALIDATE_RET( d != NULL ); + ECDSA_VALIDATE_RET( f_rng != NULL ); + ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); + + /* Use the same RNG for both blinding and ephemeral key generation */ + return( ecdsa_sign_restartable( grp, r, s, d, buf, blen, + f_rng, p_rng, f_rng, p_rng, NULL ) ); +} +#endif /* !MBEDTLS_ECDSA_SIGN_ALT */ #if defined(MBEDTLS_ECDSA_DETERMINISTIC) /* * Deterministic signature wrapper */ -int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, +static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, - mbedtls_md_type_t md_alg ) + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, size_t), + void *p_rng_blind, + mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; mbedtls_hmac_drbg_context rng_ctx; + mbedtls_hmac_drbg_context *p_rng = &rng_ctx; unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; size_t grp_len = ( grp->nbits + 7 ) / 8; const mbedtls_md_info_t *md_info; @@ -181,21 +429,147 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi mbedtls_mpi_init( &h ); mbedtls_hmac_drbg_init( &rng_ctx ); + ECDSA_RS_ENTER( det ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->det != NULL ) + { + /* redirect to our context */ + p_rng = &rs_ctx->det->rng_ctx; + + /* jump to current step */ + if( rs_ctx->det->state == ecdsa_det_sign ) + goto sign; + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); - mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len ); + mbedtls_hmac_drbg_seed_buf( p_rng, md_info, data, 2 * grp_len ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->det != NULL ) + rs_ctx->det->state = ecdsa_det_sign; + +sign: +#endif +#if defined(MBEDTLS_ECDSA_SIGN_ALT) ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, - mbedtls_hmac_drbg_random, &rng_ctx ); + mbedtls_hmac_drbg_random, p_rng ); +#else + if( f_rng_blind != NULL ) + ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, p_rng, + f_rng_blind, p_rng_blind, rs_ctx ); + else + { + mbedtls_hmac_drbg_context *p_rng_blind_det; + +#if !defined(MBEDTLS_ECP_RESTARTABLE) + /* + * To avoid reusing rng_ctx and risking incorrect behavior we seed a + * second HMAC-DRBG with the same seed. We also apply a label to avoid + * reusing the bits of the ephemeral key for blinding and eliminate the + * risk that they leak this way. + */ + const char* blind_label = "BLINDING CONTEXT"; + mbedtls_hmac_drbg_context rng_ctx_blind; + + mbedtls_hmac_drbg_init( &rng_ctx_blind ); + p_rng_blind_det = &rng_ctx_blind; + + mbedtls_hmac_drbg_seed_buf( p_rng_blind_det, md_info, + data, 2 * grp_len ); + ret = mbedtls_hmac_drbg_update_ret( p_rng_blind_det, + (const unsigned char*) blind_label, + strlen( blind_label ) ); + if( ret != 0 ) + { + mbedtls_hmac_drbg_free( &rng_ctx_blind ); + goto cleanup; + } +#else + /* + * In the case of restartable computations we would either need to store + * the second RNG in the restart context too or set it up at every + * restart. The first option would penalize the correct application of + * the function and the second would defeat the purpose of the + * restartable feature. + * + * Therefore in this case we reuse the original RNG. This comes with the + * price that the resulting signature might not be a valid deterministic + * ECDSA signature with a very low probability (same magnitude as + * successfully guessing the private key). However even then it is still + * a valid ECDSA signature. + */ + p_rng_blind_det = p_rng; +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + /* + * Since the output of the RNGs is always the same for the same key and + * message, this limits the efficiency of blinding and leaks information + * through side channels. After mbedtls_ecdsa_sign_det() is removed NULL + * won't be a valid value for f_rng_blind anymore. Therefore it should + * be checked by the caller and this branch and check can be removed. + */ + ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, p_rng, + mbedtls_hmac_drbg_random, p_rng_blind_det, + rs_ctx ); + +#if !defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_hmac_drbg_free( &rng_ctx_blind ); +#endif + } +#endif /* MBEDTLS_ECDSA_SIGN_ALT */ cleanup: mbedtls_hmac_drbg_free( &rng_ctx ); mbedtls_mpi_free( &h ); + ECDSA_RS_LEAVE( det ); + return( ret ); } + +/* + * Deterministic signature wrappers + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ) +{ + ECDSA_VALIDATE_RET( grp != NULL ); + ECDSA_VALIDATE_RET( r != NULL ); + ECDSA_VALIDATE_RET( s != NULL ); + ECDSA_VALIDATE_RET( d != NULL ); + ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); + + return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, + NULL, NULL, NULL ) ); +} + +int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, + size_t), + void *p_rng_blind ) +{ + ECDSA_VALIDATE_RET( grp != NULL ); + ECDSA_VALIDATE_RET( r != NULL ); + ECDSA_VALIDATE_RET( s != NULL ); + ECDSA_VALIDATE_RET( d != NULL ); + ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); + ECDSA_VALIDATE_RET( f_rng_blind != NULL ); + + return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, + f_rng_blind, p_rng_blind, NULL ) ); +} #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ #if !defined(MBEDTLS_ECDSA_VERIFY_ALT) @@ -203,21 +577,40 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi * Verify ECDSA signature of hashed message (SEC1 4.1.4) * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) */ -int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, - const unsigned char *buf, size_t blen, - const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) +static int ecdsa_verify_restartable( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, + const mbedtls_mpi *r, const mbedtls_mpi *s, + mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; mbedtls_mpi e, s_inv, u1, u2; mbedtls_ecp_point R; + mbedtls_mpi *pu1 = &u1, *pu2 = &u2; mbedtls_ecp_point_init( &R ); - mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); + mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); + mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ if( grp->N.p == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + ECDSA_RS_ENTER( ver ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ver != NULL ) + { + /* redirect to our context */ + pu1 = &rs_ctx->ver->u1; + pu2 = &rs_ctx->ver->u2; + + /* jump to current step */ + if( rs_ctx->ver->state == ecdsa_ver_muladd ) + goto muladd; + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + /* * Step 1: make sure r and s are in range 1..n-1 */ @@ -228,11 +621,6 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, goto cleanup; } - /* - * Additional precaution: make sure Q is valid - */ - MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); - /* * Step 3: derive MPI from hashed message */ @@ -241,21 +629,27 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, /* * Step 4: u1 = e / s mod n, u2 = r / s mod n */ + ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ver != NULL ) + rs_ctx->ver->state = ecdsa_ver_muladd; +muladd: +#endif /* * Step 5: R = u1 G + u2 Q - * - * Since we're not using any secret data, no need to pass a RNG to - * mbedtls_ecp_mul() for countermesures. */ - MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp, + &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) ); if( mbedtls_ecp_is_zero( &R ) ) { @@ -280,11 +674,32 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, cleanup: mbedtls_ecp_point_free( &R ); - mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); + mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); + mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); + + ECDSA_RS_LEAVE( ver ); return( ret ); } -#endif /* MBEDTLS_ECDSA_VERIFY_ALT */ + +/* + * Verify ECDSA signature of hashed message + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, + const mbedtls_mpi *r, + const mbedtls_mpi *s) +{ + ECDSA_VALIDATE_RET( grp != NULL ); + ECDSA_VALIDATE_RET( Q != NULL ); + ECDSA_VALIDATE_RET( r != NULL ); + ECDSA_VALIDATE_RET( s != NULL ); + ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); + + return( ecdsa_verify_restartable( grp, buf, blen, Q, r, s, NULL ) ); +} +#endif /* !MBEDTLS_ECDSA_VERIFY_ALT */ /* * Convert a signature (given by context) to ASN.1 @@ -313,30 +728,41 @@ static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, /* * Compute and write signature */ -int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, +int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hlen, unsigned char *sig, size_t *slen, int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) + void *p_rng, + mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; mbedtls_mpi r, s; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + ECDSA_VALIDATE_RET( slen != NULL ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s ); #if defined(MBEDTLS_ECDSA_DETERMINISTIC) - (void) f_rng; - (void) p_rng; - - MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d, - hash, hlen, md_alg ) ); + MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg, f_rng, + p_rng, rs_ctx ) ); #else (void) md_alg; +#if defined(MBEDTLS_ECDSA_SIGN_ALT) MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, hash, hlen, f_rng, p_rng ) ); -#endif +#else + /* Use the same RNG for both blinding and ephemeral key generation */ + MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng, f_rng, + p_rng, rs_ctx ) ); +#endif /* MBEDTLS_ECDSA_SIGN_ALT */ +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); @@ -347,13 +773,35 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t return( ret ); } -#if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \ +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + ECDSA_VALIDATE_RET( slen != NULL ); + return( mbedtls_ecdsa_write_signature_restartable( + ctx, md_alg, hash, hlen, sig, slen, f_rng, p_rng, NULL ) ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) && \ defined(MBEDTLS_ECDSA_DETERMINISTIC) int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, unsigned char *sig, size_t *slen, mbedtls_md_type_t md_alg ) { + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + ECDSA_VALIDATE_RET( slen != NULL ); return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen, NULL, NULL ) ); } @@ -365,12 +813,30 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, const unsigned char *sig, size_t slen ) +{ + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + return( mbedtls_ecdsa_read_signature_restartable( + ctx, hash, hlen, sig, slen, NULL ) ); +} + +/* + * Restartable read and check signature + */ +int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen, + mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; unsigned char *p = (unsigned char *) sig; const unsigned char *end = sig + slen; size_t len; mbedtls_mpi r, s; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s ); @@ -395,10 +861,15 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } - +#if defined(MBEDTLS_ECDSA_VERIFY_ALT) if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, - &ctx->Q, &r, &s ) ) != 0 ) + &ctx->Q, &r, &s ) ) != 0 ) goto cleanup; +#else + if( ( ret = ecdsa_verify_restartable( &ctx->grp, hash, hlen, + &ctx->Q, &r, &s, rs_ctx ) ) != 0 ) + goto cleanup; +#endif /* MBEDTLS_ECDSA_VERIFY_ALT */ /* At this point we know that the buffer starts with a valid signature. * Return 0 if the buffer just contains the signature, and a specific @@ -420,10 +891,18 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - return( mbedtls_ecp_group_load( &ctx->grp, gid ) || - mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ); + int ret = 0; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( f_rng != NULL ); + + ret = mbedtls_ecp_group_load( &ctx->grp, gid ); + if( ret != 0 ) + return( ret ); + + return( mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, + &ctx->Q, f_rng, p_rng ) ); } -#endif /* MBEDTLS_ECDSA_GENKEY_ALT */ +#endif /* !MBEDTLS_ECDSA_GENKEY_ALT */ /* * Set context from an mbedtls_ecp_keypair @@ -431,6 +910,8 @@ int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) { int ret; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( key != NULL ); if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 || ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 || @@ -447,6 +928,8 @@ int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_ke */ void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) { + ECDSA_VALIDATE( ctx != NULL ); + mbedtls_ecp_keypair_init( ctx ); } @@ -455,7 +938,53 @@ void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) */ void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) { + if( ctx == NULL ) + return; + mbedtls_ecp_keypair_free( ctx ); } +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Initialize a restart context + */ +void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx ) +{ + ECDSA_VALIDATE( ctx != NULL ); + + mbedtls_ecp_restart_init( &ctx->ecp ); + + ctx->ver = NULL; + ctx->sig = NULL; +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + ctx->det = NULL; +#endif +} + +/* + * Free the components of a restart context + */ +void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_restart_free( &ctx->ecp ); + + ecdsa_restart_ver_free( ctx->ver ); + mbedtls_free( ctx->ver ); + ctx->ver = NULL; + + ecdsa_restart_sig_free( ctx->sig ); + mbedtls_free( ctx->sig ); + ctx->sig = NULL; + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + ecdsa_restart_det_free( ctx->det ); + mbedtls_free( ctx->det ); + ctx->det = NULL; +#endif +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ + #endif /* MBEDTLS_ECDSA_C */ diff --git a/app/mbedtls/library/ecjpake.c b/app/mbedtls/library/ecjpake.c index ec5a4007db..1845c936ab 100644 --- a/app/mbedtls/library/ecjpake.c +++ b/app/mbedtls/library/ecjpake.c @@ -33,11 +33,18 @@ #if defined(MBEDTLS_ECJPAKE_C) #include "mbedtls/ecjpake.h" +#include "mbedtls/platform_util.h" #include #if !defined(MBEDTLS_ECJPAKE_ALT) +/* Parameter validation macros based on platform_util.h */ +#define ECJPAKE_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECJPAKE_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + /* * Convert a mbedtls_ecjpake_role to identifier string */ @@ -54,8 +61,7 @@ static const char * const ecjpake_id[] = { */ void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ) { - if( ctx == NULL ) - return; + ECJPAKE_VALIDATE( ctx != NULL ); ctx->md_info = NULL; mbedtls_ecp_group_init( &ctx->grp ); @@ -106,6 +112,11 @@ int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, { int ret; + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( role == MBEDTLS_ECJPAKE_CLIENT || + role == MBEDTLS_ECJPAKE_SERVER ); + ECJPAKE_VALIDATE_RET( secret != NULL || len == 0 ); + ctx->role = role; if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL ) @@ -127,6 +138,8 @@ int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, */ int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ) { + ECJPAKE_VALIDATE_RET( ctx != NULL ); + if( ctx->md_info == NULL || ctx->grp.id == MBEDTLS_ECP_DP_NONE || ctx->s.p == NULL ) @@ -213,7 +226,7 @@ static int ecjpake_hash( const mbedtls_md_info_t *md_info, p += id_len; /* Compute hash */ - mbedtls_md( md_info, buf, p - buf, hash ); + MBEDTLS_MPI_CHK( mbedtls_md( md_info, buf, p - buf, hash ) ); /* Turn it into an integer mod n */ MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash, @@ -504,6 +517,9 @@ int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, const unsigned char *buf, size_t len ) { + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, ctx->point_format, &ctx->grp.G, &ctx->Xp1, &ctx->Xp2, ID_PEER, @@ -518,6 +534,11 @@ int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + ECJPAKE_VALIDATE_RET( olen != NULL ); + ECJPAKE_VALIDATE_RET( f_rng != NULL ); + return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, ctx->point_format, &ctx->grp.G, &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2, @@ -560,6 +581,9 @@ int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, mbedtls_ecp_group grp; mbedtls_ecp_point G; /* C: GB, S: GA */ + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &G ); @@ -652,6 +676,11 @@ int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, const unsigned char *end = buf + len; size_t ec_len; + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + ECJPAKE_VALIDATE_RET( olen != NULL ); + ECJPAKE_VALIDATE_RET( f_rng != NULL ); + mbedtls_ecp_point_init( &G ); mbedtls_ecp_point_init( &Xm ); mbedtls_mpi_init( &xm ); @@ -727,6 +756,11 @@ int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, unsigned char kx[MBEDTLS_ECP_MAX_BYTES]; size_t x_bytes; + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + ECJPAKE_VALIDATE_RET( olen != NULL ); + ECJPAKE_VALIDATE_RET( f_rng != NULL ); + *olen = mbedtls_md_get_size( ctx->md_info ); if( len < *olen ) return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); @@ -917,7 +951,7 @@ static const unsigned char ecjpake_test_pms[] = { 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51 }; -/* Load my private keys and generate the correponding public keys */ +/* Load my private keys and generate the corresponding public keys */ static int ecjpake_test_load( mbedtls_ecjpake_context *ctx, const unsigned char *xm1, size_t len1, const unsigned char *xm2, size_t len2 ) diff --git a/app/mbedtls/library/ecp.c b/app/mbedtls/library/ecp.c index 75233f8cef..db36191b9b 100644 --- a/app/mbedtls/library/ecp.c +++ b/app/mbedtls/library/ecp.c @@ -26,6 +26,7 @@ * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf * RFC 4492 for the related TLS structures and constants + * RFC 7748 for the Curve448 and Curve25519 curve definitions * * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf * @@ -46,15 +47,51 @@ #include MBEDTLS_CONFIG_FILE #endif +/** + * \brief Function level alternative implementation. + * + * The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to + * replace certain functions in this module. The alternative implementations are + * typically hardware accelerators and need to activate the hardware before the + * computation starts and deactivate it after it finishes. The + * mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve + * this purpose. + * + * To preserve the correct functionality the following conditions must hold: + * + * - The alternative implementation must be activated by + * mbedtls_internal_ecp_init() before any of the replaceable functions is + * called. + * - mbedtls_internal_ecp_free() must \b only be called when the alternative + * implementation is activated. + * - mbedtls_internal_ecp_init() must \b not be called when the alternative + * implementation is activated. + * - Public functions must not return while the alternative implementation is + * activated. + * - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and + * before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) ) + * \endcode ensures that the alternative implementation supports the current + * group. + */ +#if defined(MBEDTLS_ECP_INTERNAL_ALT) +#endif + #if defined(MBEDTLS_ECP_C) #include "mbedtls/ecp.h" #include "mbedtls/threading.h" +#include "mbedtls/platform_util.h" #include #if !defined(MBEDTLS_ECP_ALT) +/* Parameter validation macros based on platform_util.h */ +#define ECP_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECP_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + #if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" #else @@ -72,11 +109,6 @@ #define inline __inline #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - #if defined(MBEDTLS_SELF_TEST) /* * Counts of point addition and doubling, and field multiplications. @@ -85,6 +117,233 @@ static void mbedtls_zeroize( void *v, size_t n ) { static unsigned long add_count, dbl_count, mul_count; #endif +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Maximum number of "basic operations" to be done in a row. + * + * Default value 0 means that ECC operations will not yield. + * Note that regardless of the value of ecp_max_ops, always at + * least one step is performed before yielding. + * + * Setting ecp_max_ops=1 can be suitable for testing purposes + * as it will interrupt computation at all possible points. + */ +static unsigned ecp_max_ops = 0; + +/* + * Set ecp_max_ops + */ +void mbedtls_ecp_set_max_ops( unsigned max_ops ) +{ + ecp_max_ops = max_ops; +} + +/* + * Check if restart is enabled + */ +int mbedtls_ecp_restart_is_enabled( void ) +{ + return( ecp_max_ops != 0 ); +} + +/* + * Restart sub-context for ecp_mul_comb() + */ +struct mbedtls_ecp_restart_mul +{ + mbedtls_ecp_point R; /* current intermediate result */ + size_t i; /* current index in various loops, 0 outside */ + mbedtls_ecp_point *T; /* table for precomputed points */ + unsigned char T_size; /* number of points in table T */ + enum { /* what were we doing last time we returned? */ + ecp_rsm_init = 0, /* nothing so far, dummy initial state */ + ecp_rsm_pre_dbl, /* precompute 2^n multiples */ + ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */ + ecp_rsm_pre_add, /* precompute remaining points by adding */ + ecp_rsm_pre_norm_add, /* normalize all precomputed points */ + ecp_rsm_comb_core, /* ecp_mul_comb_core() */ + ecp_rsm_final_norm, /* do the final normalization */ + } state; +}; + +/* + * Init restart_mul sub-context + */ +static void ecp_restart_rsm_init( mbedtls_ecp_restart_mul_ctx *ctx ) +{ + mbedtls_ecp_point_init( &ctx->R ); + ctx->i = 0; + ctx->T = NULL; + ctx->T_size = 0; + ctx->state = ecp_rsm_init; +} + +/* + * Free the components of a restart_mul sub-context + */ +static void ecp_restart_rsm_free( mbedtls_ecp_restart_mul_ctx *ctx ) +{ + unsigned char i; + + if( ctx == NULL ) + return; + + mbedtls_ecp_point_free( &ctx->R ); + + if( ctx->T != NULL ) + { + for( i = 0; i < ctx->T_size; i++ ) + mbedtls_ecp_point_free( ctx->T + i ); + mbedtls_free( ctx->T ); + } + + ecp_restart_rsm_init( ctx ); +} + +/* + * Restart context for ecp_muladd() + */ +struct mbedtls_ecp_restart_muladd +{ + mbedtls_ecp_point mP; /* mP value */ + mbedtls_ecp_point R; /* R intermediate result */ + enum { /* what should we do next? */ + ecp_rsma_mul1 = 0, /* first multiplication */ + ecp_rsma_mul2, /* second multiplication */ + ecp_rsma_add, /* addition */ + ecp_rsma_norm, /* normalization */ + } state; +}; + +/* + * Init restart_muladd sub-context + */ +static void ecp_restart_ma_init( mbedtls_ecp_restart_muladd_ctx *ctx ) +{ + mbedtls_ecp_point_init( &ctx->mP ); + mbedtls_ecp_point_init( &ctx->R ); + ctx->state = ecp_rsma_mul1; +} + +/* + * Free the components of a restart_muladd sub-context + */ +static void ecp_restart_ma_free( mbedtls_ecp_restart_muladd_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_point_free( &ctx->mP ); + mbedtls_ecp_point_free( &ctx->R ); + + ecp_restart_ma_init( ctx ); +} + +/* + * Initialize a restart context + */ +void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx ) +{ + ECP_VALIDATE( ctx != NULL ); + ctx->ops_done = 0; + ctx->depth = 0; + ctx->rsm = NULL; + ctx->ma = NULL; +} + +/* + * Free the components of a restart context + */ +void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + ecp_restart_rsm_free( ctx->rsm ); + mbedtls_free( ctx->rsm ); + + ecp_restart_ma_free( ctx->ma ); + mbedtls_free( ctx->ma ); + + mbedtls_ecp_restart_init( ctx ); +} + +/* + * Check if we can do the next step + */ +int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp, + mbedtls_ecp_restart_ctx *rs_ctx, + unsigned ops ) +{ + ECP_VALIDATE_RET( grp != NULL ); + + if( rs_ctx != NULL && ecp_max_ops != 0 ) + { + /* scale depending on curve size: the chosen reference is 256-bit, + * and multiplication is quadratic. Round to the closest integer. */ + if( grp->pbits >= 512 ) + ops *= 4; + else if( grp->pbits >= 384 ) + ops *= 2; + + /* Avoid infinite loops: always allow first step. + * Because of that, however, it's not generally true + * that ops_done <= ecp_max_ops, so the check + * ops_done > ecp_max_ops below is mandatory. */ + if( ( rs_ctx->ops_done != 0 ) && + ( rs_ctx->ops_done > ecp_max_ops || + ops > ecp_max_ops - rs_ctx->ops_done ) ) + { + return( MBEDTLS_ERR_ECP_IN_PROGRESS ); + } + + /* update running count */ + rs_ctx->ops_done += ops; + } + + return( 0 ); +} + +/* Call this when entering a function that needs its own sub-context */ +#define ECP_RS_ENTER( SUB ) do { \ + /* reset ops count for this call if top-level */ \ + if( rs_ctx != NULL && rs_ctx->depth++ == 0 ) \ + rs_ctx->ops_done = 0; \ + \ + /* set up our own sub-context if needed */ \ + if( mbedtls_ecp_restart_is_enabled() && \ + rs_ctx != NULL && rs_ctx->SUB == NULL ) \ + { \ + rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \ + if( rs_ctx->SUB == NULL ) \ + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \ + \ + ecp_restart_## SUB ##_init( rs_ctx->SUB ); \ + } \ +} while( 0 ) + +/* Call this when leaving a function that needs its own sub-context */ +#define ECP_RS_LEAVE( SUB ) do { \ + /* clear our sub-context when not in progress (done or error) */ \ + if( rs_ctx != NULL && rs_ctx->SUB != NULL && \ + ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \ + { \ + ecp_restart_## SUB ##_free( rs_ctx->SUB ); \ + mbedtls_free( rs_ctx->SUB ); \ + rs_ctx->SUB = NULL; \ + } \ + \ + if( rs_ctx != NULL ) \ + rs_ctx->depth--; \ +} while( 0 ) + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define ECP_RS_ENTER( sub ) (void) rs_ctx; +#define ECP_RS_LEAVE( sub ) (void) rs_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ @@ -99,7 +358,8 @@ static unsigned long add_count, dbl_count, mul_count; #define ECP_SHORTWEIERSTRASS #endif -#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \ + defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) #define ECP_MONTGOMERY #endif @@ -245,6 +505,9 @@ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name { const mbedtls_ecp_curve_info *curve_info; + if( name == NULL ) + return( NULL ); + for( curve_info = mbedtls_ecp_curve_list(); curve_info->grp_id != MBEDTLS_ECP_DP_NONE; curve_info++ ) @@ -275,8 +538,7 @@ static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp ) */ void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) { - if( pt == NULL ) - return; + ECP_VALIDATE( pt != NULL ); mbedtls_mpi_init( &pt->X ); mbedtls_mpi_init( &pt->Y ); @@ -288,10 +550,23 @@ void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) */ void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) { - if( grp == NULL ) - return; - - memset( grp, 0, sizeof( mbedtls_ecp_group ) ); + ECP_VALIDATE( grp != NULL ); + + grp->id = MBEDTLS_ECP_DP_NONE; + mbedtls_mpi_init( &grp->P ); + mbedtls_mpi_init( &grp->A ); + mbedtls_mpi_init( &grp->B ); + mbedtls_ecp_point_init( &grp->G ); + mbedtls_mpi_init( &grp->N ); + grp->pbits = 0; + grp->nbits = 0; + grp->h = 0; + grp->modp = NULL; + grp->t_pre = NULL; + grp->t_post = NULL; + grp->t_data = NULL; + grp->T = NULL; + grp->T_size = 0; } /* @@ -299,8 +574,7 @@ void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) */ void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ) { - if( key == NULL ) - return; + ECP_VALIDATE( key != NULL ); mbedtls_ecp_group_init( &key->grp ); mbedtls_mpi_init( &key->d ); @@ -346,7 +620,7 @@ void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ) mbedtls_free( grp->T ); } - mbedtls_zeroize( grp, sizeof( mbedtls_ecp_group ) ); + mbedtls_platform_zeroize( grp, sizeof( mbedtls_ecp_group ) ); } /* @@ -368,6 +642,8 @@ void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ) int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) { int ret; + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( Q != NULL ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) ); @@ -382,7 +658,10 @@ int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) */ int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ) { - return mbedtls_ecp_group_load( dst, src->id ); + ECP_VALIDATE_RET( dst != NULL ); + ECP_VALIDATE_RET( src != NULL ); + + return( mbedtls_ecp_group_load( dst, src->id ) ); } /* @@ -391,6 +670,7 @@ int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) { int ret; + ECP_VALIDATE_RET( pt != NULL ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) ); @@ -405,6 +685,8 @@ int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) */ int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) { + ECP_VALIDATE_RET( pt != NULL ); + return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ); } @@ -414,6 +696,9 @@ int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) { + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 && mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 && mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 ) @@ -431,6 +716,9 @@ int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, const char *x, const char *y ) { int ret; + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( x != NULL ); + ECP_VALIDATE_RET( y != NULL ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) ); @@ -443,16 +731,19 @@ int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, /* * Export a point into unsigned binary data (SEC1 2.3.3) */ -int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, - int format, size_t *olen, - unsigned char *buf, size_t buflen ) +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ) { int ret = 0; size_t plen; - - if( format != MBEDTLS_ECP_PF_UNCOMPRESSED && - format != MBEDTLS_ECP_PF_COMPRESSED ) - return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED || + format == MBEDTLS_ECP_PF_COMPRESSED ); /* * Common case: P == 0 @@ -499,11 +790,15 @@ int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ /* * Import a point from unsigned binary data (SEC1 2.3.4) */ -int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, - const unsigned char *buf, size_t ilen ) +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char *buf, size_t ilen ) { int ret; size_t plen; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( buf != NULL ); if( ilen < 1 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); @@ -538,11 +833,16 @@ int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_poi * opaque point <1..2^8-1>; * } ECPoint; */ -int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, - const unsigned char **buf, size_t buf_len ) +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len ) { unsigned char data_len; const unsigned char *buf_start; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); /* * We must have at least two bytes (1 for length, at least one for data) @@ -560,7 +860,7 @@ int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point buf_start = *buf; *buf += data_len; - return mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ); + return( mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ) ); } /* @@ -574,6 +874,12 @@ int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp unsigned char *buf, size_t blen ) { int ret; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED || + format == MBEDTLS_ECP_PF_COMPRESSED ); /* * buffer length must be at least one, for our length byte @@ -597,10 +903,33 @@ int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp /* * Set a group from an ECParameters record (RFC 4492) */ -int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ) +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, + const unsigned char **buf, size_t len ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, len ) ) != 0 ) + return( ret ); + + return( mbedtls_ecp_group_load( grp, grp_id ) ); +} + +/* + * Read a group id from an ECParameters record (RFC 4492) and convert it to + * mbedtls_ecp_group_id. + */ +int mbedtls_ecp_tls_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, size_t len ) { uint16_t tls_id; const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); /* * We expect at least three bytes (see below) @@ -624,7 +953,9 @@ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **bu if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); - return mbedtls_ecp_group_load( grp, curve_info->grp_id ); + *grp = curve_info->grp_id; + + return( 0 ); } /* @@ -634,6 +965,9 @@ int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, unsigned char *buf, size_t blen ) { const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( olen != NULL ); if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); @@ -712,25 +1046,29 @@ static int ecp_modp( mbedtls_mpi *N, const mbedtls_ecp_group *grp ) #define INC_MUL_COUNT #endif -#define MOD_MUL( N ) do { MBEDTLS_MPI_CHK( ecp_modp( &N, grp ) ); INC_MUL_COUNT } \ - while( 0 ) +#define MOD_MUL( N ) \ + do \ + { \ + MBEDTLS_MPI_CHK( ecp_modp( &(N), grp ) ); \ + INC_MUL_COUNT \ + } while( 0 ) /* * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi * N->s < 0 is a very fast test, which fails only if N is 0 */ -#define MOD_SUB( N ) \ - while( N.s < 0 && mbedtls_mpi_cmp_int( &N, 0 ) != 0 ) \ - MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &N, &N, &grp->P ) ) +#define MOD_SUB( N ) \ + while( (N).s < 0 && mbedtls_mpi_cmp_int( &(N), 0 ) != 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &(N), &(N), &grp->P ) ) /* * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. * We known P, N and the result are positive, so sub_abs is correct, and * a bit faster. */ -#define MOD_ADD( N ) \ - while( mbedtls_mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \ - MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) ) +#define MOD_ADD( N ) \ + while( mbedtls_mpi_cmp_mpi( &(N), &grp->P ) >= 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &(N), &(N), &grp->P ) ) #if defined(ECP_SHORTWEIERSTRASS) /* @@ -754,11 +1092,10 @@ static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p return( 0 ); #if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_normalize_jac( grp, pt ); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_normalize_jac( grp, pt ) ); #endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */ + mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); /* @@ -798,32 +1135,33 @@ static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p * Cost: 1N(t) := 1I + (6t - 3)M + 1S */ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, - mbedtls_ecp_point *T[], size_t t_len ) + mbedtls_ecp_point *T[], size_t T_size ) { int ret; size_t i; mbedtls_mpi *c, u, Zi, ZZi; - if( t_len < 2 ) + if( T_size < 2 ) return( ecp_normalize_jac( grp, *T ) ); #if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_normalize_jac_many(grp, T, t_len); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_normalize_jac_many( grp, T, T_size ) ); #endif - if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL ) + if( ( c = mbedtls_calloc( T_size, sizeof( mbedtls_mpi ) ) ) == NULL ) return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + for( i = 0; i < T_size; i++ ) + mbedtls_mpi_init( &c[i] ); + mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); /* * c[i] = Z_0 * ... * Z_i */ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) ); - for( i = 1; i < t_len; i++ ) + for( i = 1; i < T_size; i++ ) { MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) ); MOD_MUL( c[i] ); @@ -832,9 +1170,9 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, /* * u = 1 / (Z_0 * ... * Z_n) mod P */ - MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[T_size-1], &grp->P ) ); - for( i = t_len - 1; ; i-- ) + for( i = T_size - 1; ; i-- ) { /* * Zi = 1 / Z_i mod p @@ -874,7 +1212,7 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, cleanup: mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); - for( i = 0; i < t_len; i++ ) + for( i = 0; i < T_size; i++ ) mbedtls_mpi_free( &c[i] ); mbedtls_free( c ); @@ -931,10 +1269,8 @@ static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, #endif #if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_double_jac( grp, R, P ); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_double_jac( grp, R, P ) ); #endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */ mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U ); @@ -1029,10 +1365,8 @@ static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, #endif #if defined(MBEDTLS_ECP_ADD_MIXED_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_add_mixed( grp, R, P, Q ); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_add_mixed( grp, R, P, Q ) ); #endif /* MBEDTLS_ECP_ADD_MIXED_ALT */ /* @@ -1116,10 +1450,8 @@ static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p int count = 0; #if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng ); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng ) ); #endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */ p_size = ( grp->pbits + 7 ) / 8; @@ -1175,11 +1507,38 @@ static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p * modified version that provides resistance to SPA by avoiding zero * digits in the representation as in [3]. We modify the method further by * requiring that all K_i be odd, which has the small cost that our - * representation uses one more K_i, due to carries. + * representation uses one more K_i, due to carries, but saves on the size of + * the precomputed table. + * + * Summary of the comb method and its modifications: * - * Also, for the sake of compactness, only the seven low-order bits of x[i] - * are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in - * the paper): it is set if and only if if s_i == -1; + * - The goal is to compute m*P for some w*d-bit integer m. + * + * - The basic comb method splits m into the w-bit integers + * x[0] .. x[d-1] where x[i] consists of the bits in m whose + * index has residue i modulo d, and computes m * P as + * S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where + * S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P. + * + * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by + * .. + 2^{i-1} S[x[i-1]] - 2^i S[x[i]] + 2^{i+1} S[x[i]] + 2^{i+2} S[x[i+2]] .., + * thereby successively converting it into a form where all summands + * are nonzero, at the cost of negative summands. This is the basic idea of [3]. + * + * - More generally, even if x[i+1] != 0, we can first transform the sum as + * .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] .., + * and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]]. + * Performing and iterating this procedure for those x[i] that are even + * (keeping track of carry), we can transform the original sum into one of the form + * S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]] + * with all x'[i] odd. It is therefore only necessary to know S at odd indices, + * which is why we are only computing half of it in the first place in + * ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb. + * + * - For the sake of compactness, only the seven low-order bits of x[i] + * are used to represent its absolute value (K_i in the paper), and the msb + * of x[i] encodes the sign (s_i in the paper): it is set if and only if + * if s_i == -1; * * Calling conventions: * - x is an array of size d + 1 @@ -1188,8 +1547,8 @@ static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d * (the result will be incorrect if these assumptions are not satisfied) */ -static void ecp_comb_fixed( unsigned char x[], size_t d, - unsigned char w, const mbedtls_mpi *m ) +static void ecp_comb_recode_core( unsigned char x[], size_t d, + unsigned char w, const mbedtls_mpi *m ) { size_t i, j; unsigned char c, cc, adjust; @@ -1219,70 +1578,178 @@ static void ecp_comb_fixed( unsigned char x[], size_t d, } /* - * Precompute points for the comb method + * Precompute points for the adapted comb method * - * If i = i_{w-1} ... i_1 is the binary representation of i, then - * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P + * Assumption: T must be able to hold 2^{w - 1} elements. * - * T must be able to hold 2^{w - 1} elements + * Operation: If i = i_{w-1} ... i_1 is the binary representation of i, + * sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P. * * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) + * + * Note: Even comb values (those where P would be omitted from the + * sum defining T[i] above) are not needed in our adaption + * the comb method. See ecp_comb_recode_core(). + * + * This function currently works in four steps: + * (1) [dbl] Computation of intermediate T[i] for 2-power values of i + * (2) [norm_dbl] Normalization of coordinates of these T[i] + * (3) [add] Computation of all T[i] + * (4) [norm_add] Normalization of all T[i] + * + * Step 1 can be interrupted but not the others; together with the final + * coordinate normalization they are the largest steps done at once, depending + * on the window size. Here are operation counts for P-256: + * + * step (2) (3) (4) + * w = 5 142 165 208 + * w = 4 136 77 160 + * w = 3 130 33 136 + * w = 2 124 11 124 + * + * So if ECC operations are blocking for too long even with a low max_ops + * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order + * to minimize maximum blocking time. */ static int ecp_precompute_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point T[], const mbedtls_ecp_point *P, - unsigned char w, size_t d ) + unsigned char w, size_t d, + mbedtls_ecp_restart_ctx *rs_ctx ) { int ret; - unsigned char i, k; - size_t j; + unsigned char i; + size_t j = 0; + const unsigned char T_size = 1U << ( w - 1 ); mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1]; +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + { + if( rs_ctx->rsm->state == ecp_rsm_pre_dbl ) + goto dbl; + if( rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl ) + goto norm_dbl; + if( rs_ctx->rsm->state == ecp_rsm_pre_add ) + goto add; + if( rs_ctx->rsm->state == ecp_rsm_pre_norm_add ) + goto norm_add; + } +#else + (void) rs_ctx; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + { + rs_ctx->rsm->state = ecp_rsm_pre_dbl; + + /* initial state for the loop */ + rs_ctx->rsm->i = 0; + } + +dbl: +#endif /* * Set T[0] = P and * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) */ MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) ); - k = 0; - for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 ) + j = rs_ctx->rsm->i; + else +#endif + j = 0; + + for( ; j < d * ( w - 1 ); j++ ) { + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL ); + + i = 1U << ( j / d ); cur = T + i; - MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) ); - for( j = 0; j < d; j++ ) - MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) ); - TT[k++] = cur; + if( j % d == 0 ) + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) ); + + MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) ); } - MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl; + +norm_dbl: +#endif + /* + * Normalize current elements in T. As T has holes, + * use an auxiliary array of pointers to elements in T. + */ + j = 0; + for( i = 1; i < T_size; i <<= 1 ) + TT[j++] = T + i; + + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 ); + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_pre_add; + +add: +#endif /* * Compute the remaining ones using the minimal number of additions * Be careful to update T[2^l] only after using it! */ - k = 0; - for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + MBEDTLS_ECP_BUDGET( ( T_size - 1 ) * MBEDTLS_ECP_OPS_ADD ); + + for( i = 1; i < T_size; i <<= 1 ) { j = i; while( j-- ) - { MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) ); - TT[k++] = &T[i + j]; - } } - MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_pre_norm_add; + +norm_add: +#endif + /* + * Normalize final elements in T. Even though there are no holes now, we + * still need the auxiliary array for homogeneity with the previous + * call. Also, skip T[0] which is already normalised, being a copy of P. + */ + for( j = 0; j + 1 < T_size; j++ ) + TT[j] = T + j + 1; + + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 ); + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) ); cleanup: +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && + ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + if( rs_ctx->rsm->state == ecp_rsm_pre_dbl ) + rs_ctx->rsm->i = j; + } +#endif return( ret ); } /* * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] + * + * See ecp_comb_recode_core() for background */ static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - const mbedtls_ecp_point T[], unsigned char t_len, + const mbedtls_ecp_point T[], unsigned char T_size, unsigned char i ) { int ret; @@ -1292,7 +1759,7 @@ static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, ii = ( i & 0x7Fu ) >> 1; /* Read the whole table to thwart cache-based timing attacks */ - for( j = 0; j < t_len; j++ ) + for( j = 0; j < T_size; j++ ) { MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) ); @@ -1312,10 +1779,11 @@ static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, * Cost: d A + d D + 1 R */ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - const mbedtls_ecp_point T[], unsigned char t_len, + const mbedtls_ecp_point T[], unsigned char T_size, const unsigned char x[], size_t d, int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) { int ret; mbedtls_ecp_point Txi; @@ -1323,17 +1791,42 @@ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R mbedtls_ecp_point_init( &Txi ); - /* Start with a non-zero point and randomize its coordinates */ - i = d; - MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) ); - if( f_rng != 0 ) - MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); +#if !defined(MBEDTLS_ECP_RESTARTABLE) + (void) rs_ctx; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && + rs_ctx->rsm->state != ecp_rsm_comb_core ) + { + rs_ctx->rsm->i = 0; + rs_ctx->rsm->state = ecp_rsm_comb_core; + } + + /* new 'if' instead of nested for the sake of the 'else' branch */ + if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 ) + { + /* restore current index (R already pointing to rs_ctx->rsm->R) */ + i = rs_ctx->rsm->i; + } + else +#endif + { + /* Start with a non-zero point and randomize its coordinates */ + i = d; + MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, T_size, x[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) ); + if( f_rng != 0 ) + MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); + } - while( i-- != 0 ) + while( i != 0 ) { + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD ); + --i; + MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) ); - MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, T_size, x[i] ) ); MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); } @@ -1341,32 +1834,130 @@ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R mbedtls_ecp_point_free( &Txi ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && + ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + rs_ctx->rsm->i = i; + /* no need to save R, already pointing to rs_ctx->rsm->R */ + } +#endif + return( ret ); } /* - * Multiplication using the comb method, - * for curves in short Weierstrass form - */ -static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - const mbedtls_mpi *m, const mbedtls_ecp_point *P, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) + * Recode the scalar to get constant-time comb multiplication + * + * As the actual scalar recoding needs an odd scalar as a starting point, + * this wrapper ensures that by replacing m by N - m if necessary, and + * informs the caller that the result of multiplication will be negated. + * + * This works because we only support large prime order for Short Weierstrass + * curves, so N is always odd hence either m or N - m is. + * + * See ecp_comb_recode_core() for background. + */ +static int ecp_comb_recode_scalar( const mbedtls_ecp_group *grp, + const mbedtls_mpi *m, + unsigned char k[COMB_MAX_D + 1], + size_t d, + unsigned char w, + unsigned char *parity_trick ) { int ret; - unsigned char w, m_is_odd, p_eq_g, pre_len, i; - size_t d; - unsigned char k[COMB_MAX_D + 1]; - mbedtls_ecp_point *T; mbedtls_mpi M, mm; mbedtls_mpi_init( &M ); mbedtls_mpi_init( &mm ); - /* we need N to be odd to trnaform m in an odd number, check now */ + /* N is always odd (see above), just make extra sure */ if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + /* do we need the parity trick? */ + *parity_trick = ( mbedtls_mpi_get_bit( m, 0 ) == 0 ); + + /* execute parity fix in constant time */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, *parity_trick ) ); + + /* actual scalar recoding */ + ecp_comb_recode_core( k, d, w, &M ); + +cleanup: + mbedtls_mpi_free( &mm ); + mbedtls_mpi_free( &M ); + + return( ret ); +} + +/* + * Perform comb multiplication (for short Weierstrass curves) + * once the auxiliary table has been pre-computed. + * + * Scalar recoding may use a parity trick that makes us compute -m * P, + * if that is the case we'll need to recover m * P at the end. + */ +static int ecp_mul_comb_after_precomp( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *T, + unsigned char T_size, + unsigned char w, + size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + unsigned char parity_trick; + unsigned char k[COMB_MAX_D + 1]; + mbedtls_ecp_point *RR = R; + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + { + RR = &rs_ctx->rsm->R; + + if( rs_ctx->rsm->state == ecp_rsm_final_norm ) + goto final_norm; + } +#endif + + MBEDTLS_MPI_CHK( ecp_comb_recode_scalar( grp, m, k, d, w, + &parity_trick ) ); + MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, RR, T, T_size, k, d, + f_rng, p_rng, rs_ctx ) ); + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, RR, parity_trick ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_final_norm; + +final_norm: +#endif + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, RR ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, RR ) ); +#endif + +cleanup: + return( ret ); +} + +/* + * Pick window size based on curve size and whether we optimize for base point + */ +static unsigned char ecp_pick_window_size( const mbedtls_ecp_group *grp, + unsigned char p_eq_g ) +{ + unsigned char w; + /* * Minimize the number of multiplications, that is minimize * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) @@ -1379,14 +1970,8 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, * Just adding one avoids upping the cost of the first mul too much, * and the memory cost too. */ -#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 - p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && - mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); if( p_eq_g ) w++; -#else - p_eq_g = 0; -#endif /* * Make sure w is within bounds. @@ -1397,75 +1982,140 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, if( w >= grp->nbits ) w = 2; - /* Other sizes that depend on w */ - pre_len = 1U << ( w - 1 ); + return( w ); +} + +/* + * Multiplication using the comb method - for curves in short Weierstrass form + * + * This function is mainly responsible for administrative work: + * - managing the restart context if enabled + * - managing the table of precomputed points (passed between the below two + * functions): allocation, computation, ownership tranfer, freeing. + * + * It delegates the actual arithmetic work to: + * ecp_precompute_comb() and ecp_mul_comb_with_precomp() + * + * See comments on ecp_comb_recode_core() regarding the computation strategy. + */ +static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + unsigned char w, p_eq_g, i; + size_t d; + unsigned char T_size, T_ok; + mbedtls_ecp_point *T; + + ECP_RS_ENTER( rsm ); + + /* Is P the base point ? */ +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 + p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); +#else + p_eq_g = 0; +#endif + + /* Pick window size and deduce related sizes */ + w = ecp_pick_window_size( grp, p_eq_g ); + T_size = 1U << ( w - 1 ); d = ( grp->nbits + w - 1 ) / w; - /* - * Prepare precomputed points: if P == G we want to - * use grp->T if already initialized, or initialize it. - */ - T = p_eq_g ? grp->T : NULL; + /* Pre-computed table: do we have it already for the base point? */ + if( p_eq_g && grp->T != NULL ) + { + /* second pointer to the same table, will be deleted on exit */ + T = grp->T; + T_ok = 1; + } + else +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* Pre-computed table: do we have one in progress? complete? */ + if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL ) + { + /* transfer ownership of T from rsm to local function */ + T = rs_ctx->rsm->T; + rs_ctx->rsm->T = NULL; + rs_ctx->rsm->T_size = 0; - if( T == NULL ) + /* This effectively jumps to the call to mul_comb_after_precomp() */ + T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core; + } + else +#endif + /* Allocate table if we didn't have any */ { - T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) ); + T = mbedtls_calloc( T_size, sizeof( mbedtls_ecp_point ) ); if( T == NULL ) { ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; goto cleanup; } - MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) ); + for( i = 0; i < T_size; i++ ) + mbedtls_ecp_point_init( &T[i] ); + + T_ok = 0; + } + + /* Compute table (or finish computing it) if not done already */ + if( !T_ok ) + { + MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d, rs_ctx ) ); if( p_eq_g ) { + /* almost transfer ownership of T to the group, but keep a copy of + * the pointer to use for calling the next function more easily */ grp->T = T; - grp->T_size = pre_len; + grp->T_size = T_size; } } - /* - * Make sure M is odd (M = m or M = N - m, since N is odd) - * using the fact that m * P = - (N - m) * P - */ - m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 ); - MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) ); + /* Actual comb multiplication using precomputed points */ + MBEDTLS_MPI_CHK( ecp_mul_comb_after_precomp( grp, R, m, + T, T_size, w, d, + f_rng, p_rng, rs_ctx ) ); - /* - * Go for comb multiplication, R = M * P - */ - ecp_comb_fixed( k, d, w, &M ); - MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) ); +cleanup: - /* - * Now get m * P from M * P and normalize it - */ - MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) ); - MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + /* does T belong to the group? */ + if( T == grp->T ) + T = NULL; -cleanup: + /* does T belong to the restart context? */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL ) + { + /* transfer ownership of T from local function to rsm */ + rs_ctx->rsm->T_size = T_size; + rs_ctx->rsm->T = T; + T = NULL; + } +#endif - /* There are two cases where T is not stored in grp: - * - P != G - * - An intermediate operation failed before setting grp->T - * In either case, T must be freed. - */ - if( T != NULL && T != grp->T ) + /* did T belong to us? then let's destroy it! */ + if( T != NULL ) { - for( i = 0; i < pre_len; i++ ) + for( i = 0; i < T_size; i++ ) mbedtls_ecp_point_free( &T[i] ); mbedtls_free( T ); } - mbedtls_mpi_free( &M ); - mbedtls_mpi_free( &mm ); - + /* don't free R while in progress in case R == P */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) +#endif + /* prevent caller from using invalid value */ if( ret != 0 ) mbedtls_ecp_point_free( R ); + ECP_RS_LEAVE( rsm ); + return( ret ); } @@ -1489,10 +2139,8 @@ static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P int ret; #if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_normalize_mxz( grp, P ); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_normalize_mxz( grp, P ) ); #endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) ); @@ -1520,10 +2168,8 @@ static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P int count = 0; #if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng ); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng ); #endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */ p_size = ( grp->pbits + 7 ) / 8; @@ -1575,10 +2221,8 @@ static int ecp_double_add_mxz( const mbedtls_ecp_group *grp, mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB; #if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) - if ( mbedtls_internal_ecp_grp_capable( grp ) ) - { - return mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d ); - } + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d ) ); #endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */ mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B ); @@ -1675,54 +2319,85 @@ static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, #endif /* ECP_MONTGOMERY */ /* - * Multiplication R = m * P + * Restartable multiplication R = m * P */ -int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, +int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) { int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; #if defined(MBEDTLS_ECP_INTERNAL_ALT) char is_grp_capable = 0; #endif - - /* Common sanity checks */ - if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 ) - return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); - - if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 || - ( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 ) - return( ret ); + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* reset ops count for this call if top-level */ + if( rs_ctx != NULL && rs_ctx->depth++ == 0 ) + rs_ctx->ops_done = 0; +#endif #if defined(MBEDTLS_ECP_INTERNAL_ALT) - if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) - { + if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) ) MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* skip argument check when restarting */ + if( rs_ctx == NULL || rs_ctx->rsm == NULL ) +#endif + { + /* check_privkey is free */ + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_CHK ); + + /* Common sanity checks */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( grp, m ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); } -#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; #if defined(ECP_MONTGOMERY) if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) - ret = ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ); - + MBEDTLS_MPI_CHK( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) ); #endif #if defined(ECP_SHORTWEIERSTRASS) if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) - ret = ecp_mul_comb( grp, R, m, P, f_rng, p_rng ); - + MBEDTLS_MPI_CHK( ecp_mul_comb( grp, R, m, P, f_rng, p_rng, rs_ctx ) ); #endif -#if defined(MBEDTLS_ECP_INTERNAL_ALT) + cleanup: - if ( is_grp_capable ) - { +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if( is_grp_capable ) mbedtls_internal_ecp_free( grp ); - } - #endif /* MBEDTLS_ECP_INTERNAL_ALT */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL ) + rs_ctx->depth--; +#endif + return( ret ); } +/* + * Multiplication R = m * P + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + return( mbedtls_ecp_mul_restartable( grp, R, m, P, f_rng, p_rng, NULL ) ); +} + #if defined(ECP_SHORTWEIERSTRASS) /* * Check that an affine point is valid as a public key, @@ -1780,7 +2455,8 @@ static int ecp_check_pubkey_sw( const mbedtls_ecp_group *grp, const mbedtls_ecp_ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, - const mbedtls_ecp_point *P ) + const mbedtls_ecp_point *P, + mbedtls_ecp_restart_ctx *rs_ctx ) { int ret; @@ -1796,7 +2472,8 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, } else { - MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, R, m, P, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, R, m, P, + NULL, NULL, rs_ctx ) ); } cleanup: @@ -1804,51 +2481,118 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, } /* - * Linear combination + * Restartable linear combination * NOT constant-time */ -int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, +int mbedtls_ecp_muladd_restartable( + mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, - const mbedtls_mpi *n, const mbedtls_ecp_point *Q ) + const mbedtls_mpi *n, const mbedtls_ecp_point *Q, + mbedtls_ecp_restart_ctx *rs_ctx ) { int ret; mbedtls_ecp_point mP; + mbedtls_ecp_point *pmP = &mP; + mbedtls_ecp_point *pR = R; #if defined(MBEDTLS_ECP_INTERNAL_ALT) char is_grp_capable = 0; #endif + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( n != NULL ); + ECP_VALIDATE_RET( Q != NULL ); if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS ) return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); mbedtls_ecp_point_init( &mP ); - MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) ); - MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R, n, Q ) ); + ECP_RS_ENTER( ma ); -#if defined(MBEDTLS_ECP_INTERNAL_ALT) - if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) { - MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); + /* redirect intermediate results to restart context */ + pmP = &rs_ctx->ma->mP; + pR = &rs_ctx->ma->R; + + /* jump to next operation */ + if( rs_ctx->ma->state == ecp_rsma_mul2 ) + goto mul2; + if( rs_ctx->ma->state == ecp_rsma_add ) + goto add; + if( rs_ctx->ma->state == ecp_rsma_norm ) + goto norm; } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pmP, m, P, rs_ctx ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + rs_ctx->ma->state = ecp_rsma_mul2; + +mul2: +#endif + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pR, n, Q, rs_ctx ) ); + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) ) + MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); #endif /* MBEDTLS_ECP_INTERNAL_ALT */ - MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) ); - MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); -cleanup: +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + rs_ctx->ma->state = ecp_rsma_add; +add: +#endif + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_ADD ); + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, pR, pmP, pR ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + rs_ctx->ma->state = ecp_rsma_norm; + +norm: +#endif + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, pR ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, pR ) ); +#endif + +cleanup: #if defined(MBEDTLS_ECP_INTERNAL_ALT) - if ( is_grp_capable ) - { + if( is_grp_capable ) mbedtls_internal_ecp_free( grp ); - } - #endif /* MBEDTLS_ECP_INTERNAL_ALT */ + mbedtls_ecp_point_free( &mP ); + ECP_RS_LEAVE( ma ); + return( ret ); } +/* + * Linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ) +{ + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( n != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + return( mbedtls_ecp_muladd_restartable( grp, R, m, P, n, Q, NULL ) ); +} #if defined(ECP_MONTGOMERY) /* @@ -1857,6 +2601,8 @@ int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) { /* [Curve25519 p. 5] Just check X is the correct number of bytes */ + /* Allow any public value, if it's too big then we'll just reduce it mod p + * (RFC 7748 sec. 5 para. 3). */ if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 ) return( MBEDTLS_ERR_ECP_INVALID_KEY ); @@ -1867,8 +2613,12 @@ static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_ /* * Check that a point is valid as a public key */ -int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt ) { + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + /* Must use affine coordinates */ if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 ) return( MBEDTLS_ERR_ECP_INVALID_KEY ); @@ -1887,19 +2637,26 @@ int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_po /* * Check that an mbedtls_mpi is valid as a private key */ -int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ) +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, + const mbedtls_mpi *d ) { + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + #if defined(ECP_MONTGOMERY) if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) { - /* see [Curve25519] page 5 */ + /* see RFC 7748 sec. 5 para. 5 */ if( mbedtls_mpi_get_bit( d, 0 ) != 0 || mbedtls_mpi_get_bit( d, 1 ) != 0 || - mbedtls_mpi_get_bit( d, 2 ) != 0 || mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */ return( MBEDTLS_ERR_ECP_INVALID_KEY ); - else - return( 0 ); + + /* see [Curve25519] page 5 */ + if( grp->nbits == 254 && mbedtls_mpi_get_bit( d, 2 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + return( 0 ); } #endif /* ECP_MONTGOMERY */ #if defined(ECP_SHORTWEIERSTRASS) @@ -1918,16 +2675,21 @@ int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi * } /* - * Generate a keypair with configurable base point + * Generate a private key */ -int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, - const mbedtls_ecp_point *G, - mbedtls_mpi *d, mbedtls_ecp_point *Q, +int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp, + mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - int ret; - size_t n_size = ( grp->nbits + 7 ) / 8; + int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + size_t n_size; + + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); + + n_size = ( grp->nbits + 7 ) / 8; #if defined(ECP_MONTGOMERY) if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) @@ -1946,13 +2708,17 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, else MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) ); - /* Make sure the last three bits are unset */ + /* Make sure the last two bits are unset for Curve448, three bits for + Curve25519 */ MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + if( grp->nbits == 254 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + } } - else #endif /* ECP_MONTGOMERY */ + #if defined(ECP_SHORTWEIERSTRASS) if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) { @@ -1986,15 +2752,33 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ); } - else #endif /* ECP_SHORTWEIERSTRASS */ - return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); cleanup: - if( ret != 0 ) - return( ret ); + return( ret ); +} + +/* + * Generate a keypair with configurable base point + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + ECP_VALIDATE_RET( G != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); - return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); +cleanup: + return( ret ); } /* @@ -2005,6 +2789,11 @@ int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); + return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) ); } @@ -2015,6 +2804,8 @@ int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; + ECP_VALIDATE_RET( key != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) return( ret ); @@ -2030,6 +2821,8 @@ int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ec int ret; mbedtls_ecp_point Q; mbedtls_ecp_group grp; + ECP_VALIDATE_RET( pub != NULL ); + ECP_VALIDATE_RET( prv != NULL ); if( pub->grp.id == MBEDTLS_ECP_DP_NONE || pub->grp.id != prv->grp.id || diff --git a/app/mbedtls/library/ecp_curves.c b/app/mbedtls/library/ecp_curves.c index df5ac3eea5..282481d053 100644 --- a/app/mbedtls/library/ecp_curves.c +++ b/app/mbedtls/library/ecp_curves.c @@ -28,11 +28,18 @@ #if defined(MBEDTLS_ECP_C) #include "mbedtls/ecp.h" +#include "mbedtls/platform_util.h" #include #if !defined(MBEDTLS_ECP_ALT) +/* Parameter validation macros based on platform_util.h */ +#define ECP_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECP_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ !defined(inline) && !defined(__cplusplus) #define inline __inline @@ -44,11 +51,11 @@ */ #if defined(MBEDTLS_HAVE_INT32) -#define BYTES_TO_T_UINT_4( a, b, c, d ) \ - ( (mbedtls_mpi_uint) a << 0 ) | \ - ( (mbedtls_mpi_uint) b << 8 ) | \ - ( (mbedtls_mpi_uint) c << 16 ) | \ - ( (mbedtls_mpi_uint) d << 24 ) +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + ( (mbedtls_mpi_uint) (a) << 0 ) | \ + ( (mbedtls_mpi_uint) (b) << 8 ) | \ + ( (mbedtls_mpi_uint) (c) << 16 ) | \ + ( (mbedtls_mpi_uint) (d) << 24 ) #define BYTES_TO_T_UINT_2( a, b ) \ BYTES_TO_T_UINT_4( a, b, 0, 0 ) @@ -60,14 +67,14 @@ #else /* 64-bits */ #define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ - ( (mbedtls_mpi_uint) a << 0 ) | \ - ( (mbedtls_mpi_uint) b << 8 ) | \ - ( (mbedtls_mpi_uint) c << 16 ) | \ - ( (mbedtls_mpi_uint) d << 24 ) | \ - ( (mbedtls_mpi_uint) e << 32 ) | \ - ( (mbedtls_mpi_uint) f << 40 ) | \ - ( (mbedtls_mpi_uint) g << 48 ) | \ - ( (mbedtls_mpi_uint) h << 56 ) + ( (mbedtls_mpi_uint) (a) << 0 ) | \ + ( (mbedtls_mpi_uint) (b) << 8 ) | \ + ( (mbedtls_mpi_uint) (c) << 16 ) | \ + ( (mbedtls_mpi_uint) (d) << 24 ) | \ + ( (mbedtls_mpi_uint) (e) << 32 ) | \ + ( (mbedtls_mpi_uint) (f) << 40 ) | \ + ( (mbedtls_mpi_uint) (g) << 48 ) | \ + ( (mbedtls_mpi_uint) (h) << 56 ) #define BYTES_TO_T_UINT_4( a, b, c, d ) \ BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 ) @@ -627,6 +634,9 @@ static int ecp_mod_p521( mbedtls_mpi * ); #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) static int ecp_mod_p255( mbedtls_mpi * ); #endif +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +static int ecp_mod_p448( mbedtls_mpi * ); +#endif #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) static int ecp_mod_p192k1( mbedtls_mpi * ); #endif @@ -670,7 +680,12 @@ static int ecp_use_curve25519( mbedtls_ecp_group *grp ) MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 19 ) ); grp->pbits = mbedtls_mpi_bitlen( &grp->P ); - /* Y intentionaly not set, since we use x/z coordinates. + /* N = 2^252 + 27742317777372353535851937790883648493 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->N, 16, + "14DEF9DEA2F79CD65812631A5CF5D3ED" ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 252, 1 ) ); + + /* Y intentionally not set, since we use x/z coordinates. * This is used as a marker to identify Montgomery curves! */ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 9 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); @@ -687,11 +702,58 @@ static int ecp_use_curve25519( mbedtls_ecp_group *grp ) } #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +/* + * Specialized function for creating the Curve448 group + */ +static int ecp_use_curve448( mbedtls_ecp_group *grp ) +{ + mbedtls_mpi Ns; + int ret; + + mbedtls_mpi_init( &Ns ); + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "98AA" ) ); + + /* P = 2^448 - 2^224 - 1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) ); + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 5 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); + mbedtls_mpi_free( &grp->G.Y ); + + /* N = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 446, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &Ns, 16, + "8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D" ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &grp->N, &grp->N, &Ns ) ); + + /* Actually, the required msb for private keys */ + grp->nbits = 447; + +cleanup: + mbedtls_mpi_free( &Ns ); + if( ret != 0 ) + mbedtls_ecp_group_free( grp ); + + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + /* * Set a group using well-known domain parameters */ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) { + ECP_VALIDATE_RET( grp != NULL ); mbedtls_ecp_group_free( grp ); grp->id = id; @@ -767,6 +829,12 @@ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) return( ecp_use_curve25519( grp ) ); #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + grp->modp = ecp_mod_p448; + return( ecp_use_curve448( grp ) ); +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + default: mbedtls_ecp_group_free( grp ); return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); @@ -822,7 +890,7 @@ static inline void carry64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry ) } #define WIDTH 8 / sizeof( mbedtls_mpi_uint ) -#define A( i ) N->p + i * WIDTH +#define A( i ) N->p + (i) * WIDTH #define ADD( i ) add64( p, A( i ), &c ) #define NEXT p += WIDTH; carry64( p, &c ) #define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0 @@ -887,7 +955,8 @@ static int ecp_mod_p192( mbedtls_mpi *N ) #else /* 64-bit */ #define MAX32 N->n * 2 -#define A( j ) j % 2 ? (uint32_t)( N->p[j/2] >> 32 ) : (uint32_t)( N->p[j/2] ) +#define A( j ) (j) % 2 ? (uint32_t)( N->p[(j)/2] >> 32 ) : \ + (uint32_t)( N->p[(j)/2] ) #define STORE32 \ if( i % 2 ) { \ N->p[i/2] &= 0x00000000FFFFFFFF; \ @@ -921,20 +990,21 @@ static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry ) * Helpers for the main 'loop' * (see fix_negative for the motivation of C) */ -#define INIT( b ) \ - int ret; \ - signed char c = 0, cc; \ - uint32_t cur; \ - size_t i = 0, bits = b; \ - mbedtls_mpi C; \ - mbedtls_mpi_uint Cp[ b / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \ - \ - C.s = 1; \ - C.n = b / 8 / sizeof( mbedtls_mpi_uint) + 1; \ - C.p = Cp; \ - memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \ - \ - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, b * 2 / 8 / sizeof( mbedtls_mpi_uint ) ) ); \ +#define INIT( b ) \ + int ret; \ + signed char c = 0, cc; \ + uint32_t cur; \ + size_t i = 0, bits = (b); \ + mbedtls_mpi C; \ + mbedtls_mpi_uint Cp[ (b) / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \ + \ + C.s = 1; \ + C.n = (b) / 8 / sizeof( mbedtls_mpi_uint) + 1; \ + C.p = Cp; \ + memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \ + \ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, (b) * 2 / 8 / \ + sizeof( mbedtls_mpi_uint ) ) ); \ LOAD32; #define NEXT \ @@ -1176,7 +1246,7 @@ static int ecp_mod_p255( mbedtls_mpi *N ) M.s = 1; M.n = N->n - ( P255_WIDTH - 1 ); if( M.n > P255_WIDTH + 1 ) - M.n = P255_WIDTH + 1; + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); M.p = Mp; memset( Mp, 0, sizeof Mp ); memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); @@ -1197,6 +1267,77 @@ static int ecp_mod_p255( mbedtls_mpi *N ) } #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + +/* Size of p448 in terms of mbedtls_mpi_uint */ +#define P448_WIDTH ( 448 / 8 / sizeof( mbedtls_mpi_uint ) ) + +/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */ +#define DIV_ROUND_UP( X, Y ) ( ( ( X ) + ( Y ) - 1 ) / ( Y ) ) +#define P224_WIDTH_MIN ( 28 / sizeof( mbedtls_mpi_uint ) ) +#define P224_WIDTH_MAX DIV_ROUND_UP( 28, sizeof( mbedtls_mpi_uint ) ) +#define P224_UNUSED_BITS ( ( P224_WIDTH_MAX * sizeof( mbedtls_mpi_uint ) * 8 ) - 224 ) + +/* + * Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 + * Write N as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return + * A0 + A1 + B1 + (B0 + B1) * 2^224. This is different to the reference + * implementation of Curve448, which uses its own special 56-bit limbs rather + * than a generic bignum library. We could squeeze some extra speed out on + * 32-bit machines by splitting N up into 32-bit limbs and doing the + * arithmetic using the limbs directly as we do for the NIST primes above, + * but for 64-bit targets it should use half the number of operations if we do + * the reduction with 224-bit limbs, since mpi_add_mpi will then use 64-bit adds. + */ +static int ecp_mod_p448( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M, Q; + mbedtls_mpi_uint Mp[P448_WIDTH + 1], Qp[P448_WIDTH]; + + if( N->n <= P448_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P448_WIDTH ); + if( M.n > P448_WIDTH ) + /* Shouldn't be called with N larger than 2^896! */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + M.p = Mp; + memset( Mp, 0, sizeof( Mp ) ); + memcpy( Mp, N->p + P448_WIDTH, M.n * sizeof( mbedtls_mpi_uint ) ); + + /* N = A0 */ + for( i = P448_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N += A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) ); + + /* Q = B1, N += B1 */ + Q = M; + Q.p = Qp; + memcpy( Qp, Mp, sizeof( Qp ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Q, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &Q ) ); + + /* M = (B0 + B1) * 2^224, N += M */ + if( sizeof( mbedtls_mpi_uint ) > 4 ) + Mp[P224_WIDTH_MIN] &= ( (mbedtls_mpi_uint)-1 ) >> ( P224_UNUSED_BITS ); + for( i = P224_WIDTH_MAX; i < M.n; ++i ) + Mp[i] = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &Q ) ); + M.n = P448_WIDTH + 1; /* Make room for shifted carry bit from the addition */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &M, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) diff --git a/app/mbedtls/library/entropy.c b/app/mbedtls/library/entropy.c index e17512e779..f8db1a5503 100644 --- a/app/mbedtls/library/entropy.c +++ b/app/mbedtls/library/entropy.c @@ -35,6 +35,7 @@ #include "mbedtls/entropy.h" #include "mbedtls/entropy_poll.h" +#include "mbedtls/platform_util.h" #include @@ -59,11 +60,6 @@ #include "mbedtls/havege.h" #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - #define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) @@ -140,7 +136,7 @@ void mbedtls_entropy_free( mbedtls_entropy_context *ctx ) ctx->initial_entropy_run = 0; #endif ctx->source_count = 0; - mbedtls_zeroize( ctx->source, sizeof( ctx->source ) ); + mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) ); ctx->accumulator_started = 0; } @@ -232,7 +228,7 @@ static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id #endif cleanup: - mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); return( ret ); } @@ -300,7 +296,7 @@ static int entropy_gather_internal( mbedtls_entropy_context *ctx ) ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; cleanup: - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); return( ret ); } @@ -433,7 +429,7 @@ int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) ret = 0; exit: - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) @@ -486,7 +482,7 @@ int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *p ret = 0; exit: - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); fclose( f ); return( ret ); @@ -516,7 +512,7 @@ int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char * fclose( f ); - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); if( ret != 0 ) return( ret ); diff --git a/app/mbedtls/library/entropy_poll.c b/app/mbedtls/library/entropy_poll.c index 02b25a2721..4556f88a55 100644 --- a/app/mbedtls/library/entropy_poll.c +++ b/app/mbedtls/library/entropy_poll.c @@ -19,19 +19,25 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ +#if defined(__linux__) +/* Ensure that syscall() is available even when compiling with -std=c99 */ +#define _GNU_SOURCE +#endif + #if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/config.h" #else #include MBEDTLS_CONFIG_FILE #endif +#include + #if defined(MBEDTLS_ENTROPY_C) #include "mbedtls/entropy.h" #include "mbedtls/entropy_poll.h" #if defined(MBEDTLS_TIMING_C) -#include #include "mbedtls/timing.h" #endif #if defined(MBEDTLS_HAVEGE_C) @@ -44,7 +50,8 @@ #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ - !defined(__APPLE__) && !defined(_WIN32) + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) #error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" #endif diff --git a/app/mbedtls/library/error.c b/app/mbedtls/library/error.c index b173c7e8ef..c596f0bcc5 100644 --- a/app/mbedtls/library/error.c +++ b/app/mbedtls/library/error.c @@ -49,6 +49,10 @@ #include "mbedtls/arc4.h" #endif +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/aria.h" +#endif + #if defined(MBEDTLS_BASE64_C) #include "mbedtls/base64.h" #endif @@ -69,6 +73,14 @@ #include "mbedtls/ccm.h" #endif +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + #if defined(MBEDTLS_CIPHER_C) #include "mbedtls/cipher.h" #endif @@ -101,6 +113,10 @@ #include "mbedtls/gcm.h" #endif +#if defined(MBEDTLS_HKDF_C) +#include "mbedtls/hkdf.h" +#endif + #if defined(MBEDTLS_HMAC_DRBG_C) #include "mbedtls/hmac_drbg.h" #endif @@ -149,6 +165,14 @@ #include "mbedtls/pkcs5.h" #endif +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#endif + +#if defined(MBEDTLS_POLY1305_C) +#include "mbedtls/poly1305.h" +#endif + #if defined(MBEDTLS_RIPEMD160_C) #include "mbedtls/ripemd160.h" #endif @@ -256,19 +280,21 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) if( use_ret == -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) ) mbedtls_snprintf( buf, buflen, "ECP - The buffer is too small to write to" ); if( use_ret == -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) ) - mbedtls_snprintf( buf, buflen, "ECP - Requested curve not available" ); + mbedtls_snprintf( buf, buflen, "ECP - The requested feature is not available, for example, the requested curve is not supported" ); if( use_ret == -(MBEDTLS_ERR_ECP_VERIFY_FAILED) ) mbedtls_snprintf( buf, buflen, "ECP - The signature is not valid" ); if( use_ret == -(MBEDTLS_ERR_ECP_ALLOC_FAILED) ) mbedtls_snprintf( buf, buflen, "ECP - Memory allocation failed" ); if( use_ret == -(MBEDTLS_ERR_ECP_RANDOM_FAILED) ) - mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as (ephemeral) key, failed" ); + mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as ephemeral key, failed" ); if( use_ret == -(MBEDTLS_ERR_ECP_INVALID_KEY) ) mbedtls_snprintf( buf, buflen, "ECP - Invalid private or public key" ); if( use_ret == -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH) ) mbedtls_snprintf( buf, buflen, "ECP - The buffer contains a valid signature followed by more data" ); if( use_ret == -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) ) - mbedtls_snprintf( buf, buflen, "ECP - ECP hardware accelerator failed" ); + mbedtls_snprintf( buf, buflen, "ECP - The ECP hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "ECP - Operation in progress, call again with the same parameters to continue" ); #endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_MD_C) @@ -478,7 +504,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) if( use_ret == -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) ) mbedtls_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" ); if( use_ret == -(MBEDTLS_ERR_SSL_WANT_READ) ) - mbedtls_snprintf( buf, buflen, "SSL - Connection requires a read call" ); + mbedtls_snprintf( buf, buflen, "SSL - No data of requested type currently available on underlying transport" ); if( use_ret == -(MBEDTLS_ERR_SSL_WANT_WRITE) ) mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" ); if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) ) @@ -491,6 +517,14 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "SSL - The alert message received indicates a non-fatal error" ); if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) ) mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that further message-processing should be done" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" ); + if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "SSL - A cryptographic operation is in progress. Try again later" ); #endif /* MBEDTLS_SSL_TLS_C */ #if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) @@ -533,7 +567,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) ) mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" ); if( use_ret == -(MBEDTLS_ERR_X509_FATAL_ERROR) ) - mbedtls_snprintf( buf, buflen, "X509 - A fatal error occured, eg the chain is too long or the vrfy callback failed" ); + mbedtls_snprintf( buf, buflen, "X509 - A fatal error occurred, eg the chain is too long or the vrfy callback failed" ); #endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ // END generated code @@ -570,6 +604,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "AES - Invalid key length" ); if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) ) mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_AES_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid input data" ); if( use_ret == -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) ) mbedtls_snprintf( buf, buflen, "AES - Feature not available. For example, an unsupported AES key size" ); if( use_ret == -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED) ) @@ -581,6 +617,17 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "ARC4 - ARC4 hardware accelerator failed" ); #endif /* MBEDTLS_ARC4_C */ +#if defined(MBEDTLS_ARIA_C) + if( use_ret == -(MBEDTLS_ERR_ARIA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "ARIA - Bad input data" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ARIA - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "ARIA - Feature not available. For example, an unsupported ARIA key size" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "ARIA - ARIA hardware accelerator failed" ); +#endif /* MBEDTLS_ARIA_C */ + #if defined(MBEDTLS_ASN1_PARSE_C) if( use_ret == -(MBEDTLS_ERR_ASN1_OUT_OF_DATA) ) mbedtls_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" ); @@ -625,17 +672,17 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) #endif /* MBEDTLS_BIGNUM_C */ #if defined(MBEDTLS_BLOWFISH_C) - if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH) ) - mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid key length" ); - if( use_ret == -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED) ) - mbedtls_snprintf( buf, buflen, "BLOWFISH - Blowfish hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Bad input data" ); if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Blowfish hardware accelerator failed" ); #endif /* MBEDTLS_BLOWFISH_C */ #if defined(MBEDTLS_CAMELLIA_C) - if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH) ) - mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Bad input data" ); if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); if( use_ret == -(MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED) ) @@ -651,6 +698,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "CCM - CCM hardware accelerator failed" ); #endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHA20_C) + if( use_ret == -(MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Invalid input parameter(s)" ); + if( use_ret == -(MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Feature not available. For example, s part of the API is not implemented" ); + if( use_ret == -(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Chacha20 hardware accelerator failed" ); +#endif /* MBEDTLS_CHACHA20_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_BAD_STATE) ) + mbedtls_snprintf( buf, buflen, "CHACHAPOLY - The requested operation is not permitted in the current state" ); + if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CHACHAPOLY - Authenticated decryption failed: data was not authentic" ); +#endif /* MBEDTLS_CHACHAPOLY_C */ + #if defined(MBEDTLS_CMAC_C) if( use_ret == -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED) ) mbedtls_snprintf( buf, buflen, "CMAC - CMAC hardware accelerator failed" ); @@ -696,6 +759,11 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" ); #endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_HKDF_C) + if( use_ret == -(MBEDTLS_ERR_HKDF_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "HKDF - Bad input parameters to function" ); +#endif /* MBEDTLS_HKDF_C */ + #if defined(MBEDTLS_HMAC_DRBG_C) if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) ) mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" ); @@ -745,6 +813,10 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" ); if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) ) mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" ); + if( use_ret == -(MBEDTLS_ERR_NET_POLL_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Polling the net context failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "NET - Input invalid" ); #endif /* MBEDTLS_NET_C */ #if defined(MBEDTLS_OID_C) @@ -759,6 +831,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" ); #endif /* MBEDTLS_PADLOCK_C */ +#if defined(MBEDTLS_PLATFORM_C) + if( use_ret == -(MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "PLATFORM - Hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) ) + mbedtls_snprintf( buf, buflen, "PLATFORM - The requested feature is not supported by the platform" ); +#endif /* MBEDTLS_PLATFORM_C */ + +#if defined(MBEDTLS_POLY1305_C) + if( use_ret == -(MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Invalid input parameter(s)" ); + if( use_ret == -(MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Feature not available. For example, s part of the API is not implemented" ); + if( use_ret == -(MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Poly1305 hardware accelerator failed" ); +#endif /* MBEDTLS_POLY1305_C */ + #if defined(MBEDTLS_RIPEMD160_C) if( use_ret == -(MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED) ) mbedtls_snprintf( buf, buflen, "RIPEMD160 - RIPEMD160 hardware accelerator failed" ); @@ -767,16 +855,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) #if defined(MBEDTLS_SHA1_C) if( use_ret == -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED) ) mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_SHA1_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 input data was malformed" ); #endif /* MBEDTLS_SHA1_C */ #if defined(MBEDTLS_SHA256_C) if( use_ret == -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED) ) mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_SHA256_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 input data was malformed" ); #endif /* MBEDTLS_SHA256_C */ #if defined(MBEDTLS_SHA512_C) if( use_ret == -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED) ) mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_SHA512_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 input data was malformed" ); #endif /* MBEDTLS_SHA512_C */ #if defined(MBEDTLS_THREADING_C) diff --git a/app/mbedtls/library/gcm.c b/app/mbedtls/library/gcm.c index 294a86d3d4..675926a518 100644 --- a/app/mbedtls/library/gcm.c +++ b/app/mbedtls/library/gcm.c @@ -38,6 +38,7 @@ #if defined(MBEDTLS_GCM_C) #include "mbedtls/gcm.h" +#include "mbedtls/platform_util.h" #include @@ -47,9 +48,8 @@ #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) #include "mbedtls/aes.h" -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else +#if !defined(MBEDTLS_PLATFORM_C) #include #define mbedtls_printf printf #endif /* MBEDTLS_PLATFORM_C */ @@ -57,6 +57,12 @@ #if !defined(MBEDTLS_GCM_ALT) +/* Parameter validation macros */ +#define GCM_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_GCM_BAD_INPUT ) +#define GCM_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + /* * 32-bit integer manipulation macros (big endian) */ @@ -80,16 +86,12 @@ } #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * Initialize a context */ void mbedtls_gcm_init( mbedtls_gcm_context *ctx ) { + GCM_VALIDATE( ctx != NULL ); memset( ctx, 0, sizeof( mbedtls_gcm_context ) ); } @@ -169,6 +171,10 @@ int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, int ret; const mbedtls_cipher_info_t *cipher_info; + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( key != NULL ); + GCM_VALIDATE_RET( keybits == 128 || keybits == 192 || keybits == 256 ); + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); if( cipher_info == NULL ) return( MBEDTLS_ERR_GCM_BAD_INPUT ); @@ -279,6 +285,10 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, const unsigned char *p; size_t use_len, olen = 0; + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( iv != NULL ); + GCM_VALIDATE_RET( add_len == 0 || add != NULL ); + /* IV and AD are limited to 2^64 bits, so 2^61 bytes */ /* IV is not allowed to be zero length */ if( iv_len == 0 || @@ -361,6 +371,10 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx, unsigned char *out_p = output; size_t use_len, olen = 0; + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( length == 0 || input != NULL ); + GCM_VALIDATE_RET( length == 0 || output != NULL ); + if( output > input && (size_t) ( output - input ) < length ) return( MBEDTLS_ERR_GCM_BAD_INPUT ); @@ -414,8 +428,14 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, { unsigned char work_buf[16]; size_t i; - uint64_t orig_len = ctx->len * 8; - uint64_t orig_add_len = ctx->add_len * 8; + uint64_t orig_len; + uint64_t orig_add_len; + + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( tag != NULL ); + + orig_len = ctx->len * 8; + orig_add_len = ctx->add_len * 8; if( tag_len > 16 || tag_len < 4 ) return( MBEDTLS_ERR_GCM_BAD_INPUT ); @@ -457,6 +477,13 @@ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, { int ret; + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( iv != NULL ); + GCM_VALIDATE_RET( add_len == 0 || add != NULL ); + GCM_VALIDATE_RET( length == 0 || input != NULL ); + GCM_VALIDATE_RET( length == 0 || output != NULL ); + GCM_VALIDATE_RET( tag != NULL ); + if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 ) return( ret ); @@ -485,6 +512,13 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, size_t i; int diff; + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( iv != NULL ); + GCM_VALIDATE_RET( add_len == 0 || add != NULL ); + GCM_VALIDATE_RET( tag != NULL ); + GCM_VALIDATE_RET( length == 0 || input != NULL ); + GCM_VALIDATE_RET( length == 0 || output != NULL ); + if( ( ret = mbedtls_gcm_crypt_and_tag( ctx, MBEDTLS_GCM_DECRYPT, length, iv, iv_len, add, add_len, input, output, tag_len, check_tag ) ) != 0 ) @@ -498,7 +532,7 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, if( diff != 0 ) { - mbedtls_zeroize( output, length ); + mbedtls_platform_zeroize( output, length ); return( MBEDTLS_ERR_GCM_AUTH_FAILED ); } @@ -507,8 +541,10 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, void mbedtls_gcm_free( mbedtls_gcm_context *ctx ) { + if( ctx == NULL ) + return; mbedtls_cipher_free( &ctx->cipher_ctx ); - mbedtls_zeroize( ctx, sizeof( mbedtls_gcm_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_gcm_context ) ); } #endif /* !MBEDTLS_GCM_ALT */ @@ -768,7 +804,7 @@ int mbedtls_gcm_self_test( int verbose ) * there is an alternative underlying implementation i.e. when * MBEDTLS_AES_ALT is defined. */ - if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && key_len == 192 ) + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && key_len == 192 ) { mbedtls_printf( "skipped\n" ); break; diff --git a/app/mbedtls/library/havege.c b/app/mbedtls/library/havege.c index 2b75ef7bd8..c139e1db03 100644 --- a/app/mbedtls/library/havege.c +++ b/app/mbedtls/library/havege.c @@ -36,13 +36,20 @@ #include "mbedtls/havege.h" #include "mbedtls/timing.h" +#include "mbedtls/platform_util.h" +#include #include -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +/* If int isn't capable of storing 2^32 distinct values, the code of this + * module may cause a processor trap or a miscalculation. If int is more + * than 32 bits, the code may not calculate the intended values. */ +#if INT_MIN + 1 != -0x7fffffff +#error "The HAVEGE module requires int to be exactly 32 bits, with INT_MIN = -2^31." +#endif +#if UINT_MAX != 0xffffffff +#error "The HAVEGE module requires unsigned to be exactly 32 bits." +#endif /* ------------------------------------------------------------------------ * On average, one iteration accesses two 8-word blocks in the havege WALK @@ -58,7 +65,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { * ------------------------------------------------------------------------ */ -#define SWAP(X,Y) { int *T = X; X = Y; Y = T; } +#define SWAP(X,Y) { unsigned *T = (X); (X) = (Y); (Y) = T; } #define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; #define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; @@ -81,7 +88,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { PTX = (PT1 >> 18) & 7; \ PT1 &= 0x1FFF; \ PT2 &= 0x1FFF; \ - CLK = (int) mbedtls_timing_hardclock(); \ + CLK = (unsigned) mbedtls_timing_hardclock(); \ \ i = 0; \ A = &WALK[PT1 ]; RES[i++] ^= *A; \ @@ -104,7 +111,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { \ IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \ *A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \ - *B = IN; CLK = (int) mbedtls_timing_hardclock(); \ + *B = IN; CLK = (unsigned) mbedtls_timing_hardclock(); \ *C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \ *D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \ \ @@ -155,19 +162,20 @@ static void mbedtls_zeroize( void *v, size_t n ) { PT1 ^= (PT2 ^ 0x10) & 0x10; \ \ for( n++, i = 0; i < 16; i++ ) \ - hs->pool[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i]; + POOL[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i]; /* * Entropy gathering function */ static void havege_fill( mbedtls_havege_state *hs ) { - int i, n = 0; - int U1, U2, *A, *B, *C, *D; - int PT1, PT2, *WALK, RES[16]; - int PTX, PTY, CLK, PTEST, IN; + unsigned i, n = 0; + unsigned U1, U2, *A, *B, *C, *D; + unsigned PT1, PT2, *WALK, *POOL, RES[16]; + unsigned PTX, PTY, CLK, PTEST, IN; - WALK = hs->WALK; + WALK = (unsigned *) hs->WALK; + POOL = (unsigned *) hs->pool; PT1 = hs->PT1; PT2 = hs->PT2; @@ -208,7 +216,7 @@ void mbedtls_havege_free( mbedtls_havege_state *hs ) if( hs == NULL ) return; - mbedtls_zeroize( hs, sizeof( mbedtls_havege_state ) ); + mbedtls_platform_zeroize( hs, sizeof( mbedtls_havege_state ) ); } /* diff --git a/app/mbedtls/library/hkdf.c b/app/mbedtls/library/hkdf.c new file mode 100644 index 0000000000..82d8a429f4 --- /dev/null +++ b/app/mbedtls/library/hkdf.c @@ -0,0 +1,192 @@ +/* + * HKDF implementation -- RFC 5869 + * + * Copyright (C) 2016-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HKDF_C) + +#include +#include "mbedtls/hkdf.h" +#include "mbedtls/platform_util.h" + +int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt, + size_t salt_len, const unsigned char *ikm, size_t ikm_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len ) +{ + int ret; + unsigned char prk[MBEDTLS_MD_MAX_SIZE]; + + ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk ); + + if( ret == 0 ) + { + ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ), + info, info_len, okm, okm_len ); + } + + mbedtls_platform_zeroize( prk, sizeof( prk ) ); + + return( ret ); +} + +int mbedtls_hkdf_extract( const mbedtls_md_info_t *md, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk ) +{ + unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' }; + + if( salt == NULL ) + { + size_t hash_len; + + if( salt_len != 0 ) + { + return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; + } + + hash_len = mbedtls_md_get_size( md ); + + if( hash_len == 0 ) + { + return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; + } + + salt = null_salt; + salt_len = hash_len; + } + + return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) ); +} + +int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk, + size_t prk_len, const unsigned char *info, + size_t info_len, unsigned char *okm, size_t okm_len ) +{ + size_t hash_len; + size_t where = 0; + size_t n; + size_t t_len = 0; + size_t i; + int ret = 0; + mbedtls_md_context_t ctx; + unsigned char t[MBEDTLS_MD_MAX_SIZE]; + + if( okm == NULL ) + { + return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); + } + + hash_len = mbedtls_md_get_size( md ); + + if( prk_len < hash_len || hash_len == 0 ) + { + return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); + } + + if( info == NULL ) + { + info = (const unsigned char *) ""; + info_len = 0; + } + + n = okm_len / hash_len; + + if( (okm_len % hash_len) != 0 ) + { + n++; + } + + /* + * Per RFC 5869 Section 2.3, okm_len must not exceed + * 255 times the hash length + */ + if( n > 255 ) + { + return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); + } + + mbedtls_md_init( &ctx ); + + if( (ret = mbedtls_md_setup( &ctx, md, 1) ) != 0 ) + { + goto exit; + } + + /* + * Compute T = T(1) | T(2) | T(3) | ... | T(N) + * Where T(N) is defined in RFC 5869 Section 2.3 + */ + for( i = 1; i <= n; i++ ) + { + size_t num_to_copy; + unsigned char c = i & 0xff; + + ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len ); + if( ret != 0 ) + { + goto exit; + } + + ret = mbedtls_md_hmac_update( &ctx, t, t_len ); + if( ret != 0 ) + { + goto exit; + } + + ret = mbedtls_md_hmac_update( &ctx, info, info_len ); + if( ret != 0 ) + { + goto exit; + } + + /* The constant concatenated to the end of each T(n) is a single octet. + * */ + ret = mbedtls_md_hmac_update( &ctx, &c, 1 ); + if( ret != 0 ) + { + goto exit; + } + + ret = mbedtls_md_hmac_finish( &ctx, t ); + if( ret != 0 ) + { + goto exit; + } + + num_to_copy = i != n ? hash_len : okm_len - where; + memcpy( okm + where, t, num_to_copy ); + where += hash_len; + t_len = hash_len; + } + +exit: + mbedtls_md_free( &ctx ); + mbedtls_platform_zeroize( t, sizeof( t ) ); + + return( ret ); +} + +#endif /* MBEDTLS_HKDF_C */ diff --git a/app/mbedtls/library/hmac_drbg.c b/app/mbedtls/library/hmac_drbg.c index 9801bc50d8..284c9b4e96 100644 --- a/app/mbedtls/library/hmac_drbg.c +++ b/app/mbedtls/library/hmac_drbg.c @@ -34,6 +34,7 @@ #if defined(MBEDTLS_HMAC_DRBG_C) #include "mbedtls/hmac_drbg.h" +#include "mbedtls/platform_util.h" #include @@ -50,11 +51,6 @@ #endif /* MBEDTLS_SELF_TEST */ #endif /* MBEDTLS_PLATFORM_C */ -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * HMAC_DRBG context initialization */ @@ -111,16 +107,18 @@ int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, } exit: - mbedtls_zeroize( K, sizeof( K ) ); + mbedtls_platform_zeroize( K, sizeof( K ) ); return( ret ); } +#if !defined(MBEDTLS_DEPRECATED_REMOVED) void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t add_len ) { (void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len ); } +#endif /* MBEDTLS_DEPRECATED_REMOVED */ /* * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) @@ -151,20 +149,32 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, } /* - * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman) + * Internal function used both for seeding and reseeding the DRBG. + * Comments starting with arabic numbers refer to section 10.1.2.4 + * of SP800-90A, while roman numbers refer to section 9.2. */ -int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, - const unsigned char *additional, size_t len ) +static int hmac_drbg_reseed_core( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len, + int use_nonce ) { unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; - size_t seedlen; + size_t seedlen = 0; int ret; - /* III. Check input length */ - if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || - ctx->entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ) { - return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + size_t total_entropy_len; + + if( use_nonce == 0 ) + total_entropy_len = ctx->entropy_len; + else + total_entropy_len = ctx->entropy_len * 3 / 2; + + /* III. Check input length */ + if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || + total_entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ) + { + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + } } memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); @@ -172,9 +182,32 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, /* IV. Gather entropy_len bytes of entropy for the seed */ if( ( ret = ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) ) != 0 ) + { return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); + } + seedlen += ctx->entropy_len; + + /* For initial seeding, allow adding of nonce generated + * from the entropy source. See Sect 8.6.7 in SP800-90A. */ + if( use_nonce ) + { + /* Note: We don't merge the two calls to f_entropy() in order + * to avoid requesting too much entropy from f_entropy() + * at once. Specifically, if the underlying digest is not + * SHA-1, 3 / 2 * entropy_len is at least 36 Bytes, which + * is larger than the maximum of 32 Bytes that our own + * entropy source implementation can emit in a single + * call in configurations disabling SHA-512. */ + if( ( ret = ctx->f_entropy( ctx->p_entropy, + seed + seedlen, + ctx->entropy_len / 2 ) ) != 0 ) + { + return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen += ctx->entropy_len / 2; + } - seedlen = ctx->entropy_len; /* 1. Concatenate entropy and additional data if any */ if( additional != NULL && len != 0 ) @@ -192,12 +225,24 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, exit: /* 4. Done */ - mbedtls_zeroize( seed, seedlen ); + mbedtls_platform_zeroize( seed, seedlen ); return( ret ); } +/* + * HMAC_DRBG reseeding: 10.1.2.4 + 9.2 + */ +int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + return( hmac_drbg_reseed_core( ctx, additional, len, 0 ) ); +} + /* * HMAC_DRBG initialisation (10.1.2.3 + 9.1) + * + * The nonce is not passed as a separate parameter but extracted + * from the entropy source as suggested in 8.6.7. */ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, const mbedtls_md_info_t * md_info, @@ -207,7 +252,7 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, size_t len ) { int ret; - size_t entropy_len, md_size; + size_t md_size; if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) return( ret ); @@ -228,27 +273,25 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL; - /* - * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by - * each hash function, then according to SP800-90A rev1 10.1 table 2, - * min_entropy_len (in bits) is security_strength. - * - * (This also matches the sizes used in the NIST test vectors.) - */ - entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ - md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ - 32; /* better (256+) -> 256 bits */ - - /* - * For initialisation, use more entropy to emulate a nonce - * (Again, matches test vectors.) - */ - ctx->entropy_len = entropy_len * 3 / 2; + if( ctx->entropy_len == 0 ) + { + /* + * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by + * each hash function, then according to SP800-90A rev1 10.1 table 2, + * min_entropy_len (in bits) is security_strength. + * + * (This also matches the sizes used in the NIST test vectors.) + */ + ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ + md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ + 32; /* better (256+) -> 256 bits */ + } - if( ( ret = mbedtls_hmac_drbg_reseed( ctx, custom, len ) ) != 0 ) + if( ( ret = hmac_drbg_reseed_core( ctx, custom, len, + 1 /* add nonce */ ) ) != 0 ) + { return( ret ); - - ctx->entropy_len = entropy_len; + } return( 0 ); } @@ -263,7 +306,7 @@ void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx } /* - * Set entropy length grabbed for reseeds + * Set entropy length grabbed for seeding */ void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len ) { @@ -385,7 +428,7 @@ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ) mbedtls_mutex_free( &ctx->mutex ); #endif mbedtls_md_free( &ctx->md_ctx ); - mbedtls_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) ); } #if defined(MBEDTLS_FS_IO) @@ -411,7 +454,7 @@ int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const cha exit: fclose( f ); - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); return( ret ); } @@ -419,35 +462,36 @@ int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const cha int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) { int ret = 0; - FILE *f; + FILE *f = NULL; size_t n; unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + unsigned char c; if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); - fseek( f, 0, SEEK_END ); - n = (size_t) ftell( f ); - fseek( f, 0, SEEK_SET ); - - if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) { - fclose( f ); - return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; + goto exit; } - - if( fread( buf, 1, n, f ) != n ) + if( n == 0 || ferror( f ) ) + { ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; - else - ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); - + goto exit; + } fclose( f ); + f = NULL; - mbedtls_zeroize( buf, sizeof( buf ) ); + ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + if( f != NULL ) + fclose( f ); if( ret != 0 ) return( ret ); - return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); } #endif /* MBEDTLS_FS_IO */ diff --git a/app/mbedtls/library/md.c b/app/mbedtls/library/md.c index 00249af78b..303cdcbeeb 100644 --- a/app/mbedtls/library/md.c +++ b/app/mbedtls/library/md.c @@ -33,6 +33,7 @@ #include "mbedtls/md.h" #include "mbedtls/md_internal.h" +#include "mbedtls/platform_util.h" #if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" @@ -48,11 +49,6 @@ #include #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * Reminder: update profiles in x509_crt.c when adding a new hash! */ @@ -193,11 +189,12 @@ void mbedtls_md_free( mbedtls_md_context_t *ctx ) if( ctx->hmac_ctx != NULL ) { - mbedtls_zeroize( ctx->hmac_ctx, 2 * ctx->md_info->block_size ); + mbedtls_platform_zeroize( ctx->hmac_ctx, + 2 * ctx->md_info->block_size ); mbedtls_free( ctx->hmac_ctx ); } - mbedtls_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); } int mbedtls_md_clone( mbedtls_md_context_t *dst, @@ -311,7 +308,7 @@ int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigne ret = md_info->finish_func( ctx.md_ctx, output ); cleanup: - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); fclose( f ); mbedtls_md_free( &ctx ); @@ -361,7 +358,7 @@ int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, goto cleanup; cleanup: - mbedtls_zeroize( sum, sizeof( sum ) ); + mbedtls_platform_zeroize( sum, sizeof( sum ) ); return( ret ); } diff --git a/app/mbedtls/library/md2.c b/app/mbedtls/library/md2.c index b88aa406af..1c0b3df52d 100644 --- a/app/mbedtls/library/md2.c +++ b/app/mbedtls/library/md2.c @@ -34,6 +34,7 @@ #if defined(MBEDTLS_MD2_C) #include "mbedtls/md2.h" +#include "mbedtls/platform_util.h" #include @@ -48,11 +49,6 @@ #if !defined(MBEDTLS_MD2_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - static const unsigned char PI_SUBST[256] = { 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, @@ -93,7 +89,7 @@ void mbedtls_md2_free( mbedtls_md2_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_md2_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md2_context ) ); } void mbedtls_md2_clone( mbedtls_md2_context *dst, diff --git a/app/mbedtls/library/md4.c b/app/mbedtls/library/md4.c index ba704f58e8..828fd42999 100644 --- a/app/mbedtls/library/md4.c +++ b/app/mbedtls/library/md4.c @@ -34,6 +34,7 @@ #if defined(MBEDTLS_MD4_C) #include "mbedtls/md4.h" +#include "mbedtls/platform_util.h" #include @@ -48,11 +49,6 @@ #if !defined(MBEDTLS_MD4_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * 32-bit integer manipulation macros (little endian) */ @@ -86,7 +82,7 @@ void mbedtls_md4_free( mbedtls_md4_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_md4_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md4_context ) ); } void mbedtls_md4_clone( mbedtls_md4_context *dst, @@ -141,15 +137,21 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, GET_UINT32_LE( X[14], data, 56 ); GET_UINT32_LE( X[15], data, 60 ); -#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) +#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n)))) A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; -#define F(x, y, z) ((x & y) | ((~x) & z)) -#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } +#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z))) +#define P(a,b,c,d,x,s) \ + do \ + { \ + (a) += F((b),(c),(d)) + (x); \ + (a) = S((a),(s)); \ + } while( 0 ) + P( A, B, C, D, X[ 0], 3 ); P( D, A, B, C, X[ 1], 7 ); @@ -171,8 +173,13 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, #undef P #undef F -#define F(x,y,z) ((x & y) | (x & z) | (y & z)) -#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } +#define F(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define P(a,b,c,d,x,s) \ + do \ + { \ + (a) += F((b),(c),(d)) + (x) + 0x5A827999; \ + (a) = S((a),(s)); \ + } while( 0 ) P( A, B, C, D, X[ 0], 3 ); P( D, A, B, C, X[ 4], 5 ); @@ -194,8 +201,13 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, #undef P #undef F -#define F(x,y,z) (x ^ y ^ z) -#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } +#define F(x,y,z) ((x) ^ (y) ^ (z)) +#define P(a,b,c,d,x,s) \ + do \ + { \ + (a) += F((b),(c),(d)) + (x) + 0x6ED9EBA1; \ + (a) = S((a),(s)); \ + } while( 0 ) P( A, B, C, D, X[ 0], 3 ); P( D, A, B, C, X[ 8], 9 ); diff --git a/app/mbedtls/library/md5.c b/app/mbedtls/library/md5.c index 3ba88cfc5d..a93da8a061 100644 --- a/app/mbedtls/library/md5.c +++ b/app/mbedtls/library/md5.c @@ -33,6 +33,7 @@ #if defined(MBEDTLS_MD5_C) #include "mbedtls/md5.h" +#include "mbedtls/platform_util.h" #include @@ -47,11 +48,6 @@ #if !defined(MBEDTLS_MD5_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * 32-bit integer manipulation macros (little endian) */ @@ -85,7 +81,7 @@ void mbedtls_md5_free( mbedtls_md5_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_md5_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md5_context ) ); } void mbedtls_md5_clone( mbedtls_md5_context *dst, @@ -140,19 +136,22 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, GET_UINT32_LE( X[14], data, 56 ); GET_UINT32_LE( X[15], data, 60 ); -#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) +#define S(x,n) \ + ( ( (x) << (n) ) | ( ( (x) & 0xFFFFFFFF) >> ( 32 - (n) ) ) ) -#define P(a,b,c,d,k,s,t) \ -{ \ - a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ -} +#define P(a,b,c,d,k,s,t) \ + do \ + { \ + (a) += F((b),(c),(d)) + X[(k)] + (t); \ + (a) = S((a),(s)) + (b); \ + } while( 0 ) A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; -#define F(x,y,z) (z ^ (x & (y ^ z))) +#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) P( A, B, C, D, 0, 7, 0xD76AA478 ); P( D, A, B, C, 1, 12, 0xE8C7B756 ); @@ -173,7 +172,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, #undef F -#define F(x,y,z) (y ^ (z & (x ^ y))) +#define F(x,y,z) ((y) ^ ((z) & ((x) ^ (y)))) P( A, B, C, D, 1, 5, 0xF61E2562 ); P( D, A, B, C, 6, 9, 0xC040B340 ); @@ -194,7 +193,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, #undef F -#define F(x,y,z) (x ^ y ^ z) +#define F(x,y,z) ((x) ^ (y) ^ (z)) P( A, B, C, D, 5, 4, 0xFFFA3942 ); P( D, A, B, C, 8, 11, 0x8771F681 ); @@ -215,7 +214,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, #undef F -#define F(x,y,z) (y ^ (x | ~z)) +#define F(x,y,z) ((y) ^ ((x) | ~(z))) P( A, B, C, D, 0, 6, 0xF4292244 ); P( D, A, B, C, 7, 10, 0x432AFF97 ); diff --git a/app/mbedtls/library/memory_buffer_alloc.c b/app/mbedtls/library/memory_buffer_alloc.c index eb555f3326..51ea7c41d7 100644 --- a/app/mbedtls/library/memory_buffer_alloc.c +++ b/app/mbedtls/library/memory_buffer_alloc.c @@ -31,6 +31,7 @@ /* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C is dependent upon MBEDTLS_PLATFORM_C */ #include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" #include @@ -42,11 +43,6 @@ #include "mbedtls/threading.h" #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - #define MAGIC1 0xFF00AA55 #define MAGIC2 0xEE119966 #define MAX_BT 20 @@ -113,7 +109,7 @@ static void debug_header( memory_header *hdr ) #endif } -static void debug_chain() +static void debug_chain( void ) { memory_header *cur = heap.first; @@ -180,7 +176,7 @@ static int verify_header( memory_header *hdr ) return( 0 ); } -static int verify_chain() +static int verify_chain( void ) { memory_header *prv = heap.first, *cur; @@ -504,13 +500,13 @@ void mbedtls_memory_buffer_set_verify( int verify ) heap.verify = verify; } -int mbedtls_memory_buffer_alloc_verify() +int mbedtls_memory_buffer_alloc_verify( void ) { return verify_chain(); } #if defined(MBEDTLS_MEMORY_DEBUG) -void mbedtls_memory_buffer_alloc_status() +void mbedtls_memory_buffer_alloc_status( void ) { mbedtls_fprintf( stderr, "Current use: %zu blocks / %zu bytes, max: %zu blocks / " @@ -609,12 +605,12 @@ void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ) heap.first_free = heap.first; } -void mbedtls_memory_buffer_alloc_free() +void mbedtls_memory_buffer_alloc_free( void ) { #if defined(MBEDTLS_THREADING_C) mbedtls_mutex_free( &heap.mutex ); #endif - mbedtls_zeroize( &heap, sizeof(buffer_alloc_ctx) ); + mbedtls_platform_zeroize( &heap, sizeof(buffer_alloc_ctx) ); } #if defined(MBEDTLS_SELF_TEST) @@ -629,7 +625,7 @@ static int check_pointer( void *p ) return( 0 ); } -static int check_all_free( ) +static int check_all_free( void ) { if( #if defined(MBEDTLS_MEMORY_DEBUG) diff --git a/app/mbedtls/library/nist_kw.c b/app/mbedtls/library/nist_kw.c new file mode 100644 index 0000000000..317a2426ae --- /dev/null +++ b/app/mbedtls/library/nist_kw.c @@ -0,0 +1,755 @@ +/* + * Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes + * only + * + * Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +/* + * Definition of Key Wrapping: + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm" + * RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm" + * + * Note: RFC 3394 defines different methodology for intermediate operations for + * the wrapping and unwrapping operation than the definition in NIST SP 800-38F. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_NIST_KW_C) + +#include "mbedtls/nist_kw.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#if !defined(MBEDTLS_NIST_KW_ALT) + +#define KW_SEMIBLOCK_LENGTH 8 +#define MIN_SEMIBLOCKS_COUNT 3 + +/* constant-time buffer comparison */ +static inline unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + volatile const unsigned char *A = (volatile const unsigned char *) a; + volatile const unsigned char *B = (volatile const unsigned char *) b; + volatile unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + { + /* Read volatile data in order before computing diff. + * This avoids IAR compiler warning: + * 'the order of volatile accesses is undefined ..' */ + unsigned char x = A[i], y = B[i]; + diff |= x ^ y; + } + + return( diff ); +} + +/*! The 64-bit default integrity check value (ICV) for KW mode. */ +static const unsigned char NIST_KW_ICV1[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; +/*! The 32-bit default integrity check value (ICV) for KWP mode. */ +static const unsigned char NIST_KW_ICV2[] = {0xA6, 0x59, 0x59, 0xA6}; + +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +/* + * Initialize context + */ +void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_nist_kw_context ) ); +} + +int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits, + const int is_wrap ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values( cipher, + keybits, + MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* + * SP 800-38F currently defines AES cipher as the only block cipher allowed: + * "For KW and KWP, the underlying block cipher shall be approved, and the + * block size shall be 128 bits. Currently, the AES block cipher, with key + * lengths of 128, 192, or 256 bits, is the only block cipher that fits + * this profile." + * Currently we don't support other 128 bit block ciphers for key wrapping, + * such as Camellia and Aria. + */ + if( cipher != MBEDTLS_CIPHER_ID_AES ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + is_wrap ? MBEDTLS_ENCRYPT : + MBEDTLS_DECRYPT ) + ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Free context + */ +void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_nist_kw_context ) ); +} + +/* + * Helper function for Xoring the uint64_t "t" with the encrypted A. + * Defined in NIST SP 800-38F section 6.1 + */ +static void calc_a_xor_t( unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t ) +{ + size_t i = 0; + for( i = 0; i < sizeof( t ); i++ ) + { + A[i] ^= ( t >> ( ( sizeof( t ) - 1 - i ) * 8 ) ) & 0xff; + } +} + +/* + * KW-AE as defined in SP 800-38F section 6.2 + * KWP-AE as defined in SP 800-38F section 6.3 + */ +int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size ) +{ + int ret = 0; + size_t semiblocks = 0; + size_t s; + size_t olen, padlen = 0; + uint64_t t = 0; + unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH; + unsigned char *A = output; + + *out_len = 0; + /* + * Generate the String to work on + */ + if( mode == MBEDTLS_KW_MODE_KW ) + { + if( out_size < in_len + KW_SEMIBLOCK_LENGTH ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + /* + * According to SP 800-38F Table 1, the plaintext length for KW + * must be between 2 to 2^54-1 semiblocks inclusive. + */ + if( in_len < 16 || +#if SIZE_MAX > 0x1FFFFFFFFFFFFF8 + in_len > 0x1FFFFFFFFFFFFF8 || +#endif + in_len % KW_SEMIBLOCK_LENGTH != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH ); + memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len ); + } + else + { + if( in_len % 8 != 0 ) + { + padlen = ( 8 - ( in_len % 8 ) ); + } + + if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + /* + * According to SP 800-38F Table 1, the plaintext length for KWP + * must be between 1 and 2^32-1 octets inclusive. + */ + if( in_len < 1 +#if SIZE_MAX > 0xFFFFFFFF + || in_len > 0xFFFFFFFF +#endif + ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 ); + PUT_UINT32_BE( ( in_len & 0xffffffff ), output, + KW_SEMIBLOCK_LENGTH / 2 ); + + memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len ); + memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen ); + } + semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1; + + s = 6 * ( semiblocks - 1 ); + + if( mode == MBEDTLS_KW_MODE_KWP + && in_len <= KW_SEMIBLOCK_LENGTH ) + { + memcpy( inbuff, output, 16 ); + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + inbuff, 16, output, &olen ); + if( ret != 0 ) + goto cleanup; + } + else + { + /* + * Do the wrapping function W, as defined in RFC 3394 section 2.2.1 + */ + if( semiblocks < MIN_SEMIBLOCKS_COUNT ) + { + ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + goto cleanup; + } + + /* Calculate intermediate values */ + for( t = 1; t <= s; t++ ) + { + memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH ); + memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH ); + + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + inbuff, 16, outbuff, &olen ); + if( ret != 0 ) + goto cleanup; + + memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); + calc_a_xor_t( A, t ); + + memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); + R2 += KW_SEMIBLOCK_LENGTH; + if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) ) + R2 = output + KW_SEMIBLOCK_LENGTH; + } + } + + *out_len = semiblocks * KW_SEMIBLOCK_LENGTH; + +cleanup: + + if( ret != 0) + { + memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH ); + } + mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 ); + mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 ); + + return( ret ); +} + +/* + * W-1 function as defined in RFC 3394 section 2.2.2 + * This function assumes the following: + * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH. + * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH. + * 3. Minimal number of semiblocks is 3. + * 4. A is a buffer to hold the first semiblock of the input buffer. + */ +static int unwrap( mbedtls_nist_kw_context *ctx, + const unsigned char *input, size_t semiblocks, + unsigned char A[KW_SEMIBLOCK_LENGTH], + unsigned char *output, size_t* out_len ) +{ + int ret = 0; + const size_t s = 6 * ( semiblocks - 1 ); + size_t olen; + uint64_t t = 0; + unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char *R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH; + *out_len = 0; + + if( semiblocks < MIN_SEMIBLOCKS_COUNT ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( A, input, KW_SEMIBLOCK_LENGTH ); + memmove( output, input + KW_SEMIBLOCK_LENGTH, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH ); + + /* Calculate intermediate values */ + for( t = s; t >= 1; t-- ) + { + calc_a_xor_t( A, t ); + + memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH ); + memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH ); + + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + inbuff, 16, outbuff, &olen ); + if( ret != 0 ) + goto cleanup; + + memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); + + /* Set R as LSB64 of outbuff */ + memcpy( R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); + + if( R == output ) + R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH; + else + R -= KW_SEMIBLOCK_LENGTH; + } + + *out_len = ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH; + +cleanup: + if( ret != 0) + memset( output, 0, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH ); + mbedtls_platform_zeroize( inbuff, sizeof( inbuff ) ); + mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) ); + + return( ret ); +} + +/* + * KW-AD as defined in SP 800-38F section 6.2 + * KWP-AD as defined in SP 800-38F section 6.3 + */ +int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size ) +{ + int ret = 0; + size_t i, olen; + unsigned char A[KW_SEMIBLOCK_LENGTH]; + unsigned char diff, bad_padding = 0; + + *out_len = 0; + if( out_size < in_len - KW_SEMIBLOCK_LENGTH ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + if( mode == MBEDTLS_KW_MODE_KW ) + { + /* + * According to SP 800-38F Table 1, the ciphertext length for KW + * must be between 3 to 2^54 semiblocks inclusive. + */ + if( in_len < 24 || +#if SIZE_MAX > 0x200000000000000 + in_len > 0x200000000000000 || +#endif + in_len % KW_SEMIBLOCK_LENGTH != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH, + A, output, out_len ); + if( ret != 0 ) + goto cleanup; + + /* Check ICV in "constant-time" */ + diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH ); + + if( diff != 0 ) + { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + goto cleanup; + } + + } + else if( mode == MBEDTLS_KW_MODE_KWP ) + { + size_t padlen = 0; + uint32_t Plen; + /* + * According to SP 800-38F Table 1, the ciphertext length for KWP + * must be between 2 to 2^29 semiblocks inclusive. + */ + if( in_len < KW_SEMIBLOCK_LENGTH * 2 || +#if SIZE_MAX > 0x100000000 + in_len > 0x100000000 || +#endif + in_len % KW_SEMIBLOCK_LENGTH != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + if( in_len == KW_SEMIBLOCK_LENGTH * 2 ) + { + unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + input, 16, outbuff, &olen ); + if( ret != 0 ) + goto cleanup; + + memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); + memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); + mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) ); + *out_len = KW_SEMIBLOCK_LENGTH; + } + else + { + /* in_len >= KW_SEMIBLOCK_LENGTH * 3 */ + ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH, + A, output, out_len ); + if( ret != 0 ) + goto cleanup; + } + + /* Check ICV in "constant-time" */ + diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 ); + + if( diff != 0 ) + { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 ); + + /* + * Plen is the length of the plaintext, when the input is valid. + * If Plen is larger than the plaintext and padding, padlen will be + * larger than 8, because of the type wrap around. + */ + padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen; + if ( padlen > 7 ) + { + padlen &= 7; + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + /* Check padding in "constant-time" */ + for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ ) + { + if( i >= KW_SEMIBLOCK_LENGTH - padlen ) + diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; + else + bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; + } + + if( diff != 0 ) + { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + if( ret != 0 ) + { + goto cleanup; + } + memset( output + Plen, 0, padlen ); + *out_len = Plen; + } + else + { + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto cleanup; + } + +cleanup: + if( ret != 0 ) + { + memset( output, 0, *out_len ); + *out_len = 0; + } + + mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) ); + mbedtls_platform_zeroize( &diff, sizeof( diff ) ); + mbedtls_platform_zeroize( A, sizeof( A ) ); + + return( ret ); +} + +#endif /* !MBEDTLS_NIST_KW_ALT */ + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) + +#define KW_TESTS 3 + +/* + * Test vectors taken from NIST + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW + */ +static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 }; + +static const unsigned char kw_key[KW_TESTS][32] = { + { 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2, + 0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 }, + { 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b, + 0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d, + 0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 }, + { 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25, + 0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33, + 0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d, + 0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 } +}; + +static const unsigned char kw_msg[KW_TESTS][40] = { + { 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea, + 0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f }, + { 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb, + 0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d, + 0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45, + 0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d, + 0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c }, + { 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7, + 0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8, + 0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 } +}; + +static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 }; +static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 }; +static const unsigned char kw_res[KW_TESTS][48] = { + { 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d, + 0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3, + 0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb }, + { 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91, + 0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec, + 0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d, + 0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8, + 0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19, + 0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d }, + { 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d, + 0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87, + 0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9, + 0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 } +}; + +static const unsigned char kwp_key[KW_TESTS][32] = { + { 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a, + 0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 }, + { 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98, + 0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7, + 0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 }, + { 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5, + 0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f, + 0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae, + 0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a } +}; + +static const unsigned char kwp_msg[KW_TESTS][31] = { + { 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8, + 0x96 }, + { 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb, + 0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19, + 0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66, + 0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f }, + { 0xd1 } +}; +static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 }; + +static const unsigned char kwp_res[KW_TESTS][48] = { + { 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e, + 0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7, + 0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 }, + { 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13, + 0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88, + 0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63, + 0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90, + 0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 }, + { 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd, + 0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4 } +}; +static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 }; + +int mbedtls_nist_kw_self_test( int verbose ) +{ + mbedtls_nist_kw_context ctx; + unsigned char out[48]; + size_t olen; + int i; + int ret = 0; + mbedtls_nist_kw_init( &ctx ); + + for( i = 0; i < KW_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " KW-AES-%u ", (unsigned int) key_len[i] * 8 ); + + ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, + kw_key[i], key_len[i] * 8, 1 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KW: setup failed " ); + + goto end; + } + + ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KW, kw_msg[i], + kw_msg_len[i], out, &olen, sizeof( out ) ); + if( ret != 0 || kw_out_len[i] != olen || + memcmp( out, kw_res[i], kw_out_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed. "); + + ret = 1; + goto end; + } + + if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, + kw_key[i], key_len[i] * 8, 0 ) ) + != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KW: setup failed "); + + goto end; + } + + ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KW, + out, olen, out, &olen, sizeof( out ) ); + + if( ret != 0 || olen != kw_msg_len[i] || + memcmp( out, kw_msg[i], kw_msg_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto end; + } + + if( verbose != 0 ) + mbedtls_printf( " passed\n" ); + } + + for( i = 0; i < KW_TESTS; i++ ) + { + olen = sizeof( out ); + if( verbose != 0 ) + mbedtls_printf( " KWP-AES-%u ", (unsigned int) key_len[i] * 8 ); + + ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i], + key_len[i] * 8, 1 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KWP: setup failed " ); + + goto end; + } + ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i], + kwp_msg_len[i], out, &olen, sizeof( out ) ); + + if( ret != 0 || kwp_out_len[i] != olen || + memcmp( out, kwp_res[i], kwp_out_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed. "); + + ret = 1; + goto end; + } + + if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, + kwp_key[i], key_len[i] * 8, 0 ) ) + != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KWP: setup failed "); + + goto end; + } + + ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KWP, out, + olen, out, &olen, sizeof( out ) ); + + if( ret != 0 || olen != kwp_msg_len[i] || + memcmp( out, kwp_msg[i], kwp_msg_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed. "); + + ret = 1; + goto end; + } + + if( verbose != 0 ) + mbedtls_printf( " passed\n" ); + } +end: + mbedtls_nist_kw_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_NIST_KW_C */ diff --git a/app/mbedtls/library/oid.c b/app/mbedtls/library/oid.c index edea950f8f..33f437cbe6 100644 --- a/app/mbedtls/library/oid.c +++ b/app/mbedtls/library/oid.c @@ -54,22 +54,24 @@ * Macro to generate an internal function for oid_XXX_from_asn1() (used by * the other functions) */ -#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \ -static const TYPE_T * oid_ ## NAME ## _from_asn1( const mbedtls_asn1_buf *oid ) \ -{ \ - const TYPE_T *p = LIST; \ - const mbedtls_oid_descriptor_t *cur = (const mbedtls_oid_descriptor_t *) p; \ - if( p == NULL || oid == NULL ) return( NULL ); \ - while( cur->asn1 != NULL ) { \ - if( cur->asn1_len == oid->len && \ - memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \ - return( p ); \ - } \ - p++; \ - cur = (const mbedtls_oid_descriptor_t *) p; \ - } \ - return( NULL ); \ -} +#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \ + static const TYPE_T * oid_ ## NAME ## _from_asn1( \ + const mbedtls_asn1_buf *oid ) \ + { \ + const TYPE_T *p = (LIST); \ + const mbedtls_oid_descriptor_t *cur = \ + (const mbedtls_oid_descriptor_t *) p; \ + if( p == NULL || oid == NULL ) return( NULL ); \ + while( cur->asn1 != NULL ) { \ + if( cur->asn1_len == oid->len && \ + memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \ + return( p ); \ + } \ + p++; \ + cur = (const mbedtls_oid_descriptor_t *) p; \ + } \ + return( NULL ); \ + } /* * Macro to generate a function for retrieving a single attribute from the @@ -103,12 +105,13 @@ int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) */ #define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \ ATTR2_TYPE, ATTR2) \ -int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, \ + ATTR2_TYPE * ATTR2 ) \ { \ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ - if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ - *ATTR1 = data->ATTR1; \ - *ATTR2 = data->ATTR2; \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *(ATTR1) = data->ATTR1; \ + *(ATTR2) = data->ATTR2; \ return( 0 ); \ } @@ -119,16 +122,16 @@ int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 #define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \ int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ { \ - const TYPE_T *cur = LIST; \ + const TYPE_T *cur = (LIST); \ while( cur->descriptor.asn1 != NULL ) { \ - if( cur->ATTR1 == ATTR1 ) { \ + if( cur->ATTR1 == (ATTR1) ) { \ *oid = cur->descriptor.asn1; \ *olen = cur->descriptor.asn1_len; \ return( 0 ); \ } \ cur++; \ } \ - return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ } /* @@ -140,9 +143,9 @@ int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \ size_t *olen ) \ { \ - const TYPE_T *cur = LIST; \ + const TYPE_T *cur = (LIST); \ while( cur->descriptor.asn1 != NULL ) { \ - if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \ + if( cur->ATTR1 == (ATTR1) && cur->ATTR2 == (ATTR2) ) { \ *oid = cur->descriptor.asn1; \ *olen = cur->descriptor.asn1_len; \ return( 0 ); \ diff --git a/app/mbedtls/library/pem.c b/app/mbedtls/library/pem.c index ac86d7e479..897c8a0d6f 100644 --- a/app/mbedtls/library/pem.c +++ b/app/mbedtls/library/pem.c @@ -33,6 +33,7 @@ #include "mbedtls/aes.h" #include "mbedtls/md5.h" #include "mbedtls/cipher.h" +#include "mbedtls/platform_util.h" #include @@ -45,11 +46,6 @@ #endif #if defined(MBEDTLS_PEM_PARSE_C) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - void mbedtls_pem_init( mbedtls_pem_context *ctx ) { memset( ctx, 0, sizeof( mbedtls_pem_context ) ); @@ -135,7 +131,7 @@ static int pem_pbkdf1( unsigned char *key, size_t keylen, exit: mbedtls_md5_free( &md5_ctx ); - mbedtls_zeroize( md5sum, 16 ); + mbedtls_platform_zeroize( md5sum, 16 ); return( ret ); } @@ -164,7 +160,7 @@ static int pem_des_decrypt( unsigned char des_iv[8], exit: mbedtls_des_free( &des_ctx ); - mbedtls_zeroize( des_key, 8 ); + mbedtls_platform_zeroize( des_key, 8 ); return( ret ); } @@ -192,7 +188,7 @@ static int pem_des3_decrypt( unsigned char des3_iv[8], exit: mbedtls_des3_free( &des3_ctx ); - mbedtls_zeroize( des3_key, 24 ); + mbedtls_platform_zeroize( des3_key, 24 ); return( ret ); } @@ -222,7 +218,7 @@ static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, exit: mbedtls_aes_free( &aes_ctx ); - mbedtls_zeroize( aes_key, keylen ); + mbedtls_platform_zeroize( aes_key, keylen ); return( ret ); } @@ -359,7 +355,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) { - mbedtls_zeroize( buf, len ); + mbedtls_platform_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); } @@ -370,7 +366,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) if( pwd == NULL ) { - mbedtls_zeroize( buf, len ); + mbedtls_platform_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); } @@ -403,16 +399,16 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 * length bytes (allow 4 to be sure) in all known use cases. * - * Use that as heurisitic to try detecting password mismatchs. + * Use that as a heuristic to try to detect password mismatches. */ if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) { - mbedtls_zeroize( buf, len ); + mbedtls_platform_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); } #else - mbedtls_zeroize( buf, len ); + mbedtls_platform_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && @@ -427,12 +423,14 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const void mbedtls_pem_free( mbedtls_pem_context *ctx ) { - if( ctx->buf != NULL ) - mbedtls_zeroize( ctx->buf, ctx->buflen ); - mbedtls_free( ctx->buf ); + if ( ctx->buf != NULL ) + { + mbedtls_platform_zeroize( ctx->buf, ctx->buflen ); + mbedtls_free( ctx->buf ); + } mbedtls_free( ctx->info ); - mbedtls_zeroize( ctx, sizeof( mbedtls_pem_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pem_context ) ); } #endif /* MBEDTLS_PEM_PARSE_C */ diff --git a/app/mbedtls/library/pk.c b/app/mbedtls/library/pk.c index b52c73fbc6..bac685dc19 100644 --- a/app/mbedtls/library/pk.c +++ b/app/mbedtls/library/pk.c @@ -29,6 +29,8 @@ #include "mbedtls/pk.h" #include "mbedtls/pk_internal.h" +#include "mbedtls/platform_util.h" + #if defined(MBEDTLS_RSA_C) #include "mbedtls/rsa.h" #endif @@ -42,18 +44,18 @@ #include #include -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +/* Parameter validation macros based on platform_util.h */ +#define PK_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) +#define PK_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) /* * Initialise a mbedtls_pk_context */ void mbedtls_pk_init( mbedtls_pk_context *ctx ) { - if( ctx == NULL ) - return; + PK_VALIDATE( ctx != NULL ); ctx->pk_info = NULL; ctx->pk_ctx = NULL; @@ -64,13 +66,43 @@ void mbedtls_pk_init( mbedtls_pk_context *ctx ) */ void mbedtls_pk_free( mbedtls_pk_context *ctx ) { - if( ctx == NULL || ctx->pk_info == NULL ) + if( ctx == NULL ) + return; + + if ( ctx->pk_info != NULL ) + ctx->pk_info->ctx_free_func( ctx->pk_ctx ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pk_context ) ); +} + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Initialize a restart context + */ +void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx ) +{ + PK_VALIDATE( ctx != NULL ); + ctx->pk_info = NULL; + ctx->rs_ctx = NULL; +} + +/* + * Free the components of a restart context + */ +void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + ctx->pk_info->rs_free_func == NULL ) + { return; + } - ctx->pk_info->ctx_free_func( ctx->pk_ctx ); + ctx->pk_info->rs_free_func( ctx->rs_ctx ); - mbedtls_zeroize( ctx, sizeof( mbedtls_pk_context ) ); + ctx->pk_info = NULL; + ctx->rs_ctx = NULL; } +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ /* * Get pk_info structure from type @@ -103,7 +135,8 @@ const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ) */ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ) { - if( ctx == NULL || info == NULL || ctx->pk_info != NULL ) + PK_VALIDATE_RET( ctx != NULL ); + if( info == NULL || ctx->pk_info != NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) @@ -126,7 +159,8 @@ int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, mbedtls_rsa_alt_context *rsa_alt; const mbedtls_pk_info_t *info = &mbedtls_rsa_alt_info; - if( ctx == NULL || ctx->pk_info != NULL ) + PK_VALIDATE_RET( ctx != NULL ); + if( ctx->pk_info != NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) @@ -150,7 +184,9 @@ int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, */ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ) { - /* null or NONE context can't do anything */ + /* A context with null pk_info is not set up yet and can't do anything. + * For backward compatibility, also accept NULL instead of a context + * pointer. */ if( ctx == NULL || ctx->pk_info == NULL ) return( 0 ); @@ -174,17 +210,71 @@ static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len return( 0 ); } +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) /* - * Verify a signature + * Helper to set up a restart context if needed */ -int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, +static int pk_restart_setup( mbedtls_pk_restart_ctx *ctx, + const mbedtls_pk_info_t *info ) +{ + /* Don't do anything if already set up or invalid */ + if( ctx == NULL || ctx->pk_info != NULL ) + return( 0 ); + + /* Should never happen when we're called */ + if( info->rs_alloc_func == NULL || info->rs_free_func == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->rs_ctx = info->rs_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + return( 0 ); +} +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +/* + * Verify a signature (restartable) + */ +int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, - const unsigned char *sig, size_t sig_len ) + const unsigned char *sig, size_t sig_len, + mbedtls_pk_restart_ctx *rs_ctx ) { - if( ctx == NULL || ctx->pk_info == NULL || + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) || + hash != NULL ); + PK_VALIDATE_RET( sig != NULL ); + + if( ctx->pk_info == NULL || pk_hashlen_helper( md_alg, &hash_len ) != 0 ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* optimization: use non-restartable version if restart disabled */ + if( rs_ctx != NULL && + mbedtls_ecp_restart_is_enabled() && + ctx->pk_info->verify_rs_func != NULL ) + { + int ret; + + if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 ) + return( ret ); + + ret = ctx->pk_info->verify_rs_func( ctx->pk_ctx, + md_alg, hash, hash_len, sig, sig_len, rs_ctx->rs_ctx ); + + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) + mbedtls_pk_restart_free( rs_ctx ); + + return( ret ); + } +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + (void) rs_ctx; +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + if( ctx->pk_info->verify_func == NULL ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); @@ -192,6 +282,17 @@ int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, sig, sig_len ) ); } +/* + * Verify a signature + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + return( mbedtls_pk_verify_restartable( ctx, md_alg, hash, hash_len, + sig, sig_len, NULL ) ); +} + /* * Verify a signature with options */ @@ -200,7 +301,12 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len ) { - if( ctx == NULL || ctx->pk_info == NULL ) + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) || + hash != NULL ); + PK_VALIDATE_RET( sig != NULL ); + + if( ctx->pk_info == NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); if( ! mbedtls_pk_can_do( ctx, type ) ) @@ -251,17 +357,47 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, } /* - * Make a signature + * Make a signature (restartable) */ -int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, +int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t *sig_len, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_pk_restart_ctx *rs_ctx ) { - if( ctx == NULL || ctx->pk_info == NULL || + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) || + hash != NULL ); + PK_VALIDATE_RET( sig != NULL ); + + if( ctx->pk_info == NULL || pk_hashlen_helper( md_alg, &hash_len ) != 0 ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* optimization: use non-restartable version if restart disabled */ + if( rs_ctx != NULL && + mbedtls_ecp_restart_is_enabled() && + ctx->pk_info->sign_rs_func != NULL ) + { + int ret; + + if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 ) + return( ret ); + + ret = ctx->pk_info->sign_rs_func( ctx->pk_ctx, md_alg, + hash, hash_len, sig, sig_len, f_rng, p_rng, rs_ctx->rs_ctx ); + + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) + mbedtls_pk_restart_free( rs_ctx ); + + return( ret ); + } +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + (void) rs_ctx; +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + if( ctx->pk_info->sign_func == NULL ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); @@ -269,6 +405,18 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, sig, sig_len, f_rng, p_rng ) ); } +/* + * Make a signature + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_pk_sign_restartable( ctx, md_alg, hash, hash_len, + sig, sig_len, f_rng, p_rng, NULL ) ); +} + /* * Decrypt message */ @@ -277,7 +425,12 @@ int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, unsigned char *output, size_t *olen, size_t osize, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - if( ctx == NULL || ctx->pk_info == NULL ) + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( input != NULL || ilen == 0 ); + PK_VALIDATE_RET( output != NULL || osize == 0 ); + PK_VALIDATE_RET( olen != NULL ); + + if( ctx->pk_info == NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); if( ctx->pk_info->decrypt_func == NULL ) @@ -295,7 +448,12 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, unsigned char *output, size_t *olen, size_t osize, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - if( ctx == NULL || ctx->pk_info == NULL ) + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( input != NULL || ilen == 0 ); + PK_VALIDATE_RET( output != NULL || osize == 0 ); + PK_VALIDATE_RET( olen != NULL ); + + if( ctx->pk_info == NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); if( ctx->pk_info->encrypt_func == NULL ) @@ -310,8 +468,11 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, */ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ) { - if( pub == NULL || pub->pk_info == NULL || - prv == NULL || prv->pk_info == NULL || + PK_VALIDATE_RET( pub != NULL ); + PK_VALIDATE_RET( prv != NULL ); + + if( pub->pk_info == NULL || + prv->pk_info == NULL || prv->pk_info->check_pair_func == NULL ) { return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); @@ -336,6 +497,8 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte */ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) { + /* For backward compatibility, accept NULL or a context that + * isn't set up yet, and return a fake value that should be safe. */ if( ctx == NULL || ctx->pk_info == NULL ) return( 0 ); @@ -347,7 +510,8 @@ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) */ int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ) { - if( ctx == NULL || ctx->pk_info == NULL ) + PK_VALIDATE_RET( ctx != NULL ); + if( ctx->pk_info == NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); if( ctx->pk_info->debug_func == NULL ) diff --git a/app/mbedtls/library/pk_wrap.c b/app/mbedtls/library/pk_wrap.c index 5446e23507..87806be337 100644 --- a/app/mbedtls/library/pk_wrap.c +++ b/app/mbedtls/library/pk_wrap.c @@ -41,6 +41,10 @@ #include "mbedtls/ecdsa.h" #endif +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +#include "mbedtls/platform_util.h" +#endif + #if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" #else @@ -52,13 +56,6 @@ #include #include -#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} -#endif - #if defined(MBEDTLS_RSA_C) static int rsa_can_do( mbedtls_pk_type_t type ) { @@ -193,11 +190,19 @@ const mbedtls_pk_info_t mbedtls_rsa_info = { rsa_can_do, rsa_verify_wrap, rsa_sign_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif rsa_decrypt_wrap, rsa_encrypt_wrap, rsa_check_pair_wrap, rsa_alloc_wrap, rsa_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif rsa_debug, }; #endif /* MBEDTLS_RSA_C */ @@ -265,6 +270,110 @@ static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, return( ret ); } +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* Forward declarations */ +static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ); + +static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + void *rs_ctx ); + +/* + * Restart context for ECDSA operations with ECKEY context + * + * We need to store an actual ECDSA context, as we need to pass the same to + * the underlying ecdsa function, so we can't create it on the fly every time. + */ +typedef struct +{ + mbedtls_ecdsa_restart_ctx ecdsa_rs; + mbedtls_ecdsa_context ecdsa_ctx; +} eckey_restart_ctx; + +static void *eckey_rs_alloc( void ) +{ + eckey_restart_ctx *rs_ctx; + + void *ctx = mbedtls_calloc( 1, sizeof( eckey_restart_ctx ) ); + + if( ctx != NULL ) + { + rs_ctx = ctx; + mbedtls_ecdsa_restart_init( &rs_ctx->ecdsa_rs ); + mbedtls_ecdsa_init( &rs_ctx->ecdsa_ctx ); + } + + return( ctx ); +} + +static void eckey_rs_free( void *ctx ) +{ + eckey_restart_ctx *rs_ctx; + + if( ctx == NULL) + return; + + rs_ctx = ctx; + mbedtls_ecdsa_restart_free( &rs_ctx->ecdsa_rs ); + mbedtls_ecdsa_free( &rs_ctx->ecdsa_ctx ); + + mbedtls_free( ctx ); +} + +static int eckey_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ) +{ + int ret; + eckey_restart_ctx *rs = rs_ctx; + + /* Should never happen */ + if( rs == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* set up our own sub-context if needed (that is, on first run) */ + if( rs->ecdsa_ctx.grp.pbits == 0 ) + MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) ); + + MBEDTLS_MPI_CHK( ecdsa_verify_rs_wrap( &rs->ecdsa_ctx, + md_alg, hash, hash_len, + sig, sig_len, &rs->ecdsa_rs ) ); + +cleanup: + return( ret ); +} + +static int eckey_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + void *rs_ctx ) +{ + int ret; + eckey_restart_ctx *rs = rs_ctx; + + /* Should never happen */ + if( rs == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* set up our own sub-context if needed (that is, on first run) */ + if( rs->ecdsa_ctx.grp.pbits == 0 ) + MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) ); + + MBEDTLS_MPI_CHK( ecdsa_sign_rs_wrap( &rs->ecdsa_ctx, md_alg, + hash, hash_len, sig, sig_len, + f_rng, p_rng, &rs->ecdsa_rs ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ #endif /* MBEDTLS_ECDSA_C */ static int eckey_check_pair( const void *pub, const void *prv ) @@ -304,15 +413,23 @@ const mbedtls_pk_info_t mbedtls_eckey_info = { #if defined(MBEDTLS_ECDSA_C) eckey_verify_wrap, eckey_sign_wrap, -#else +#if defined(MBEDTLS_ECP_RESTARTABLE) + eckey_verify_rs_wrap, + eckey_sign_rs_wrap, +#endif +#else /* MBEDTLS_ECDSA_C */ NULL, NULL, -#endif +#endif /* MBEDTLS_ECDSA_C */ NULL, NULL, eckey_check_pair, eckey_alloc_wrap, eckey_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + eckey_rs_alloc, + eckey_rs_free, +#endif eckey_debug, }; @@ -332,11 +449,19 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = { eckeydh_can_do, NULL, NULL, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif NULL, NULL, eckey_check_pair, eckey_alloc_wrap, /* Same underlying key structure */ eckey_free_wrap, /* Same underlying key structure */ +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif eckey_debug, /* Same underlying key structure */ }; #endif /* MBEDTLS_ECP_C */ @@ -372,6 +497,40 @@ static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) ); } +#if defined(MBEDTLS_ECP_RESTARTABLE) +static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ) +{ + int ret; + ((void) md_alg); + + ret = mbedtls_ecdsa_read_signature_restartable( + (mbedtls_ecdsa_context *) ctx, + hash, hash_len, sig, sig_len, + (mbedtls_ecdsa_restart_ctx *) rs_ctx ); + + if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( ret ); +} + +static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + void *rs_ctx ) +{ + return( mbedtls_ecdsa_write_signature_restartable( + (mbedtls_ecdsa_context *) ctx, + md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng, + (mbedtls_ecdsa_restart_ctx *) rs_ctx ) ); + +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ + static void *ecdsa_alloc_wrap( void ) { void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_context ) ); @@ -388,6 +547,24 @@ static void ecdsa_free_wrap( void *ctx ) mbedtls_free( ctx ); } +#if defined(MBEDTLS_ECP_RESTARTABLE) +static void *ecdsa_rs_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_restart_ctx ) ); + + if( ctx != NULL ) + mbedtls_ecdsa_restart_init( ctx ); + + return( ctx ); +} + +static void ecdsa_rs_free( void *ctx ) +{ + mbedtls_ecdsa_restart_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ + const mbedtls_pk_info_t mbedtls_ecdsa_info = { MBEDTLS_PK_ECDSA, "ECDSA", @@ -395,11 +572,19 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = { ecdsa_can_do, ecdsa_verify_wrap, ecdsa_sign_wrap, +#if defined(MBEDTLS_ECP_RESTARTABLE) + ecdsa_verify_rs_wrap, + ecdsa_sign_rs_wrap, +#endif NULL, NULL, eckey_check_pair, /* Compatible key structures */ ecdsa_alloc_wrap, ecdsa_free_wrap, +#if defined(MBEDTLS_ECP_RESTARTABLE) + ecdsa_rs_alloc, + ecdsa_rs_free, +#endif eckey_debug, /* Compatible key structures */ }; #endif /* MBEDTLS_ECDSA_C */ @@ -498,7 +683,7 @@ static void *rsa_alt_alloc_wrap( void ) static void rsa_alt_free_wrap( void *ctx ) { - mbedtls_zeroize( ctx, sizeof( mbedtls_rsa_alt_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_rsa_alt_context ) ); mbedtls_free( ctx ); } @@ -509,6 +694,10 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = { rsa_alt_can_do, NULL, rsa_alt_sign_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif rsa_alt_decrypt_wrap, NULL, #if defined(MBEDTLS_RSA_C) @@ -518,6 +707,10 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = { #endif rsa_alt_alloc_wrap, rsa_alt_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif NULL, }; diff --git a/app/mbedtls/library/pkcs12.c b/app/mbedtls/library/pkcs12.c index 5e8b2879a0..7edf064c13 100644 --- a/app/mbedtls/library/pkcs12.c +++ b/app/mbedtls/library/pkcs12.c @@ -36,6 +36,7 @@ #include "mbedtls/pkcs12.h" #include "mbedtls/asn1.h" #include "mbedtls/cipher.h" +#include "mbedtls/platform_util.h" #include @@ -47,11 +48,6 @@ #include "mbedtls/des.h" #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - #if defined(MBEDTLS_ASN1_PARSE_C) static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params, @@ -168,7 +164,7 @@ int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, goto exit; exit: - mbedtls_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( key, sizeof( key ) ); mbedtls_arc4_free( &ctx ); return( ret ); @@ -225,8 +221,8 @@ int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH; exit: - mbedtls_zeroize( key, sizeof( key ) ); - mbedtls_zeroize( iv, sizeof( iv ) ); + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( iv, sizeof( iv ) ); mbedtls_cipher_free( &cipher_ctx ); return( ret ); @@ -356,10 +352,10 @@ int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, ret = 0; exit: - mbedtls_zeroize( salt_block, sizeof( salt_block ) ); - mbedtls_zeroize( pwd_block, sizeof( pwd_block ) ); - mbedtls_zeroize( hash_block, sizeof( hash_block ) ); - mbedtls_zeroize( hash_output, sizeof( hash_output ) ); + mbedtls_platform_zeroize( salt_block, sizeof( salt_block ) ); + mbedtls_platform_zeroize( pwd_block, sizeof( pwd_block ) ); + mbedtls_platform_zeroize( hash_block, sizeof( hash_block ) ); + mbedtls_platform_zeroize( hash_output, sizeof( hash_output ) ); mbedtls_md_free( &md_ctx ); diff --git a/app/mbedtls/library/pkparse.c b/app/mbedtls/library/pkparse.c index ec9b55f8c5..ae210bca6a 100644 --- a/app/mbedtls/library/pkparse.c +++ b/app/mbedtls/library/pkparse.c @@ -30,6 +30,7 @@ #include "mbedtls/pk.h" #include "mbedtls/asn1.h" #include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" #include @@ -60,13 +61,11 @@ #define mbedtls_free free #endif -#if defined(MBEDTLS_FS_IO) || \ - defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} -#endif +/* Parameter validation macros based on platform_util.h */ +#define PK_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) +#define PK_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) #if defined(MBEDTLS_FS_IO) /* @@ -81,6 +80,10 @@ int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) FILE *f; long size; + PK_VALIDATE_RET( path != NULL ); + PK_VALIDATE_RET( buf != NULL ); + PK_VALIDATE_RET( n != NULL ); + if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); @@ -105,7 +108,7 @@ int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) { fclose( f ); - mbedtls_zeroize( *buf, *n ); + mbedtls_platform_zeroize( *buf, *n ); mbedtls_free( *buf ); return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); @@ -131,6 +134,9 @@ int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, size_t n; unsigned char *buf; + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( path != NULL ); + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) return( ret ); @@ -140,7 +146,7 @@ int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, ret = mbedtls_pk_parse_key( ctx, buf, n, (const unsigned char *) pwd, strlen( pwd ) ); - mbedtls_zeroize( buf, n ); + mbedtls_platform_zeroize( buf, n ); mbedtls_free( buf ); return( ret ); @@ -155,12 +161,15 @@ int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) size_t n; unsigned char *buf; + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( path != NULL ); + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) return( ret ); ret = mbedtls_pk_parse_public_key( ctx, buf, n ); - mbedtls_zeroize( buf, n ); + mbedtls_platform_zeroize( buf, n ); mbedtls_free( buf ); return( ret ); @@ -612,6 +621,11 @@ int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; const mbedtls_pk_info_t *pk_info; + PK_VALIDATE_RET( p != NULL ); + PK_VALIDATE_RET( *p != NULL ); + PK_VALIDATE_RET( end != NULL ); + PK_VALIDATE_RET( pk != NULL ); + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { @@ -1152,16 +1166,22 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk, { int ret; const mbedtls_pk_info_t *pk_info; - #if defined(MBEDTLS_PEM_PARSE_C) size_t len; mbedtls_pem_context pem; +#endif - mbedtls_pem_init( &pem ); + PK_VALIDATE_RET( pk != NULL ); + if( keylen == 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + PK_VALIDATE_RET( key != NULL ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_init( &pem ); #if defined(MBEDTLS_RSA_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if( keylen == 0 || key[keylen - 1] != '\0' ) + if( key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, @@ -1192,7 +1212,7 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk, #if defined(MBEDTLS_ECP_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if( keylen == 0 || key[keylen - 1] != '\0' ) + if( key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, @@ -1222,7 +1242,7 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk, #endif /* MBEDTLS_ECP_C */ /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if( keylen == 0 || key[keylen - 1] != '\0' ) + if( key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, @@ -1245,7 +1265,7 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk, #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if( keylen == 0 || key[keylen - 1] != '\0' ) + if( key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, @@ -1283,9 +1303,6 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk, { unsigned char *key_copy; - if( keylen == 0 ) - return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); - if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL ) return( MBEDTLS_ERR_PK_ALLOC_FAILED ); @@ -1294,7 +1311,7 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk, ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen, pwd, pwdlen ); - mbedtls_zeroize( key_copy, keylen ); + mbedtls_platform_zeroize( key_copy, keylen ); mbedtls_free( key_copy ); } @@ -1361,14 +1378,55 @@ int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, { int ret; unsigned char *p; +#if defined(MBEDTLS_RSA_C) + const mbedtls_pk_info_t *pk_info; +#endif #if defined(MBEDTLS_PEM_PARSE_C) size_t len; mbedtls_pem_context pem; +#endif + + PK_VALIDATE_RET( ctx != NULL ); + if( keylen == 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + PK_VALIDATE_RET( key != NULL || keylen == 0 ); +#if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_init( &pem ); +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN RSA PUBLIC KEY-----", + "-----END RSA PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + p = pem.buf; + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) + return( ret ); + + if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 ) + mbedtls_pk_free( ctx ); + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } +#endif /* MBEDTLS_RSA_C */ /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if( keylen == 0 || key[keylen - 1] != '\0' ) + if( key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, @@ -1381,23 +1439,43 @@ int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, /* * Was PEM encoded */ - key = pem.buf; - keylen = pem.buflen; + p = pem.buf; + + ret = mbedtls_pk_parse_subpubkey( &p, p + pem.buflen, ctx ); + mbedtls_pem_free( &pem ); + return( ret ); } else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { mbedtls_pem_free( &pem ); return( ret ); } + mbedtls_pem_free( &pem ); #endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_RSA_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) + return( ret ); + + p = (unsigned char *)key; + ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) ); + if( ret == 0 ) + { + return( ret ); + } + mbedtls_pk_free( ctx ); + if( ret != ( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + { + return( ret ); + } +#endif /* MBEDTLS_RSA_C */ p = (unsigned char *) key; ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); -#if defined(MBEDTLS_PEM_PARSE_C) - mbedtls_pem_free( &pem ); -#endif - return( ret ); } diff --git a/app/mbedtls/library/pkwrite.c b/app/mbedtls/library/pkwrite.c index 8eabd889b5..03d14f2ff9 100644 --- a/app/mbedtls/library/pkwrite.c +++ b/app/mbedtls/library/pkwrite.c @@ -30,6 +30,7 @@ #include "mbedtls/pk.h" #include "mbedtls/asn1write.h" #include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" #include @@ -37,7 +38,9 @@ #include "mbedtls/rsa.h" #endif #if defined(MBEDTLS_ECP_C) +#include "mbedtls/bignum.h" #include "mbedtls/ecp.h" +#include "mbedtls/platform_util.h" #endif #if defined(MBEDTLS_ECDSA_C) #include "mbedtls/ecdsa.h" @@ -54,6 +57,12 @@ #define mbedtls_free free #endif +/* Parameter validation macros based on platform_util.h */ +#define PK_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) +#define PK_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + #if defined(MBEDTLS_RSA_C) /* * RSAPublicKey ::= SEQUENCE { @@ -143,6 +152,26 @@ static int pk_write_ec_param( unsigned char **p, unsigned char *start, return( (int) len ); } + +/* + * privateKey OCTET STRING -- always of length ceil(log2(n)/8) + */ +static int pk_write_ec_private( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t byte_length = ( ec->grp.pbits + 7 ) / 8; + unsigned char tmp[MBEDTLS_ECP_MAX_BYTES]; + + ret = mbedtls_mpi_write_binary( &ec->d, tmp, byte_length ); + if( ret != 0 ) + goto exit; + ret = mbedtls_asn1_write_octet_string( p, start, tmp, byte_length ); + +exit: + mbedtls_platform_zeroize( tmp, byte_length ); + return( ret ); +} #endif /* MBEDTLS_ECP_C */ int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, @@ -151,6 +180,11 @@ int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, int ret; size_t len = 0; + PK_VALIDATE_RET( p != NULL ); + PK_VALIDATE_RET( *p != NULL ); + PK_VALIDATE_RET( start != NULL ); + PK_VALIDATE_RET( key != NULL ); + #if defined(MBEDTLS_RSA_C) if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) MBEDTLS_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedtls_pk_rsa( *key ) ) ); @@ -173,6 +207,11 @@ int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, si size_t len = 0, par_len = 0, oid_len; const char *oid; + PK_VALIDATE_RET( key != NULL ); + if( size == 0 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + PK_VALIDATE_RET( buf != NULL ); + c = buf + size; MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) ); @@ -217,9 +256,16 @@ int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, si int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) { int ret; - unsigned char *c = buf + size; + unsigned char *c; size_t len = 0; + PK_VALIDATE_RET( key != NULL ); + if( size == 0 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + PK_VALIDATE_RET( buf != NULL ); + + c = buf + size; + #if defined(MBEDTLS_RSA_C) if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) { @@ -340,9 +386,8 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_ MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); len += par_len; - /* privateKey: write as MPI then fix tag */ - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) ); - *c = MBEDTLS_ASN1_OCTET_STRING; + /* privateKey */ + MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_private( &c, buf, ec ) ); /* version */ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) ); @@ -457,6 +502,9 @@ int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, si unsigned char output_buf[PUB_DER_MAX_BYTES]; size_t olen = 0; + PK_VALIDATE_RET( key != NULL ); + PK_VALIDATE_RET( buf != NULL || size == 0 ); + if( ( ret = mbedtls_pk_write_pubkey_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) { @@ -480,6 +528,9 @@ int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_ const char *begin, *end; size_t olen = 0; + PK_VALIDATE_RET( key != NULL ); + PK_VALIDATE_RET( buf != NULL || size == 0 ); + if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) return( ret ); diff --git a/app/mbedtls/library/platform.c b/app/mbedtls/library/platform.c index aa88fc1a66..73a6db9ebe 100644 --- a/app/mbedtls/library/platform.c +++ b/app/mbedtls/library/platform.c @@ -28,14 +28,7 @@ #if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" - -#if defined(MBEDTLS_ENTROPY_NV_SEED) && \ - !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} -#endif +#include "mbedtls/platform_util.h" /* The compile time configuration of memory allocation via the macros * MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO takes precedence over the runtime @@ -65,14 +58,24 @@ static void platform_free_uninit( void *ptr ) #define MBEDTLS_PLATFORM_STD_FREE platform_free_uninit #endif /* !MBEDTLS_PLATFORM_STD_FREE */ -void * (*mbedtls_calloc)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC; -void (*mbedtls_free)( void * ) = MBEDTLS_PLATFORM_STD_FREE; +static void * (*mbedtls_calloc_func)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC; +static void (*mbedtls_free_func)( void * ) = MBEDTLS_PLATFORM_STD_FREE; + +void * mbedtls_calloc( size_t nmemb, size_t size ) +{ + return (*mbedtls_calloc_func)( nmemb, size ); +} + +void mbedtls_free( void * ptr ) +{ + (*mbedtls_free_func)( ptr ); +} int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), void (*free_func)( void * ) ) { - mbedtls_calloc = calloc_func; - mbedtls_free = free_func; + mbedtls_calloc_func = calloc_func; + mbedtls_free_func = free_func; return( 0 ); } #endif /* MBEDTLS_PLATFORM_MEMORY && @@ -250,7 +253,7 @@ int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ) if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len ) { fclose( file ); - mbedtls_zeroize( buf, buf_len ); + mbedtls_platform_zeroize( buf, buf_len ); return( -1 ); } diff --git a/app/mbedtls/library/platform_util.c b/app/mbedtls/library/platform_util.c new file mode 100644 index 0000000000..b1f745097c --- /dev/null +++ b/app/mbedtls/library/platform_util.c @@ -0,0 +1,139 @@ +/* + * Common and shared functions used by multiple modules in the Mbed TLS + * library. + * + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +/* + * Ensure gmtime_r is available even with -std=c99; must be defined before + * config.h, which pulls in glibc's features.h. Harmless on other platforms. + */ +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 200112L +#endif + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/platform_util.h" +#include "mbedtls/platform.h" +#include "mbedtls/threading.h" + +#include +#include + +#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT) +/* + * This implementation should never be optimized out by the compiler + * + * This implementation for mbedtls_platform_zeroize() was inspired from Colin + * Percival's blog article at: + * + * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + * + * It uses a volatile function pointer to the standard memset(). Because the + * pointer is volatile the compiler expects it to change at + * any time and will not optimize out the call that could potentially perform + * other operations on the input buffer instead of just setting it to 0. + * Nevertheless, as pointed out by davidtgoldblatt on Hacker News + * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for + * details), optimizations of the following form are still possible: + * + * if( memset_func != memset ) + * memset_func( buf, 0, len ); + * + * Note that it is extremely difficult to guarantee that + * mbedtls_platform_zeroize() will not be optimized out by aggressive compilers + * in a portable way. For this reason, Mbed TLS also provides the configuration + * option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for their + * platform and needs. + */ +static void * (* const volatile memset_func)( void *, int, size_t ) = memset; + +void mbedtls_platform_zeroize( void *buf, size_t len ) +{ + MBEDTLS_INTERNAL_VALIDATE( len == 0 || buf != NULL ); + + if( len > 0 ) + memset_func( buf, 0, len ); +} +#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */ + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) +#include +#if !defined(_WIN32) && (defined(unix) || \ + defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \ + defined(__MACH__))) +#include +#endif /* !_WIN32 && (unix || __unix || __unix__ || + * (__APPLE__ && __MACH__)) */ + +#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) +/* + * This is a convenience shorthand macro to avoid checking the long + * preprocessor conditions above. Ideally, we could expose this macro in + * platform_util.h and simply use it in platform_util.c, threading.c and + * threading.h. However, this macro is not part of the Mbed TLS public API, so + * we keep it private by only defining it in this file + */ +#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) +#define PLATFORM_UTIL_USE_GMTIME +#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */ + +#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */ + +struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt, + struct tm *tm_buf ) +{ +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL ); +#elif !defined(PLATFORM_UTIL_USE_GMTIME) + return( gmtime_r( tt, tm_buf ) ); +#else + struct tm *lt; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( NULL ); +#endif /* MBEDTLS_THREADING_C */ + + lt = gmtime( tt ); + + if( lt != NULL ) + { + memcpy( tm_buf, lt, sizeof( struct tm ) ); + } + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( NULL ); +#endif /* MBEDTLS_THREADING_C */ + + return( ( lt == NULL ) ? NULL : tm_buf ); +#endif /* _WIN32 && !EFIX64 && !EFI32 */ +} +#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */ diff --git a/app/mbedtls/library/poly1305.c b/app/mbedtls/library/poly1305.c new file mode 100644 index 0000000000..2b56c5f7ef --- /dev/null +++ b/app/mbedtls/library/poly1305.c @@ -0,0 +1,559 @@ +/** + * \file poly1305.c + * + * \brief Poly1305 authentication algorithm. + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_POLY1305_C) + +#include "mbedtls/poly1305.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_POLY1305_ALT) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define POLY1305_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA ) +#define POLY1305_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define POLY1305_BLOCK_SIZE_BYTES ( 16U ) + +#define BYTES_TO_U32_LE( data, offset ) \ + ( (uint32_t) (data)[offset] \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \ + ) + +/* + * Our implementation is tuned for 32-bit platforms with a 64-bit multiplier. + * However we provided an alternative for platforms without such a multiplier. + */ +#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION) +static uint64_t mul64( uint32_t a, uint32_t b ) +{ + /* a = al + 2**16 ah, b = bl + 2**16 bh */ + const uint16_t al = (uint16_t) a; + const uint16_t bl = (uint16_t) b; + const uint16_t ah = a >> 16; + const uint16_t bh = b >> 16; + + /* ab = al*bl + 2**16 (ah*bl + bl*bh) + 2**32 ah*bh */ + const uint32_t lo = (uint32_t) al * bl; + const uint64_t me = (uint64_t)( (uint32_t) ah * bl ) + (uint32_t) al * bh; + const uint32_t hi = (uint32_t) ah * bh; + + return( lo + ( me << 16 ) + ( (uint64_t) hi << 32 ) ); +} +#else +static inline uint64_t mul64( uint32_t a, uint32_t b ) +{ + return( (uint64_t) a * b ); +} +#endif + + +/** + * \brief Process blocks with Poly1305. + * + * \param ctx The Poly1305 context. + * \param nblocks Number of blocks to process. Note that this + * function only processes full blocks. + * \param input Buffer containing the input block(s). + * \param needs_padding Set to 0 if the padding bit has already been + * applied to the input data before calling this + * function. Otherwise, set this parameter to 1. + */ +static void poly1305_process( mbedtls_poly1305_context *ctx, + size_t nblocks, + const unsigned char *input, + uint32_t needs_padding ) +{ + uint64_t d0, d1, d2, d3; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t r0, r1, r2, r3; + uint32_t rs1, rs2, rs3; + size_t offset = 0U; + size_t i; + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + r3 = ctx->r[3]; + + rs1 = r1 + ( r1 >> 2U ); + rs2 = r2 + ( r2 >> 2U ); + rs3 = r3 + ( r3 >> 2U ); + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Process full blocks */ + for( i = 0U; i < nblocks; i++ ) + { + /* The input block is treated as a 128-bit little-endian integer */ + d0 = BYTES_TO_U32_LE( input, offset + 0 ); + d1 = BYTES_TO_U32_LE( input, offset + 4 ); + d2 = BYTES_TO_U32_LE( input, offset + 8 ); + d3 = BYTES_TO_U32_LE( input, offset + 12 ); + + /* Compute: acc += (padded) block as a 130-bit integer */ + d0 += (uint64_t) acc0; + d1 += (uint64_t) acc1 + ( d0 >> 32U ); + d2 += (uint64_t) acc2 + ( d1 >> 32U ); + d3 += (uint64_t) acc3 + ( d2 >> 32U ); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 += (uint32_t) ( d3 >> 32U ) + needs_padding; + + /* Compute: acc *= r */ + d0 = mul64( acc0, r0 ) + + mul64( acc1, rs3 ) + + mul64( acc2, rs2 ) + + mul64( acc3, rs1 ); + d1 = mul64( acc0, r1 ) + + mul64( acc1, r0 ) + + mul64( acc2, rs3 ) + + mul64( acc3, rs2 ) + + mul64( acc4, rs1 ); + d2 = mul64( acc0, r2 ) + + mul64( acc1, r1 ) + + mul64( acc2, r0 ) + + mul64( acc3, rs3 ) + + mul64( acc4, rs2 ); + d3 = mul64( acc0, r3 ) + + mul64( acc1, r2 ) + + mul64( acc2, r1 ) + + mul64( acc3, r0 ) + + mul64( acc4, rs3 ); + acc4 *= r0; + + /* Compute: acc %= (2^130 - 5) (partial remainder) */ + d1 += ( d0 >> 32 ); + d2 += ( d1 >> 32 ); + d3 += ( d2 >> 32 ); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 = (uint32_t) ( d3 >> 32 ) + acc4; + + d0 = (uint64_t) acc0 + ( acc4 >> 2 ) + ( acc4 & 0xFFFFFFFCU ); + acc4 &= 3U; + acc0 = (uint32_t) d0; + d0 = (uint64_t) acc1 + ( d0 >> 32U ); + acc1 = (uint32_t) d0; + d0 = (uint64_t) acc2 + ( d0 >> 32U ); + acc2 = (uint32_t) d0; + d0 = (uint64_t) acc3 + ( d0 >> 32U ); + acc3 = (uint32_t) d0; + d0 = (uint64_t) acc4 + ( d0 >> 32U ); + acc4 = (uint32_t) d0; + + offset += POLY1305_BLOCK_SIZE_BYTES; + } + + ctx->acc[0] = acc0; + ctx->acc[1] = acc1; + ctx->acc[2] = acc2; + ctx->acc[3] = acc3; + ctx->acc[4] = acc4; +} + +/** + * \brief Compute the Poly1305 MAC + * + * \param ctx The Poly1305 context. + * \param mac The buffer to where the MAC is written. Must be + * big enough to contain the 16-byte MAC. + */ +static void poly1305_compute_mac( const mbedtls_poly1305_context *ctx, + unsigned char mac[16] ) +{ + uint64_t d; + uint32_t g0, g1, g2, g3, g4; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t mask; + uint32_t mask_inv; + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Before adding 's' we ensure that the accumulator is mod 2^130 - 5. + * We do this by calculating acc - (2^130 - 5), then checking if + * the 131st bit is set. If it is, then reduce: acc -= (2^130 - 5) + */ + + /* Calculate acc + -(2^130 - 5) */ + d = ( (uint64_t) acc0 + 5U ); + g0 = (uint32_t) d; + d = ( (uint64_t) acc1 + ( d >> 32 ) ); + g1 = (uint32_t) d; + d = ( (uint64_t) acc2 + ( d >> 32 ) ); + g2 = (uint32_t) d; + d = ( (uint64_t) acc3 + ( d >> 32 ) ); + g3 = (uint32_t) d; + g4 = acc4 + (uint32_t) ( d >> 32U ); + + /* mask == 0xFFFFFFFF if 131st bit is set, otherwise mask == 0 */ + mask = (uint32_t) 0U - ( g4 >> 2U ); + mask_inv = ~mask; + + /* If 131st bit is set then acc=g, otherwise, acc is unmodified */ + acc0 = ( acc0 & mask_inv ) | ( g0 & mask ); + acc1 = ( acc1 & mask_inv ) | ( g1 & mask ); + acc2 = ( acc2 & mask_inv ) | ( g2 & mask ); + acc3 = ( acc3 & mask_inv ) | ( g3 & mask ); + + /* Add 's' */ + d = (uint64_t) acc0 + ctx->s[0]; + acc0 = (uint32_t) d; + d = (uint64_t) acc1 + ctx->s[1] + ( d >> 32U ); + acc1 = (uint32_t) d; + d = (uint64_t) acc2 + ctx->s[2] + ( d >> 32U ); + acc2 = (uint32_t) d; + acc3 += ctx->s[3] + (uint32_t) ( d >> 32U ); + + /* Compute MAC (128 least significant bits of the accumulator) */ + mac[ 0] = (unsigned char)( acc0 ); + mac[ 1] = (unsigned char)( acc0 >> 8 ); + mac[ 2] = (unsigned char)( acc0 >> 16 ); + mac[ 3] = (unsigned char)( acc0 >> 24 ); + mac[ 4] = (unsigned char)( acc1 ); + mac[ 5] = (unsigned char)( acc1 >> 8 ); + mac[ 6] = (unsigned char)( acc1 >> 16 ); + mac[ 7] = (unsigned char)( acc1 >> 24 ); + mac[ 8] = (unsigned char)( acc2 ); + mac[ 9] = (unsigned char)( acc2 >> 8 ); + mac[10] = (unsigned char)( acc2 >> 16 ); + mac[11] = (unsigned char)( acc2 >> 24 ); + mac[12] = (unsigned char)( acc3 ); + mac[13] = (unsigned char)( acc3 >> 8 ); + mac[14] = (unsigned char)( acc3 >> 16 ); + mac[15] = (unsigned char)( acc3 >> 24 ); +} + +void mbedtls_poly1305_init( mbedtls_poly1305_context *ctx ) +{ + POLY1305_VALIDATE( ctx != NULL ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) ); +} + +void mbedtls_poly1305_free( mbedtls_poly1305_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) ); +} + +int mbedtls_poly1305_starts( mbedtls_poly1305_context *ctx, + const unsigned char key[32] ) +{ + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( key != NULL ); + + /* r &= 0x0ffffffc0ffffffc0ffffffc0fffffff */ + ctx->r[0] = BYTES_TO_U32_LE( key, 0 ) & 0x0FFFFFFFU; + ctx->r[1] = BYTES_TO_U32_LE( key, 4 ) & 0x0FFFFFFCU; + ctx->r[2] = BYTES_TO_U32_LE( key, 8 ) & 0x0FFFFFFCU; + ctx->r[3] = BYTES_TO_U32_LE( key, 12 ) & 0x0FFFFFFCU; + + ctx->s[0] = BYTES_TO_U32_LE( key, 16 ); + ctx->s[1] = BYTES_TO_U32_LE( key, 20 ); + ctx->s[2] = BYTES_TO_U32_LE( key, 24 ); + ctx->s[3] = BYTES_TO_U32_LE( key, 28 ); + + /* Initial accumulator state */ + ctx->acc[0] = 0U; + ctx->acc[1] = 0U; + ctx->acc[2] = 0U; + ctx->acc[3] = 0U; + ctx->acc[4] = 0U; + + /* Queue initially empty */ + mbedtls_platform_zeroize( ctx->queue, sizeof( ctx->queue ) ); + ctx->queue_len = 0U; + + return( 0 ); +} + +int mbedtls_poly1305_update( mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + size_t offset = 0U; + size_t remaining = ilen; + size_t queue_free_len; + size_t nblocks; + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( ( remaining > 0U ) && ( ctx->queue_len > 0U ) ) + { + queue_free_len = ( POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len ); + + if( ilen < queue_free_len ) + { + /* Not enough data to complete the block. + * Store this data with the other leftovers. + */ + memcpy( &ctx->queue[ctx->queue_len], + input, + ilen ); + + ctx->queue_len += ilen; + + remaining = 0U; + } + else + { + /* Enough data to produce a complete block */ + memcpy( &ctx->queue[ctx->queue_len], + input, + queue_free_len ); + + ctx->queue_len = 0U; + + poly1305_process( ctx, 1U, ctx->queue, 1U ); /* add padding bit */ + + offset += queue_free_len; + remaining -= queue_free_len; + } + } + + if( remaining >= POLY1305_BLOCK_SIZE_BYTES ) + { + nblocks = remaining / POLY1305_BLOCK_SIZE_BYTES; + + poly1305_process( ctx, nblocks, &input[offset], 1U ); + + offset += nblocks * POLY1305_BLOCK_SIZE_BYTES; + remaining %= POLY1305_BLOCK_SIZE_BYTES; + } + + if( remaining > 0U ) + { + /* Store partial block */ + ctx->queue_len = remaining; + memcpy( ctx->queue, &input[offset], remaining ); + } + + return( 0 ); +} + +int mbedtls_poly1305_finish( mbedtls_poly1305_context *ctx, + unsigned char mac[16] ) +{ + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( mac != NULL ); + + /* Process any leftover data */ + if( ctx->queue_len > 0U ) + { + /* Add padding bit */ + ctx->queue[ctx->queue_len] = 1U; + ctx->queue_len++; + + /* Pad with zeroes */ + memset( &ctx->queue[ctx->queue_len], + 0, + POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len ); + + poly1305_process( ctx, 1U, /* Process 1 block */ + ctx->queue, 0U ); /* Already padded above */ + } + + poly1305_compute_mac( ctx, mac ); + + return( 0 ); +} + +int mbedtls_poly1305_mac( const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16] ) +{ + mbedtls_poly1305_context ctx; + int ret; + POLY1305_VALIDATE_RET( key != NULL ); + POLY1305_VALIDATE_RET( mac != NULL ); + POLY1305_VALIDATE_RET( ilen == 0 || input != NULL ); + + mbedtls_poly1305_init( &ctx ); + + ret = mbedtls_poly1305_starts( &ctx, key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_update( &ctx, input, ilen ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_finish( &ctx, mac ); + +cleanup: + mbedtls_poly1305_free( &ctx ); + return( ret ); +} + +#endif /* MBEDTLS_POLY1305_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, + 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, + 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, + 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b + }, + { + 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, + 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, + 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, + 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 + } +}; + +static const unsigned char test_data[2][127] = +{ + { + 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x6f, + 0x72, 0x75, 0x6d, 0x20, 0x52, 0x65, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f, + 0x75, 0x70 + }, + { + 0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, + 0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f, + 0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20, + 0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c, + 0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, + 0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75, + 0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e + } +}; + +static const size_t test_data_len[2] = +{ + 34U, + 127U +}; + +static const unsigned char test_mac[2][16] = +{ + { + 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6, + 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9 + }, + { + 0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61, + 0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62 + } +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_poly1305_self_test( int verbose ) +{ + unsigned char mac[16]; + unsigned i; + int ret; + + for( i = 0U; i < 2U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " Poly1305 test %u ", i ); + + ret = mbedtls_poly1305_mac( test_keys[i], + test_data[i], + test_data_len[i], + mac ); + ASSERT( 0 == ret, ( "error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( mac, test_mac[i], 16U ), ( "failed (mac)\n" ) ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_POLY1305_C */ diff --git a/app/mbedtls/library/ripemd160.c b/app/mbedtls/library/ripemd160.c index 2ba48b7fdb..0791ae4cc9 100644 --- a/app/mbedtls/library/ripemd160.c +++ b/app/mbedtls/library/ripemd160.c @@ -34,6 +34,7 @@ #if defined(MBEDTLS_RIPEMD160_C) #include "mbedtls/ripemd160.h" +#include "mbedtls/platform_util.h" #include @@ -71,11 +72,6 @@ } #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ) { memset( ctx, 0, sizeof( mbedtls_ripemd160_context ) ); @@ -86,7 +82,7 @@ void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_ripemd160_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ripemd160_context ) ); } void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst, @@ -151,22 +147,29 @@ int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx, D = Dp = ctx->state[3]; E = Ep = ctx->state[4]; -#define F1( x, y, z ) ( x ^ y ^ z ) -#define F2( x, y, z ) ( ( x & y ) | ( ~x & z ) ) -#define F3( x, y, z ) ( ( x | ~y ) ^ z ) -#define F4( x, y, z ) ( ( x & z ) | ( y & ~z ) ) -#define F5( x, y, z ) ( x ^ ( y | ~z ) ) - -#define S( x, n ) ( ( x << n ) | ( x >> (32 - n) ) ) - -#define P( a, b, c, d, e, r, s, f, k ) \ - a += f( b, c, d ) + X[r] + k; \ - a = S( a, s ) + e; \ - c = S( c, 10 ); - -#define P2( a, b, c, d, e, r, s, rp, sp ) \ - P( a, b, c, d, e, r, s, F, K ); \ - P( a ## p, b ## p, c ## p, d ## p, e ## p, rp, sp, Fp, Kp ); +#define F1( x, y, z ) ( (x) ^ (y) ^ (z) ) +#define F2( x, y, z ) ( ( (x) & (y) ) | ( ~(x) & (z) ) ) +#define F3( x, y, z ) ( ( (x) | ~(y) ) ^ (z) ) +#define F4( x, y, z ) ( ( (x) & (z) ) | ( (y) & ~(z) ) ) +#define F5( x, y, z ) ( (x) ^ ( (y) | ~(z) ) ) + +#define S( x, n ) ( ( (x) << (n) ) | ( (x) >> (32 - (n)) ) ) + +#define P( a, b, c, d, e, r, s, f, k ) \ + do \ + { \ + (a) += f( (b), (c), (d) ) + X[r] + (k); \ + (a) = S( (a), (s) ) + (e); \ + (c) = S( (c), 10 ); \ + } while( 0 ) + +#define P2( a, b, c, d, e, r, s, rp, sp ) \ + do \ + { \ + P( (a), (b), (c), (d), (e), (r), (s), F, K ); \ + P( a ## p, b ## p, c ## p, d ## p, e ## p, \ + (rp), (sp), Fp, Kp ); \ + } while( 0 ) #define F F1 #define K 0x00000000 diff --git a/app/mbedtls/library/rsa.c b/app/mbedtls/library/rsa.c index 4b3cc0213d..af1a878599 100644 --- a/app/mbedtls/library/rsa.c +++ b/app/mbedtls/library/rsa.c @@ -48,6 +48,7 @@ #include "mbedtls/rsa.h" #include "mbedtls/rsa_internal.h" #include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" #include @@ -70,10 +71,11 @@ #if !defined(MBEDTLS_RSA_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} +/* Parameter validation macros */ +#define RSA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_RSA_BAD_INPUT_DATA ) +#define RSA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) #if defined(MBEDTLS_PKCS1_V15) /* constant-time buffer comparison */ @@ -97,6 +99,7 @@ int mbedtls_rsa_import( mbedtls_rsa_context *ctx, const mbedtls_mpi *D, const mbedtls_mpi *E ) { int ret; + RSA_VALIDATE_RET( ctx != NULL ); if( ( N != NULL && ( ret = mbedtls_mpi_copy( &ctx->N, N ) ) != 0 ) || ( P != NULL && ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ) || @@ -121,6 +124,7 @@ int mbedtls_rsa_import_raw( mbedtls_rsa_context *ctx, unsigned char const *E, size_t E_len ) { int ret = 0; + RSA_VALIDATE_RET( ctx != NULL ); if( N != NULL ) { @@ -244,12 +248,16 @@ static int rsa_check_context( mbedtls_rsa_context const *ctx, int is_priv, int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ) { int ret = 0; + int have_N, have_P, have_Q, have_D, have_E; + int n_missing, pq_missing, d_missing, is_pub, is_priv; + + RSA_VALIDATE_RET( ctx != NULL ); - const int have_N = ( mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 ); - const int have_P = ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 ); - const int have_Q = ( mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 ); - const int have_D = ( mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 ); - const int have_E = ( mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0 ); + have_N = ( mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 ); + have_P = ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 ); + have_Q = ( mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 ); + have_D = ( mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 ); + have_E = ( mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0 ); /* * Check whether provided parameters are enough @@ -261,13 +269,13 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ) * */ - const int n_missing = have_P && have_Q && have_D && have_E; - const int pq_missing = have_N && !have_P && !have_Q && have_D && have_E; - const int d_missing = have_P && have_Q && !have_D && have_E; - const int is_pub = have_N && !have_P && !have_Q && !have_D && have_E; + n_missing = have_P && have_Q && have_D && have_E; + pq_missing = have_N && !have_P && !have_Q && have_D && have_E; + d_missing = have_P && have_Q && !have_D && have_E; + is_pub = have_N && !have_P && !have_Q && !have_D && have_E; /* These three alternatives are mutually exclusive */ - const int is_priv = n_missing || pq_missing || d_missing; + is_priv = n_missing || pq_missing || d_missing; if( !is_priv && !is_pub ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -340,9 +348,11 @@ int mbedtls_rsa_export_raw( const mbedtls_rsa_context *ctx, unsigned char *E, size_t E_len ) { int ret = 0; + int is_priv; + RSA_VALIDATE_RET( ctx != NULL ); /* Check if key is private or public */ - const int is_priv = + is_priv = mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && @@ -383,9 +393,11 @@ int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, mbedtls_mpi *D, mbedtls_mpi *E ) { int ret; + int is_priv; + RSA_VALIDATE_RET( ctx != NULL ); /* Check if key is private or public */ - int is_priv = + is_priv = mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && @@ -425,9 +437,11 @@ int mbedtls_rsa_export_crt( const mbedtls_rsa_context *ctx, mbedtls_mpi *DP, mbedtls_mpi *DQ, mbedtls_mpi *QP ) { int ret; + int is_priv; + RSA_VALIDATE_RET( ctx != NULL ); /* Check if key is private or public */ - int is_priv = + is_priv = mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && @@ -463,6 +477,10 @@ void mbedtls_rsa_init( mbedtls_rsa_context *ctx, int padding, int hash_id ) { + RSA_VALIDATE( ctx != NULL ); + RSA_VALIDATE( padding == MBEDTLS_RSA_PKCS_V15 || + padding == MBEDTLS_RSA_PKCS_V21 ); + memset( ctx, 0, sizeof( mbedtls_rsa_context ) ); mbedtls_rsa_set_padding( ctx, padding, hash_id ); @@ -475,8 +493,13 @@ void mbedtls_rsa_init( mbedtls_rsa_context *ctx, /* * Set padding for an existing RSA context */ -void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id ) +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, + int hash_id ) { + RSA_VALIDATE( ctx != NULL ); + RSA_VALIDATE( padding == MBEDTLS_RSA_PKCS_V15 || + padding == MBEDTLS_RSA_PKCS_V21 ); + ctx->padding = padding; ctx->hash_id = hash_id; } @@ -495,6 +518,9 @@ size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ) /* * Generate an RSA keypair + * + * This generation method follows the RSA key pair generation procedure of + * FIPS 186-4 if 2^16 < exponent < 2^256 and nbits = 2048 or nbits = 3072. */ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), @@ -502,65 +528,87 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, unsigned int nbits, int exponent ) { int ret; - mbedtls_mpi H, G; + mbedtls_mpi H, G, L; + int prime_quality = 0; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( f_rng != NULL ); - if( f_rng == NULL || nbits < 128 || exponent < 3 ) + if( nbits < 128 || exponent < 3 || nbits % 2 != 0 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - if( nbits % 2 ) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + /* + * If the modulus is 1024 bit long or shorter, then the security strength of + * the RSA algorithm is less than or equal to 80 bits and therefore an error + * rate of 2^-80 is sufficient. + */ + if( nbits > 1024 ) + prime_quality = MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR; mbedtls_mpi_init( &H ); mbedtls_mpi_init( &G ); + mbedtls_mpi_init( &L ); /* * find primes P and Q with Q < P so that: - * GCD( E, (P-1)*(Q-1) ) == 1 + * 1. |P-Q| > 2^( nbits / 2 - 100 ) + * 2. GCD( E, (P-1)*(Q-1) ) == 1 + * 3. E^-1 mod LCM(P-1, Q-1) > 2^( nbits / 2 ) */ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) ); do { - MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, 0, - f_rng, p_rng ) ); - - MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, 0, - f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, + prime_quality, f_rng, p_rng ) ); - if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) - continue; + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, + prime_quality, f_rng, p_rng ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); - if( mbedtls_mpi_bitlen( &ctx->N ) != nbits ) + /* make sure the difference between p and q is not too small (FIPS 186-4 §B.3.3 step 5.4) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &H, &ctx->P, &ctx->Q ) ); + if( mbedtls_mpi_bitlen( &H ) <= ( ( nbits >= 200 ) ? ( ( nbits >> 1 ) - 99 ) : 0 ) ) continue; - if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) + /* not required by any standards, but some users rely on the fact that P > Q */ + if( H.s < 0 ) mbedtls_mpi_swap( &ctx->P, &ctx->Q ); /* Temporarily replace P,Q by P-1, Q-1 */ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &ctx->P, &ctx->P, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &ctx->Q, &ctx->Q, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &ctx->P, &ctx->Q ) ); + + /* check GCD( E, (P-1)*(Q-1) ) == 1 (FIPS 186-4 §B.3.1 criterion 2(a)) */ MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + continue; + + /* compute smallest possible D = E^-1 mod LCM(P-1, Q-1) (FIPS 186-4 §B.3.1 criterion 3(b)) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->P, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L, NULL, &H, &G ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D, &ctx->E, &L ) ); + + if( mbedtls_mpi_bitlen( &ctx->D ) <= ( ( nbits + 1 ) / 2 ) ) // (FIPS 186-4 §B.3.1 criterion 3(a)) + continue; + + break; } - while( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ); + while( 1 ); /* Restore P,Q */ MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &ctx->P, &ctx->P, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &ctx->Q, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + ctx->len = mbedtls_mpi_size( &ctx->N ); +#if !defined(MBEDTLS_RSA_NO_CRT) /* - * D = E^-1 mod ((P-1)*(Q-1)) * DP = D mod (P - 1) * DQ = D mod (Q - 1) * QP = Q^-1 mod P */ - - MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D, &ctx->E, &H ) ); - -#if !defined(MBEDTLS_RSA_NO_CRT) MBEDTLS_MPI_CHK( mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D, &ctx->DP, &ctx->DQ, &ctx->QP ) ); #endif /* MBEDTLS_RSA_NO_CRT */ @@ -572,6 +620,7 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, mbedtls_mpi_free( &H ); mbedtls_mpi_free( &G ); + mbedtls_mpi_free( &L ); if( ret != 0 ) { @@ -589,6 +638,8 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, */ int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ) { + RSA_VALIDATE_RET( ctx != NULL ); + if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) != 0 ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); @@ -612,6 +663,8 @@ int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ) */ int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) { + RSA_VALIDATE_RET( ctx != NULL ); + if( mbedtls_rsa_check_pubkey( ctx ) != 0 || rsa_check_context( ctx, 1 /* private */, 1 /* blinding */ ) != 0 ) { @@ -641,6 +694,9 @@ int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv ) { + RSA_VALIDATE_RET( pub != NULL ); + RSA_VALIDATE_RET( prv != NULL ); + if( mbedtls_rsa_check_pubkey( pub ) != 0 || mbedtls_rsa_check_privkey( prv ) != 0 ) { @@ -666,6 +722,9 @@ int mbedtls_rsa_public( mbedtls_rsa_context *ctx, int ret; size_t olen; mbedtls_mpi T; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( output != NULL ); if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -808,6 +867,10 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, * checked result; should be the same in the end. */ mbedtls_mpi I, C; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( output != NULL ); + if( rsa_check_context( ctx, 1 /* private key checks */, f_rng != NULL /* blinding y/n */ ) != 0 ) { @@ -1042,7 +1105,7 @@ static int mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, } exit: - mbedtls_zeroize( mask, sizeof( mask ) ); + mbedtls_platform_zeroize( mask, sizeof( mask ) ); return( ret ); } @@ -1068,6 +1131,13 @@ int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, const mbedtls_md_info_t *md_info; mbedtls_md_context_t md_ctx; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( label_len == 0 || label != NULL ); + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -1144,11 +1214,13 @@ int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, int ret; unsigned char *p = output; - if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output != NULL ); + RSA_VALIDATE_RET( input != NULL ); - // We don't check p_rng because it won't be dereferenced here - if( f_rng == NULL || input == NULL || output == NULL ) + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); olen = ctx->len; @@ -1162,6 +1234,9 @@ int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, *p++ = 0; if( mode == MBEDTLS_RSA_PUBLIC ) { + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + *p++ = MBEDTLS_RSA_CRYPT; while( nb_pad-- > 0 ) @@ -1206,6 +1281,12 @@ int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, const unsigned char *input, unsigned char *output ) { + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output != NULL ); + RSA_VALIDATE_RET( input != NULL ); + switch( ctx->padding ) { #if defined(MBEDTLS_PKCS1_V15) @@ -1248,6 +1329,14 @@ int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, const mbedtls_md_info_t *md_info; mbedtls_md_context_t md_ctx; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); + RSA_VALIDATE_RET( label_len == 0 || label != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( olen != NULL ); + /* * Parameters sanity checks */ @@ -1356,8 +1445,8 @@ int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, ret = 0; cleanup: - mbedtls_zeroize( buf, sizeof( buf ) ); - mbedtls_zeroize( lhash, sizeof( lhash ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( lhash, sizeof( lhash ) ); return( ret ); } @@ -1467,11 +1556,7 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, size_t output_max_len ) { int ret; - size_t ilen = ctx->len; - size_t i; - size_t plaintext_max_size = ( output_max_len > ilen - 11 ? - ilen - 11 : - output_max_len ); + size_t ilen, i, plaintext_max_size; unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; /* The following variables take sensitive values: their value must * not leak into the observable behavior of the function other than @@ -1489,6 +1574,18 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, size_t plaintext_size = 0; unsigned output_too_large; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( olen != NULL ); + + ilen = ctx->len; + plaintext_max_size = ( output_max_len > ilen - 11 ? + ilen - 11 : + output_max_len ); + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -1607,7 +1704,7 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, *olen = plaintext_size; cleanup: - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); return( ret ); } @@ -1624,6 +1721,13 @@ int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, unsigned char *output, size_t output_max_len) { + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( olen != NULL ); + switch( ctx->padding ) { #if defined(MBEDTLS_PKCS1_V15) @@ -1660,11 +1764,18 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, size_t olen; unsigned char *p = sig; unsigned char salt[MBEDTLS_MD_MAX_SIZE]; - unsigned int slen, hlen, offset = 0; + size_t slen, min_slen, hlen, offset = 0; int ret; size_t msb; const mbedtls_md_info_t *md_info; mbedtls_md_context_t md_ctx; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + RSA_VALIDATE_RET( sig != NULL ); if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -1689,10 +1800,20 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); hlen = mbedtls_md_get_size( md_info ); - slen = hlen; - if( olen < hlen + slen + 2 ) + /* Calculate the largest possible salt length. Normally this is the hash + * length, which is the maximum length the salt can have. If there is not + * enough room, use the maximum salt length that fits. The constraint is + * that the hash length plus the salt length plus 2 bytes must be at most + * the key length. This complies with FIPS 186-4 §5.5 (e) and RFC 8017 + * (PKCS#1 v2.2) §9.1.1 step 3. */ + min_slen = hlen - 2; + if( olen < hlen + min_slen + 2 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + else if( olen >= hlen + hlen + 2 ) + slen = hlen; + else + slen = olen - hlen - 2; memset( sig, 0, olen ); @@ -1702,7 +1823,7 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, /* Note: EMSA-PSS encoding is over the length of N - 1 bits */ msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; - p += olen - hlen * 2 - 2; + p += olen - hlen - slen - 2; *p++ = 0x01; memcpy( p, salt, slen ); p += slen; @@ -1738,7 +1859,7 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, p += hlen; *p++ = 0xBC; - mbedtls_zeroize( salt, sizeof( salt ) ); + mbedtls_platform_zeroize( salt, sizeof( salt ) ); exit: mbedtls_md_free( &md_ctx ); @@ -1880,7 +2001,7 @@ static int rsa_rsassa_pkcs1_v15_encode( mbedtls_md_type_t md_alg, * after the initial bounds check. */ if( p != dst + dst_len ) { - mbedtls_zeroize( dst, dst_len ); + mbedtls_platform_zeroize( dst, dst_len ); return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); } @@ -1902,6 +2023,14 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, int ret; unsigned char *sig_try = NULL, *verif = NULL; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + RSA_VALIDATE_RET( sig != NULL ); + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -1971,6 +2100,14 @@ int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, const unsigned char *hash, unsigned char *sig ) { + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + RSA_VALIDATE_RET( sig != NULL ); + switch( ctx->padding ) { #if defined(MBEDTLS_PKCS1_V15) @@ -2017,6 +2154,14 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, mbedtls_md_context_t md_ctx; unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -2145,7 +2290,16 @@ int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, const unsigned char *hash, const unsigned char *sig ) { - mbedtls_md_type_t mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE ) + mbedtls_md_type_t mgf1_hash_id; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + + mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE ) ? (mbedtls_md_type_t) ctx->hash_id : md_alg; @@ -2171,9 +2325,19 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, const unsigned char *sig ) { int ret = 0; - const size_t sig_len = ctx->len; + size_t sig_len; unsigned char *encoded = NULL, *encoded_expected = NULL; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + + sig_len = ctx->len; + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -2217,13 +2381,13 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, if( encoded != NULL ) { - mbedtls_zeroize( encoded, sig_len ); + mbedtls_platform_zeroize( encoded, sig_len ); mbedtls_free( encoded ); } if( encoded_expected != NULL ) { - mbedtls_zeroize( encoded_expected, sig_len ); + mbedtls_platform_zeroize( encoded_expected, sig_len ); mbedtls_free( encoded_expected ); } @@ -2243,6 +2407,14 @@ int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, const unsigned char *hash, const unsigned char *sig ) { + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + switch( ctx->padding ) { #if defined(MBEDTLS_PKCS1_V15) @@ -2268,6 +2440,8 @@ int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ) { int ret; + RSA_VALIDATE_RET( dst != NULL ); + RSA_VALIDATE_RET( src != NULL ); dst->ver = src->ver; dst->len = src->len; @@ -2307,14 +2481,23 @@ int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ) */ void mbedtls_rsa_free( mbedtls_rsa_context *ctx ) { - mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->Vf ); - mbedtls_mpi_free( &ctx->RN ); mbedtls_mpi_free( &ctx->D ); - mbedtls_mpi_free( &ctx->Q ); mbedtls_mpi_free( &ctx->P ); - mbedtls_mpi_free( &ctx->E ); mbedtls_mpi_free( &ctx->N ); + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->Vi ); + mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->RN ); + mbedtls_mpi_free( &ctx->D ); + mbedtls_mpi_free( &ctx->Q ); + mbedtls_mpi_free( &ctx->P ); + mbedtls_mpi_free( &ctx->E ); + mbedtls_mpi_free( &ctx->N ); #if !defined(MBEDTLS_RSA_NO_CRT) - mbedtls_mpi_free( &ctx->RQ ); mbedtls_mpi_free( &ctx->RP ); - mbedtls_mpi_free( &ctx->QP ); mbedtls_mpi_free( &ctx->DQ ); + mbedtls_mpi_free( &ctx->RQ ); + mbedtls_mpi_free( &ctx->RP ); + mbedtls_mpi_free( &ctx->QP ); + mbedtls_mpi_free( &ctx->DQ ); mbedtls_mpi_free( &ctx->DP ); #endif /* MBEDTLS_RSA_NO_CRT */ diff --git a/app/mbedtls/library/rsa_internal.c b/app/mbedtls/library/rsa_internal.c index 507009f131..9a42d47ceb 100644 --- a/app/mbedtls/library/rsa_internal.c +++ b/app/mbedtls/library/rsa_internal.c @@ -351,15 +351,20 @@ int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P, */ #if defined(MBEDTLS_GENPRIME) + /* + * When generating keys, the strongest security we support aims for an error + * rate of at most 2^-100 and we are aiming for the same certainty here as + * well. + */ if( f_rng != NULL && P != NULL && - ( ret = mbedtls_mpi_is_prime( P, f_rng, p_rng ) ) != 0 ) + ( ret = mbedtls_mpi_is_prime_ext( P, 50, f_rng, p_rng ) ) != 0 ) { ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; goto cleanup; } if( f_rng != NULL && Q != NULL && - ( ret = mbedtls_mpi_is_prime( Q, f_rng, p_rng ) ) != 0 ) + ( ret = mbedtls_mpi_is_prime_ext( Q, 50, f_rng, p_rng ) ) != 0 ) { ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; goto cleanup; diff --git a/app/mbedtls/library/sha1.c b/app/mbedtls/library/sha1.c index 5d0335d5ae..355c83d2f7 100644 --- a/app/mbedtls/library/sha1.c +++ b/app/mbedtls/library/sha1.c @@ -33,6 +33,7 @@ #if defined(MBEDTLS_SHA1_C) #include "mbedtls/sha1.h" +#include "mbedtls/platform_util.h" #include @@ -45,12 +46,12 @@ #endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_SELF_TEST */ -#if !defined(MBEDTLS_SHA1_ALT) +#define SHA1_VALIDATE_RET(cond) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA1_BAD_INPUT_DATA ) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; -} +#define SHA1_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if !defined(MBEDTLS_SHA1_ALT) /* * 32-bit integer manipulation macros (big endian) @@ -77,6 +78,8 @@ static void mbedtls_zeroize( void *v, size_t n ) { void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) { + SHA1_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); } @@ -85,12 +88,15 @@ void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); } void mbedtls_sha1_clone( mbedtls_sha1_context *dst, const mbedtls_sha1_context *src ) { + SHA1_VALIDATE( dst != NULL ); + SHA1_VALIDATE( src != NULL ); + *dst = *src; } @@ -99,6 +105,8 @@ void mbedtls_sha1_clone( mbedtls_sha1_context *dst, */ int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ) { + SHA1_VALIDATE_RET( ctx != NULL ); + ctx->total[0] = 0; ctx->total[1] = 0; @@ -124,6 +132,9 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, { uint32_t temp, W[16], A, B, C, D, E; + SHA1_VALIDATE_RET( ctx != NULL ); + SHA1_VALIDATE_RET( (const unsigned char *)data != NULL ); + GET_UINT32_BE( W[ 0], data, 0 ); GET_UINT32_BE( W[ 1], data, 4 ); GET_UINT32_BE( W[ 2], data, 8 ); @@ -141,19 +152,21 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, GET_UINT32_BE( W[14], data, 56 ); GET_UINT32_BE( W[15], data, 60 ); -#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) +#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n)))) -#define R(t) \ -( \ - temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ - W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ - ( W[t & 0x0F] = S(temp,1) ) \ -) +#define R(t) \ + ( \ + temp = W[( (t) - 3 ) & 0x0F] ^ W[( (t) - 8 ) & 0x0F] ^ \ + W[( (t) - 14 ) & 0x0F] ^ W[ (t) & 0x0F], \ + ( W[(t) & 0x0F] = S(temp,1) ) \ + ) -#define P(a,b,c,d,e,x) \ -{ \ - e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ -} +#define P(a,b,c,d,e,x) \ + do \ + { \ + (e) += S((a),5) + F((b),(c),(d)) + K + (x); \ + (b) = S((b),30); \ + } while( 0 ) A = ctx->state[0]; B = ctx->state[1]; @@ -161,7 +174,7 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, D = ctx->state[3]; E = ctx->state[4]; -#define F(x,y,z) (z ^ (x & (y ^ z))) +#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define K 0x5A827999 P( A, B, C, D, E, W[0] ); @@ -188,7 +201,7 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, #undef K #undef F -#define F(x,y,z) (x ^ y ^ z) +#define F(x,y,z) ((x) ^ (y) ^ (z)) #define K 0x6ED9EBA1 P( A, B, C, D, E, R(20) ); @@ -215,7 +228,7 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, #undef K #undef F -#define F(x,y,z) ((x & y) | (z & (x | y))) +#define F(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) #define K 0x8F1BBCDC P( A, B, C, D, E, R(40) ); @@ -242,7 +255,7 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, #undef K #undef F -#define F(x,y,z) (x ^ y ^ z) +#define F(x,y,z) ((x) ^ (y) ^ (z)) #define K 0xCA62C1D6 P( A, B, C, D, E, R(60) ); @@ -298,6 +311,9 @@ int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, size_t fill; uint32_t left; + SHA1_VALIDATE_RET( ctx != NULL ); + SHA1_VALIDATE_RET( ilen == 0 || input != NULL ); + if( ilen == 0 ) return( 0 ); @@ -356,6 +372,9 @@ int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, uint32_t used; uint32_t high, low; + SHA1_VALIDATE_RET( ctx != NULL ); + SHA1_VALIDATE_RET( (unsigned char *)output != NULL ); + /* * Add padding: 0x80 then 0x00 until 8 bytes remain for the length */ @@ -424,6 +443,9 @@ int mbedtls_sha1_ret( const unsigned char *input, int ret; mbedtls_sha1_context ctx; + SHA1_VALIDATE_RET( ilen == 0 || input != NULL ); + SHA1_VALIDATE_RET( (unsigned char *)output != NULL ); + mbedtls_sha1_init( &ctx ); if( ( ret = mbedtls_sha1_starts_ret( &ctx ) ) != 0 ) diff --git a/app/mbedtls/library/sha256.c b/app/mbedtls/library/sha256.c index 4ec9164a8d..2dc0e1a2c9 100644 --- a/app/mbedtls/library/sha256.c +++ b/app/mbedtls/library/sha256.c @@ -33,6 +33,7 @@ #if defined(MBEDTLS_SHA256_C) #include "mbedtls/sha256.h" +#include "mbedtls/platform_util.h" #include @@ -48,12 +49,11 @@ #endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_SELF_TEST */ -#if !defined(MBEDTLS_SHA256_ALT) +#define SHA256_VALIDATE_RET(cond) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA256_BAD_INPUT_DATA ) +#define SHA256_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond ) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +#if !defined(MBEDTLS_SHA256_ALT) /* * 32-bit integer manipulation macros (big endian) @@ -80,6 +80,8 @@ do { \ void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) { + SHA256_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); } @@ -88,12 +90,15 @@ void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); } void mbedtls_sha256_clone( mbedtls_sha256_context *dst, const mbedtls_sha256_context *src ) { + SHA256_VALIDATE( dst != NULL ); + SHA256_VALIDATE( src != NULL ); + *dst = *src; } @@ -102,6 +107,9 @@ void mbedtls_sha256_clone( mbedtls_sha256_context *dst, */ int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ) { + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( is224 == 0 || is224 == 1 ); + ctx->total[0] = 0; ctx->total[1] = 0; @@ -164,8 +172,8 @@ static const uint32_t K[] = 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, }; -#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) -#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) +#define SHR(x,n) (((x) & 0xFFFFFFFF) >> (n)) +#define ROTR(x,n) (SHR(x,n) | ((x) << (32 - (n)))) #define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) #define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) @@ -173,21 +181,22 @@ static const uint32_t K[] = #define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) #define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) -#define F0(x,y,z) ((x & y) | (z & (x | y))) -#define F1(x,y,z) (z ^ (x & (y ^ z))) +#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define R(t) \ -( \ - W[t] = S1(W[t - 2]) + W[t - 7] + \ - S0(W[t - 15]) + W[t - 16] \ -) - -#define P(a,b,c,d,e,f,g,h,x,K) \ -{ \ - temp1 = h + S3(e) + F1(e,f,g) + K + x; \ - temp2 = S2(a) + F0(a,b,c); \ - d += temp1; h = temp1 + temp2; \ -} + ( \ + W[t] = S1(W[(t) - 2]) + W[(t) - 7] + \ + S0(W[(t) - 15]) + W[(t) - 16] \ + ) + +#define P(a,b,c,d,e,f,g,h,x,K) \ + do \ + { \ + temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \ + temp2 = S2(a) + F0((a),(b),(c)); \ + (d) += temp1; (h) = temp1 + temp2; \ + } while( 0 ) int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ) @@ -196,6 +205,9 @@ int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, uint32_t A[8]; unsigned int i; + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( (const unsigned char *)data != NULL ); + for( i = 0; i < 8; i++ ) A[i] = ctx->state[i]; @@ -267,6 +279,9 @@ int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, size_t fill; uint32_t left; + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( ilen == 0 || input != NULL ); + if( ilen == 0 ) return( 0 ); @@ -325,6 +340,9 @@ int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, uint32_t used; uint32_t high, low; + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( (unsigned char *)output != NULL ); + /* * Add padding: 0x80 then 0x00 until 8 bytes remain for the length */ @@ -399,6 +417,10 @@ int mbedtls_sha256_ret( const unsigned char *input, int ret; mbedtls_sha256_context ctx; + SHA256_VALIDATE_RET( is224 == 0 || is224 == 1 ); + SHA256_VALIDATE_RET( ilen == 0 || input != NULL ); + SHA256_VALIDATE_RET( (unsigned char *)output != NULL ); + mbedtls_sha256_init( &ctx ); if( ( ret = mbedtls_sha256_starts_ret( &ctx, is224 ) ) != 0 ) diff --git a/app/mbedtls/library/sha512.c b/app/mbedtls/library/sha512.c index db2617ebdf..bdd20b284a 100644 --- a/app/mbedtls/library/sha512.c +++ b/app/mbedtls/library/sha512.c @@ -33,6 +33,7 @@ #if defined(MBEDTLS_SHA512_C) #include "mbedtls/sha512.h" +#include "mbedtls/platform_util.h" #if defined(_MSC_VER) || defined(__WATCOMC__) #define UL64(x) x##ui64 @@ -54,12 +55,11 @@ #endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_SELF_TEST */ -#if !defined(MBEDTLS_SHA512_ALT) +#define SHA512_VALIDATE_RET(cond) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA512_BAD_INPUT_DATA ) +#define SHA512_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond ) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +#if !defined(MBEDTLS_SHA512_ALT) /* * 64-bit integer manipulation macros (big endian) @@ -94,6 +94,8 @@ static void mbedtls_zeroize( void *v, size_t n ) { void mbedtls_sha512_init( mbedtls_sha512_context *ctx ) { + SHA512_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_sha512_context ) ); } @@ -102,12 +104,15 @@ void mbedtls_sha512_free( mbedtls_sha512_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_sha512_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha512_context ) ); } void mbedtls_sha512_clone( mbedtls_sha512_context *dst, const mbedtls_sha512_context *src ) { + SHA512_VALIDATE( dst != NULL ); + SHA512_VALIDATE( src != NULL ); + *dst = *src; } @@ -116,6 +121,9 @@ void mbedtls_sha512_clone( mbedtls_sha512_context *dst, */ int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ) { + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( is384 == 0 || is384 == 1 ); + ctx->total[0] = 0; ctx->total[1] = 0; @@ -213,8 +221,11 @@ int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, uint64_t temp1, temp2, W[80]; uint64_t A, B, C, D, E, F, G, H; -#define SHR(x,n) (x >> n) -#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( (const unsigned char *)data != NULL ); + +#define SHR(x,n) ((x) >> (n)) +#define ROTR(x,n) (SHR((x),(n)) | ((x) << (64 - (n)))) #define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) #define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) @@ -222,15 +233,16 @@ int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, #define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) #define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) -#define F0(x,y,z) ((x & y) | (z & (x | y))) -#define F1(x,y,z) (z ^ (x & (y ^ z))) +#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define P(a,b,c,d,e,f,g,h,x,K) \ -{ \ - temp1 = h + S3(e) + F1(e,f,g) + K + x; \ - temp2 = S2(a) + F0(a,b,c); \ - d += temp1; h = temp1 + temp2; \ -} +#define P(a,b,c,d,e,f,g,h,x,K) \ + do \ + { \ + temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \ + temp2 = S2(a) + F0((a),(b),(c)); \ + (d) += temp1; (h) = temp1 + temp2; \ + } while( 0 ) for( i = 0; i < 16; i++ ) { @@ -298,6 +310,9 @@ int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, size_t fill; unsigned int left; + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( ilen == 0 || input != NULL ); + if( ilen == 0 ) return( 0 ); @@ -355,6 +370,9 @@ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, unsigned used; uint64_t high, low; + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( (unsigned char *)output != NULL ); + /* * Add padding: 0x80 then 0x00 until 16 bytes remain for the length */ @@ -431,6 +449,10 @@ int mbedtls_sha512_ret( const unsigned char *input, int ret; mbedtls_sha512_context ctx; + SHA512_VALIDATE_RET( is384 == 0 || is384 == 1 ); + SHA512_VALIDATE_RET( ilen == 0 || input != NULL ); + SHA512_VALIDATE_RET( (unsigned char *)output != NULL ); + mbedtls_sha512_init( &ctx ); if( ( ret = mbedtls_sha512_starts_ret( &ctx, is384 ) ) != 0 ) diff --git a/app/mbedtls/library/ssl_ciphersuites.c b/app/mbedtls/library/ssl_ciphersuites.c index 800b5f84d8..518f7dde00 100644 --- a/app/mbedtls/library/ssl_ciphersuites.c +++ b/app/mbedtls/library/ssl_ciphersuites.c @@ -43,11 +43,11 @@ /* * Ordered from most preferred to least preferred in terms of security. * - * Current rule (except rc4, weak and null which come last): + * Current rule (except RC4 and 3DES, weak and null which come last): * 1. By key exchange: * Forward-secure non-PSK > forward-secure PSK > ECJPAKE > other non-PSK > other PSK * 2. By key length and cipher: - * AES-256 > Camellia-256 > AES-128 > Camellia-128 > 3DES + * ChaCha > AES-256 > Camellia-256 > ARIA-256 > AES-128 > Camellia-128 > ARIA-128 * 3. By cipher mode when relevant GCM > CCM > CBC > CCM_8 * 4. By hash function used when relevant * 5. By key exchange/auth again: EC > non-EC @@ -57,6 +57,11 @@ static const int ciphersuite_preference[] = #if defined(MBEDTLS_SSL_CIPHERSUITES) MBEDTLS_SSL_CIPHERSUITES, #else + /* Chacha-Poly ephemeral suites */ + MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + /* All AES-256 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, @@ -81,6 +86,14 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + /* All ARIA-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, + /* All AES-128 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, @@ -105,12 +118,17 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, - /* All remaining >= 128-bit ephemeral suites */ - MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + /* All ARIA-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, /* The PSK ephemeral suites */ + MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, @@ -121,6 +139,9 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, @@ -132,9 +153,9 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, - - MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, - MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, /* The ECJPAKE suite */ MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, @@ -161,6 +182,14 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + /* All ARIA-256 suites */ + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384, + /* All AES-128 suites */ MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, MBEDTLS_TLS_RSA_WITH_AES_128_CCM, @@ -183,27 +212,34 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, - /* All remaining >= 128-bit suites */ - MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, - MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + /* All ARIA-128 suites */ + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256, /* The RSA PSK suites */ + MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384, MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, - - MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256, /* The PSK suites */ + MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_PSK_WITH_AES_256_CCM, MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, @@ -211,6 +247,8 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, + MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384, MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, MBEDTLS_TLS_PSK_WITH_AES_128_CCM, @@ -219,7 +257,19 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, + MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256, + /* 3DES suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, /* RC4 suites */ @@ -266,6 +316,75 @@ static const int ciphersuite_preference[] = static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = { +#if defined(MBEDTLS_CHACHAPOLY_C) && \ + defined(MBEDTLS_SHA256_C) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + { MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + { MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-ECDHE-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + { MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-DHE-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + { MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-RSA-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#endif /* MBEDTLS_CHACHAPOLY_C && + MBEDTLS_SHA256_C && + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) #if defined(MBEDTLS_AES_C) #if defined(MBEDTLS_SHA1_C) @@ -1688,6 +1807,365 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = #endif /* MBEDTLS_DES_C */ #endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ +#if defined(MBEDTLS_ARIA_C) + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, + "TLS-RSA-PSK-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-RSA-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, + "TLS-RSA-PSK-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-RSA-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384, + "TLS-PSK-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384,MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256, + "TLS-PSK-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDH-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDH-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDH-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDH-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDHE-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDHE-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDHE-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDHE-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDHE-ECDSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDHE-ECDSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDH-ECDSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDH-ECDSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDH-ECDSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDH-ECDSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-DHE-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-DHE-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, + "TLS-DHE-PSK-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-DHE-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, + "TLS-DHE-PSK-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-DHE-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#endif /* MBEDTLS_ARIA_C */ + + { 0, "", MBEDTLS_CIPHER_NONE, MBEDTLS_MD_NONE, MBEDTLS_KEY_EXCHANGE_NONE, 0, 0, 0, 0, 0 } @@ -1704,6 +2182,26 @@ const int *mbedtls_ssl_list_ciphersuites( void ) static int supported_ciphersuites[MAX_CIPHERSUITES]; static int supported_init = 0; +static int ciphersuite_is_removed( const mbedtls_ssl_ciphersuite_t *cs_info ) +{ + (void)cs_info; + +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + if( cs_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + return( 1 ); +#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */ + +#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES) + if( cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_ECB || + cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_CBC ) + { + return( 1 ); + } +#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */ + + return( 0 ); +} + const int *mbedtls_ssl_list_ciphersuites( void ) { /* @@ -1719,14 +2217,12 @@ const int *mbedtls_ssl_list_ciphersuites( void ) *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1; p++ ) { -#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) const mbedtls_ssl_ciphersuite_t *cs_info; if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL && - cs_info->cipher != MBEDTLS_CIPHER_ARC4_128 ) -#else - if( mbedtls_ssl_ciphersuite_from_id( *p ) != NULL ) -#endif + !ciphersuite_is_removed( cs_info ) ) + { *(q++) = *p; + } } *q = 0; diff --git a/app/mbedtls/library/ssl_cli.c b/app/mbedtls/library/ssl_cli.c index 0d3623e613..afced7a99c 100644 --- a/app/mbedtls/library/ssl_cli.c +++ b/app/mbedtls/library/ssl_cli.c @@ -48,10 +48,7 @@ #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +#include "mbedtls/platform_util.h" #endif #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) @@ -60,7 +57,7 @@ static void ssl_write_hostname_ext( mbedtls_ssl_context *ssl, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; size_t hostname_len; *olen = 0; @@ -130,7 +127,7 @@ static void ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; *olen = 0; @@ -174,7 +171,7 @@ static void ssl_write_signature_algorithms_ext( mbedtls_ssl_context *ssl, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; size_t sig_alg_len = 0; const int *md; #if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) @@ -259,7 +256,7 @@ static void ssl_write_supported_elliptic_curves_ext( mbedtls_ssl_context *ssl, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; unsigned char *elliptic_curve_list = p + 6; size_t elliptic_curve_len = 0; const mbedtls_ecp_curve_info *info; @@ -332,7 +329,7 @@ static void ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; *olen = 0; @@ -365,7 +362,7 @@ static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, { int ret; unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; size_t kkpp_len; *olen = 0; @@ -442,7 +439,7 @@ static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; *olen = 0; @@ -475,7 +472,7 @@ static void ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl, unsigned char *buf, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; *olen = 0; @@ -507,7 +504,7 @@ static void ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, unsigned char *buf, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; *olen = 0; @@ -541,7 +538,7 @@ static void ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl, unsigned char *buf, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; *olen = 0; @@ -575,7 +572,7 @@ static void ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl, unsigned char *buf, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; size_t tlen = ssl->session_negotiate->ticket_len; *olen = 0; @@ -619,7 +616,7 @@ static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, unsigned char *buf, size_t *olen ) { unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; size_t alpnlen = 0; const char **cur; @@ -1091,12 +1088,21 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) mbedtls_ssl_send_flight_completed( ssl ); #endif - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client hello" ) ); return( 0 ); @@ -1494,7 +1500,7 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) buf = ssl->in_msg; - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { /* No alert on a read error. */ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); @@ -1757,6 +1763,14 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + ssl->handshake->ecrs_enabled = 1; + } +#endif + if( comp != MBEDTLS_SSL_COMPRESS_NULL #if defined(MBEDTLS_ZLIB_SUPPORT) && comp != MBEDTLS_SSL_COMPRESS_DEFLATE @@ -2013,8 +2027,14 @@ static int ssl_parse_server_dh_params( mbedtls_ssl_context *ssl, unsigned char * static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) { const mbedtls_ecp_curve_info *curve_info; + mbedtls_ecp_group_id grp_id; +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + grp_id = ssl->handshake->ecdh_ctx.grp.id; +#else + grp_id = ssl->handshake->ecdh_ctx.grp_id; +#endif - curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + curve_info = mbedtls_ecp_curve_info_from_grp_id( grp_id ); if( curve_info == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); @@ -2024,14 +2044,15 @@ static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); #if defined(MBEDTLS_ECP_C) - if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) + if( mbedtls_ssl_check_curve( ssl, grp_id ) != 0 ) #else if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || ssl->handshake->ecdh_ctx.grp.nbits > 521 ) #endif return( -1 ); - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); return( 0 ); } @@ -2062,6 +2083,10 @@ static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl, (const unsigned char **) p, end ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_params" ), ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif return( ret ); } @@ -2132,7 +2157,7 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2; unsigned char *p = ssl->handshake->premaster + pms_offset; - if( offset + len_bytes > MBEDTLS_SSL_MAX_CONTENT_LEN ) + if( offset + len_bytes > MBEDTLS_SSL_OUT_CONTENT_LEN ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small for encrypted pms" ) ); return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); @@ -2175,7 +2200,7 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, if( ( ret = mbedtls_pk_encrypt( &ssl->session_negotiate->peer_cert->pk, p, ssl->handshake->pmslen, ssl->out_msg + offset + len_bytes, olen, - MBEDTLS_SSL_MAX_CONTENT_LEN - offset - len_bytes, + MBEDTLS_SSL_OUT_CONTENT_LEN - offset - len_bytes, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_rsa_pkcs1_encrypt", ret ); @@ -2343,7 +2368,15 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled && + ssl->handshake->ecrs_state == ssl_ecrs_ske_start_processing ) + { + goto start_processing; + } +#endif + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); @@ -2380,6 +2413,12 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); } +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + ssl->handshake->ecrs_state = ssl_ecrs_ske_start_processing; + +start_processing: +#endif p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); end = ssl->in_msg + ssl->in_hslen; MBEDTLS_SSL_DEBUG_BUF( 3, "server key exchange", p, end - p ); @@ -2472,6 +2511,7 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; unsigned char *params = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); size_t params_len = p - params; + void *rs_ctx = NULL; /* * Handle the digitally-signed structure @@ -2518,6 +2558,7 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) /* * Read signature */ + if( p > end - 2 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); @@ -2558,10 +2599,9 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) defined(MBEDTLS_SSL_PROTO_TLS1_2) if( md_alg != MBEDTLS_MD_NONE ) { - /* Info from md_alg will be used instead */ - hashlen = 0; - ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, params, - params_len, md_alg ); + ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, &hashlen, + params, params_len, + md_alg ); if( ret != 0 ) return( ret ); } @@ -2573,8 +2613,7 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen : - (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); if( ssl->session_negotiate->peer_cert == NULL ) { @@ -2595,12 +2634,25 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); } - if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk, - md_alg, hash, hashlen, p, sig_len ) ) != 0 ) +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + rs_ctx = &ssl->handshake->ecrs_ctx.pk; +#endif + + if( ( ret = mbedtls_pk_verify_restartable( + &ssl->session_negotiate->peer_cert->pk, + md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 ) { - mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) +#endif + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR ); MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif return( ret ); } } @@ -2651,7 +2703,7 @@ static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl ) return( 0 ); } - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); @@ -2803,7 +2855,7 @@ static int ssl_parse_server_hello_done( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) ); - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); @@ -2898,6 +2950,16 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) */ i = 4; +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + { + if( ssl->handshake->ecrs_state == ssl_ecrs_cke_ecdh_calc_secret ) + goto ecdh_calc_secret; + + mbedtls_ecdh_enable_restart( &ssl->handshake->ecdh_ctx ); + } +#endif + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, &n, &ssl->out_msg[i], 1000, @@ -2905,11 +2967,27 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) if( ret != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif return( ret ); } - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + { + ssl->handshake->ecrs_n = n; + ssl->handshake->ecrs_state = ssl_ecrs_cke_ecdh_calc_secret; + } +ecdh_calc_secret: + if( ssl->handshake->ecrs_enabled ) + n = ssl->handshake->ecrs_n; +#endif if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &ssl->handshake->pmslen, ssl->handshake->premaster, @@ -2917,10 +2995,15 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif return( ret ); } - MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || @@ -2942,7 +3025,7 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) i = 4; n = ssl->conf->psk_identity_len; - if( i + 2 + n > MBEDTLS_SSL_MAX_CONTENT_LEN ) + if( i + 2 + n > MBEDTLS_SSL_OUT_CONTENT_LEN ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity too long or " "SSL buffer too short" ) ); @@ -2978,7 +3061,7 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) */ n = ssl->handshake->dhm_ctx.len; - if( i + 2 + n > MBEDTLS_SSL_MAX_CONTENT_LEN ) + if( i + 2 + n > MBEDTLS_SSL_OUT_CONTENT_LEN ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity or DHM size too long" " or SSL buffer too short" ) ); @@ -3007,7 +3090,7 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) * ClientECDiffieHellmanPublic public; */ ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, &n, - &ssl->out_msg[i], MBEDTLS_SSL_MAX_CONTENT_LEN - i, + &ssl->out_msg[i], MBEDTLS_SSL_OUT_CONTENT_LEN - i, ssl->conf->f_rng, ssl->conf->p_rng ); if( ret != 0 ) { @@ -3015,7 +3098,8 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) return( ret ); } - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ @@ -3048,7 +3132,7 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) i = 4; ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, - ssl->out_msg + i, MBEDTLS_SSL_MAX_CONTENT_LEN - i, &n, + ssl->out_msg + i, MBEDTLS_SSL_OUT_CONTENT_LEN - i, &n, ssl->conf->f_rng, ssl->conf->p_rng ); if( ret != 0 ) { @@ -3079,9 +3163,9 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) ssl->state++; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } @@ -3135,9 +3219,18 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) unsigned char *hash_start = hash; mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; unsigned int hashlen; + void *rs_ctx = NULL; MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled && + ssl->handshake->ecrs_state == ssl_ecrs_crt_vrfy_sign ) + { + goto sign; + } +#endif + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); @@ -3169,8 +3262,15 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) } /* - * Make an RSA signature of the handshake digests + * Make a signature of the handshake digests */ +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + ssl->handshake->ecrs_state = ssl_ecrs_crt_vrfy_sign; + +sign: +#endif + ssl->handshake->calc_verify( ssl, hash ); #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ @@ -3247,11 +3347,21 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash_start, hashlen, +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + rs_ctx = &ssl->handshake->ecrs_ctx.pk; +#endif + + if( ( ret = mbedtls_pk_sign_restartable( mbedtls_ssl_own_key( ssl ), + md_alg, hash_start, hashlen, ssl->out_msg + 6 + offset, &n, - ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + ssl->conf->f_rng, ssl->conf->p_rng, rs_ctx ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif return( ret ); } @@ -3264,9 +3374,9 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) ssl->state++; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } @@ -3292,7 +3402,7 @@ static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); @@ -3353,8 +3463,8 @@ static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl ) if( ticket_len == 0 ) return( 0 ); - mbedtls_zeroize( ssl->session_negotiate->ticket, - ssl->session_negotiate->ticket_len ); + mbedtls_platform_zeroize( ssl->session_negotiate->ticket, + ssl->session_negotiate->ticket_len ); mbedtls_free( ssl->session_negotiate->ticket ); ssl->session_negotiate->ticket = NULL; ssl->session_negotiate->ticket_len = 0; @@ -3406,10 +3516,10 @@ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) { - if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) return( ret ); } -#endif +#endif /* MBEDTLS_SSL_PROTO_DTLS */ /* Change state now, so that it is right in mbedtls_ssl_read_record(), used * by DTLS for dropping out-of-sequence ChangeCipherSpec records */ diff --git a/app/mbedtls/library/ssl_cookie.c b/app/mbedtls/library/ssl_cookie.c index caf119990d..56e9bdd2bf 100644 --- a/app/mbedtls/library/ssl_cookie.c +++ b/app/mbedtls/library/ssl_cookie.c @@ -40,14 +40,10 @@ #include "mbedtls/ssl_cookie.h" #include "mbedtls/ssl_internal.h" +#include "mbedtls/platform_util.h" #include -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * If DTLS is in use, then at least one of SHA-1, SHA-256, SHA-512 is * available. Try SHA-256 first, 512 wastes resources since we need to stay @@ -101,7 +97,7 @@ void mbedtls_ssl_cookie_free( mbedtls_ssl_cookie_ctx *ctx ) mbedtls_mutex_free( &ctx->mutex ); #endif - mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_cookie_ctx ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_cookie_ctx ) ); } int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, @@ -122,7 +118,7 @@ int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, if( ret != 0 ) return( ret ); - mbedtls_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( key, sizeof( key ) ); return( 0 ); } diff --git a/app/mbedtls/library/ssl_srv.c b/app/mbedtls/library/ssl_srv.c index c8da871cd7..5825970c43 100644 --- a/app/mbedtls/library/ssl_srv.c +++ b/app/mbedtls/library/ssl_srv.c @@ -38,6 +38,7 @@ #include "mbedtls/debug.h" #include "mbedtls/ssl.h" #include "mbedtls/ssl_internal.h" +#include "mbedtls/platform_util.h" #include @@ -49,13 +50,6 @@ #include "mbedtls/platform_time.h" #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} -#endif - #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, const unsigned char *info, @@ -572,7 +566,7 @@ static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl, memcpy( ssl->session_negotiate, &session, sizeof( mbedtls_ssl_session ) ); /* Zeroize instead of free as we copied the content */ - mbedtls_zeroize( &session, sizeof( mbedtls_ssl_session ) ); + mbedtls_platform_zeroize( &session, sizeof( mbedtls_ssl_session ) ); MBEDTLS_SSL_DEBUG_MSG( 3, ( "session successfully restored from ticket" ) ); @@ -734,7 +728,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate", cur->cert ); - if( ! mbedtls_pk_can_do( cur->key, pk_alg ) ) + if( ! mbedtls_pk_can_do( &cur->cert->pk, pk_alg ) ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) ); continue; @@ -758,7 +752,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_ECDSA_C) if( pk_alg == MBEDTLS_PK_ECDSA && - ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 ) + ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); continue; @@ -1300,7 +1294,7 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); } - memcpy( ssl->out_ctr + 2, ssl->in_ctr + 2, 6 ); + memcpy( ssl->cur_out_ctr + 2, ssl->in_ctr + 2, 6 ); #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) if( mbedtls_ssl_dtls_replay_check( ssl ) != 0 ) @@ -1328,7 +1322,7 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) else #endif { - if( msg_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + if( msg_len > MBEDTLS_SSL_IN_CONTENT_LEN ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); @@ -1455,7 +1449,7 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) */ /* - * Minimal length (with everything empty and extensions ommitted) is + * Minimal length (with everything empty and extensions omitted) is * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can * read at least up to session id length without worrying. */ @@ -2266,7 +2260,7 @@ static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, { int ret; unsigned char *p = buf; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; size_t kkpp_len; *olen = 0; @@ -2373,7 +2367,7 @@ static int ssl_write_hello_verify_request( mbedtls_ssl_context *ssl ) cookie_len_byte = p++; if( ( ret = ssl->conf->f_cookie_write( ssl->conf->p_cookie, - &p, ssl->out_buf + MBEDTLS_SSL_BUFFER_LEN, + &p, ssl->out_buf + MBEDTLS_SSL_OUT_BUFFER_LEN, ssl->cli_id, ssl->cli_id_len ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "f_cookie_write", ret ); @@ -2390,11 +2384,20 @@ static int ssl_write_hello_verify_request( mbedtls_ssl_context *ssl ) ssl->state = MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); return( ret ); } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello verify request" ) ); @@ -2630,7 +2633,7 @@ static int ssl_write_server_hello( mbedtls_ssl_context *ssl ) ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; - ret = mbedtls_ssl_write_record( ssl ); + ret = mbedtls_ssl_write_handshake_msg( ssl ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); @@ -2673,7 +2676,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) size_t dn_size, total_dn_size; /* excluding length bytes */ size_t ct_len, sa_len; /* including length bytes */ unsigned char *buf, *p; - const unsigned char * const end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const unsigned char * const end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; const mbedtls_x509_crt *crt; int authmode; @@ -2825,7 +2828,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) ssl->out_msg[4 + ct_len + sa_len] = (unsigned char)( total_dn_size >> 8 ); ssl->out_msg[5 + ct_len + sa_len] = (unsigned char)( total_dn_size ); - ret = mbedtls_ssl_write_record( ssl ); + ret = mbedtls_ssl_write_handshake_msg( ssl ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); @@ -2863,54 +2866,56 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ -static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ + defined(MBEDTLS_SSL_ASYNC_PRIVATE) +static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, + size_t *signature_len ) +{ + /* Append the signature to ssl->out_msg, leaving 2 bytes for the + * signature length which will be added in ssl_write_server_key_exchange + * after the call to ssl_prepare_server_key_exchange. + * ssl_write_server_key_exchange also takes care of incrementing + * ssl->out_msglen. */ + unsigned char *sig_start = ssl->out_msg + ssl->out_msglen + 2; + size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_OUT_CONTENT_LEN + - sig_start ); + int ret = ssl->conf->f_async_resume( ssl, + sig_start, signature_len, sig_max_len ); + if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + { + ssl->handshake->async_in_progress = 0; + mbedtls_ssl_set_async_operation_data( ssl, NULL ); + } + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_resume_server_key_exchange", ret ); + return( ret ); +} +#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && + defined(MBEDTLS_SSL_ASYNC_PRIVATE) */ + +/* Prepare the ServerKeyExchange message, up to and including + * calculating the signature if any, but excluding formatting the + * signature and sending the message. */ +static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, + size_t *signature_len ) { - int ret; - size_t n = 0; const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; - #if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) - unsigned char *p = ssl->out_msg + 4; - size_t len = 0; #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) - unsigned char *dig_signed = p; - size_t dig_signed_len = 0; + unsigned char *dig_signed = NULL; #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ #endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); - - /* - * - * Part 1: Extract static ECDH parameters and abort - * if ServerKeyExchange not needed. - * - */ - - /* For suites involving ECDH, extract DH parameters - * from certificate at this point. */ -#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED) - if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) ) - { - ssl_get_ecdh_params_from_cert( ssl ); - } -#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */ + (void) ciphersuite_info; /* unused in some configurations */ +#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + (void) signature_len; +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ - /* Key exchanges not involving ephemeral keys don't use - * ServerKeyExchange, so end here. */ -#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) - if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) ) - { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); - ssl->state++; - return( 0 ); - } -#endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */ + ssl->out_msglen = 4; /* header (type:1, length:3) to be written later */ /* * - * Part 2: Provide key exchange parameters for chosen ciphersuite. + * Part 1: Provide key exchange parameters for chosen ciphersuite. * */ @@ -2920,18 +2925,21 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) { - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + int ret; + size_t len = 0; - ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, - p, end - p, &len, ssl->conf->f_rng, ssl->conf->p_rng ); + ret = mbedtls_ecjpake_write_round_two( + &ssl->handshake->ecjpake_ctx, + ssl->out_msg + ssl->out_msglen, + MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen, &len, + ssl->conf->f_rng, ssl->conf->p_rng ); if( ret != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret ); return( ret ); } - p += len; - n += len; + ssl->out_msglen += len; } #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ @@ -2945,10 +2953,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) { - *(p++) = 0x00; - *(p++) = 0x00; - - n += 2; + ssl->out_msg[ssl->out_msglen++] = 0x00; + ssl->out_msg[ssl->out_msglen++] = 0x00; } #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED || MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ @@ -2959,6 +2965,9 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED) if( mbedtls_ssl_ciphersuite_uses_dhe( ciphersuite_info ) ) { + int ret; + size_t len = 0; + if( ssl->conf->dhm_P.p == NULL || ssl->conf->dhm_G.p == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "no DH parameters set" ) ); @@ -2982,21 +2991,21 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) return( ret ); } - if( ( ret = mbedtls_dhm_make_params( &ssl->handshake->dhm_ctx, - (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), - p, &len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + if( ( ret = mbedtls_dhm_make_params( + &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + ssl->out_msg + ssl->out_msglen, &len, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_params", ret ); return( ret ); } #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) - dig_signed = p; - dig_signed_len = len; + dig_signed = ssl->out_msg + ssl->out_msglen; #endif - p += len; - n += len; + ssl->out_msglen += len; MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); @@ -3021,6 +3030,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) */ const mbedtls_ecp_curve_info **curve = NULL; const mbedtls_ecp_group_id *gid; + int ret; + size_t len = 0; /* Match our preference list against the offered curves */ for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) @@ -3037,48 +3048,50 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", (*curve)->name ) ); - if( ( ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, - (*curve)->grp_id ) ) != 0 ) + if( ( ret = mbedtls_ecdh_setup( &ssl->handshake->ecdh_ctx, + (*curve)->grp_id ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); return( ret ); } - if( ( ret = mbedtls_ecdh_make_params( &ssl->handshake->ecdh_ctx, &len, - p, MBEDTLS_SSL_MAX_CONTENT_LEN - n, - ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + if( ( ret = mbedtls_ecdh_make_params( + &ssl->handshake->ecdh_ctx, &len, + ssl->out_msg + ssl->out_msglen, + MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret ); return( ret ); } #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) - dig_signed = p; - dig_signed_len = len; + dig_signed = ssl->out_msg + ssl->out_msglen; #endif - p += len; - n += len; + ssl->out_msglen += len; - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); } #endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ /* * - * Part 3: For key exchanges involving the server signing the + * Part 2: For key exchanges involving the server signing the * exchange parameters, compute and add the signature here. * */ #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) ) { - size_t signature_len = 0; - unsigned int hashlen = 0; - unsigned char hash[64]; + size_t dig_signed_len = ssl->out_msg + ssl->out_msglen - dig_signed; + size_t hashlen = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + int ret; /* - * 3.1: Choose hash algorithm: + * 2.1: Choose hash algorithm: * A: For TLS 1.2, obey signature-hash-algorithm extension * to choose appropriate hash. * B: For SSL3, TLS1.0, TLS1.1 and ECDHE_ECDSA, use SHA1 @@ -3125,7 +3138,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 3, ( "pick hash algorithm %d for signing", md_alg ) ); /* - * 3.2: Compute the hash to be signed + * 2.2: Compute the hash to be signed */ #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) @@ -3145,9 +3158,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) defined(MBEDTLS_SSL_PROTO_TLS1_2) if( md_alg != MBEDTLS_MD_NONE ) { - /* Info from md_alg will be used instead */ - hashlen = 0; - ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, + ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, &hashlen, dig_signed, dig_signed_len, md_alg ); @@ -3162,18 +3173,11 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen : - (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); /* - * 3.3: Compute and add the signature + * 2.3: Compute and add the signature */ - if( mbedtls_ssl_own_key( ssl ) == NULL ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) ); - return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); - } - #if defined(MBEDTLS_SSL_PROTO_TLS1_2) if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) { @@ -3193,46 +3197,162 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) * */ - *(p++) = mbedtls_ssl_hash_from_md_alg( md_alg ); - *(p++) = mbedtls_ssl_sig_from_pk_alg( sig_alg ); - - n += 2; + ssl->out_msg[ssl->out_msglen++] = + mbedtls_ssl_hash_from_md_alg( md_alg ); + ssl->out_msg[ssl->out_msglen++] = + mbedtls_ssl_sig_from_pk_alg( sig_alg ); } #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ - if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash, hashlen, - p + 2 , &signature_len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if( ssl->conf->f_async_sign_start != NULL ) + { + ret = ssl->conf->f_async_sign_start( ssl, + mbedtls_ssl_own_cert( ssl ), + md_alg, hash, hashlen ); + switch( ret ) + { + case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH: + /* act as if f_async_sign was null */ + break; + case 0: + ssl->handshake->async_in_progress = 1; + return( ssl_resume_server_key_exchange( ssl, signature_len ) ); + case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: + ssl->handshake->async_in_progress = 1; + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + default: + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign_start", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* Append the signature to ssl->out_msg, leaving 2 bytes for the + * signature length which will be added in ssl_write_server_key_exchange + * after the call to ssl_prepare_server_key_exchange. + * ssl_write_server_key_exchange also takes care of incrementing + * ssl->out_msglen. */ + if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), + md_alg, hash, hashlen, + ssl->out_msg + ssl->out_msglen + 2, + signature_len, + ssl->conf->f_rng, + ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); return( ret ); } + } +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + + return( 0 ); +} + +/* Prepare the ServerKeyExchange message and send it. For ciphersuites + * that do not include a ServerKeyExchange message, do nothing. Either + * way, if successful, move on to the next step in the SSL state + * machine. */ +static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t signature_len = 0; +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) + /* Extract static ECDH parameters and abort if ServerKeyExchange + * is not needed. */ + if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) ) + { + /* For suites involving ECDH, extract DH parameters + * from certificate at this point. */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED) + if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) ) + { + ssl_get_ecdh_params_from_cert( ssl ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */ - *(p++) = (unsigned char)( signature_len >> 8 ); - *(p++) = (unsigned char)( signature_len ); - n += 2; + /* Key exchanges not involving ephemeral keys don't use + * ServerKeyExchange, so end here. */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ - MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", p, signature_len ); +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ + defined(MBEDTLS_SSL_ASYNC_PRIVATE) + /* If we have already prepared the message and there is an ongoing + * signature operation, resume signing. */ + if( ssl->handshake->async_in_progress != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); + ret = ssl_resume_server_key_exchange( ssl, &signature_len ); + } + else +#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && + defined(MBEDTLS_SSL_ASYNC_PRIVATE) */ + { + /* ServerKeyExchange is needed. Prepare the message. */ + ret = ssl_prepare_server_key_exchange( ssl, &signature_len ); + } - n += signature_len; + if( ret != 0 ) + { + /* If we're starting to write a new message, set ssl->out_msglen + * to 0. But if we're resuming after an asynchronous message, + * out_msglen is the amount of data written so far and mst be + * preserved. */ + if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) ); + else + ssl->out_msglen = 0; + return( ret ); } -#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ - /* Done with actual work; add header and send. */ + /* If there is a signature, write its length. + * ssl_prepare_server_key_exchange already wrote the signature + * itself at its proper place in the output buffer. */ +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + if( signature_len != 0 ) + { + ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len >> 8 ); + ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len ); - ssl->out_msglen = 4 + n; + MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", + ssl->out_msg + ssl->out_msglen, + signature_len ); + + /* Skip over the already-written signature */ + ssl->out_msglen += signature_len; + } +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + + /* Add header and send. */ ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE; ssl->state++; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) ); - return( 0 ); } @@ -3253,12 +3373,21 @@ static int ssl_write_server_hello_done( mbedtls_ssl_context *ssl ) mbedtls_ssl_send_flight_completed( ssl ); #endif - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello done" ) ); return( 0 ); @@ -3307,28 +3436,50 @@ static int ssl_parse_client_dh_public( mbedtls_ssl_context *ssl, unsigned char * #if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) -static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, - const unsigned char *p, - const unsigned char *end, - size_t pms_offset ) + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl, + unsigned char *peer_pms, + size_t *peer_pmslen, + size_t peer_pmssize ) +{ + int ret = ssl->conf->f_async_resume( ssl, + peer_pms, peer_pmslen, peer_pmssize ); + if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + { + ssl->handshake->async_in_progress = 0; + mbedtls_ssl_set_async_operation_data( ssl, NULL ); + } + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret ); + return( ret ); +} +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, + const unsigned char *p, + const unsigned char *end, + unsigned char *peer_pms, + size_t *peer_pmslen, + size_t peer_pmssize ) { int ret; - size_t len = mbedtls_pk_get_len( mbedtls_ssl_own_key( ssl ) ); - unsigned char *pms = ssl->handshake->premaster + pms_offset; - unsigned char ver[2]; - unsigned char fake_pms[48], peer_pms[48]; - unsigned char mask; - size_t i, peer_pmslen; - unsigned int diff; + mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl ); + mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk; + size_t len = mbedtls_pk_get_len( public_key ); - if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) ) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + /* If we have already started decoding the message and there is an ongoing + * decryption operation, resume signing. */ + if( ssl->handshake->async_in_progress != 0 ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) ); - return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming decryption operation" ) ); + return( ssl_resume_decrypt_pms( ssl, + peer_pms, peer_pmslen, peer_pmssize ) ); } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /* - * Decrypt the premaster using own private RSA key + * Prepare to decrypt the premaster using own private RSA key */ #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_2) @@ -3353,30 +3504,120 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); } + /* + * Decrypt the premaster secret + */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if( ssl->conf->f_async_decrypt_start != NULL ) + { + ret = ssl->conf->f_async_decrypt_start( ssl, + mbedtls_ssl_own_cert( ssl ), + p, len ); + switch( ret ) + { + case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH: + /* act as if f_async_decrypt_start was null */ + break; + case 0: + ssl->handshake->async_in_progress = 1; + return( ssl_resume_decrypt_pms( ssl, + peer_pms, + peer_pmslen, + peer_pmssize ) ); + case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: + ssl->handshake->async_in_progress = 1; + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + default: + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_decrypt_start", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + + if( ! mbedtls_pk_can_do( private_key, MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + ret = mbedtls_pk_decrypt( private_key, p, len, + peer_pms, peer_pmslen, peer_pmssize, + ssl->conf->f_rng, ssl->conf->p_rng ); + return( ret ); +} + +static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, + const unsigned char *p, + const unsigned char *end, + size_t pms_offset ) +{ + int ret; + unsigned char *pms = ssl->handshake->premaster + pms_offset; + unsigned char ver[2]; + unsigned char fake_pms[48], peer_pms[48]; + unsigned char mask; + size_t i, peer_pmslen; + unsigned int diff; + + /* In case of a failure in decryption, the decryption may write less than + * 2 bytes of output, but we always read the first two bytes. It doesn't + * matter in the end because diff will be nonzero in that case due to + * peer_pmslen being less than 48, and we only care whether diff is 0. + * But do initialize peer_pms for robustness anyway. This also makes + * memory analyzers happy (don't access uninitialized memory, even + * if it's an unsigned char). */ + peer_pms[0] = peer_pms[1] = ~0; + + ret = ssl_decrypt_encrypted_pms( ssl, p, end, + peer_pms, + &peer_pmslen, + sizeof( peer_pms ) ); + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if ( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + return( ret ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + mbedtls_ssl_write_version( ssl->handshake->max_major_ver, - ssl->handshake->max_minor_ver, - ssl->conf->transport, ver ); + ssl->handshake->max_minor_ver, + ssl->conf->transport, ver ); + + /* Avoid data-dependent branches while checking for invalid + * padding, to protect against timing-based Bleichenbacher-type + * attacks. */ + diff = (unsigned int) ret; + diff |= peer_pmslen ^ 48; + diff |= peer_pms[0] ^ ver[0]; + diff |= peer_pms[1] ^ ver[1]; + + /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */ + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif /* * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding * must not cause the connection to end immediately; instead, send a * bad_record_mac later in the handshake. - * Also, avoid data-dependant branches here to protect against - * timing-based variants. + * To protect against timing-based variants of the attack, we must + * not have any branch that depends on whether the decryption was + * successful. In particular, always generate the fake premaster secret, + * regardless of whether it will ultimately influence the output or not. */ ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) ); if( ret != 0 ) + { + /* It's ok to abort on an RNG failure, since this does not reveal + * anything about the RSA decryption. */ return( ret ); - - ret = mbedtls_pk_decrypt( mbedtls_ssl_own_key( ssl ), p, len, - peer_pms, &peer_pmslen, - sizeof( peer_pms ), - ssl->conf->f_rng, ssl->conf->p_rng ); - - diff = (unsigned int) ret; - diff |= peer_pmslen ^ 48; - diff |= peer_pms[0] ^ ver[0]; - diff |= peer_pms[1] ^ ver[1]; + } #if defined(MBEDTLS_SSL_DEBUG_ALL) if( diff != 0 ) @@ -3391,18 +3632,8 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, } ssl->handshake->pmslen = 48; - /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */ - /* MSVC has a warning about unary minus on unsigned, but this is - * well-defined and precisely what we want to do here */ -#if defined(_MSC_VER) -#pragma warning( push ) -#pragma warning( disable : 4146 ) -#endif - mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) ); -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - + /* Set pms to either the true or the fake PMS, without + * data-dependent branches. */ for( i = 0; i < ssl->handshake->pmslen; i++ ) pms[i] = ( mask & fake_pms[i] ) | ( (~mask) & peer_pms[i] ); @@ -3484,7 +3715,21 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) ); - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) && \ + ( defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) ) + if( ( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) && + ( ssl->handshake->async_in_progress != 0 ) ) + { + /* We've already read a record and there is an asynchronous + * operation in progress to decrypt it. So skip reading the + * record. */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "will resume decryption of previously-read record" ) ); + } + else +#endif + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); @@ -3550,7 +3795,8 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); } - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &ssl->handshake->pmslen, @@ -3562,7 +3808,8 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); } - MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z ", &ssl->handshake->ecdh_ctx.z ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || @@ -3596,6 +3843,19 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) { +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if ( ssl->handshake->async_in_progress != 0 ) + { + /* There is an asynchronous operation in progress to + * decrypt the encrypted premaster secret, so skip + * directly to resuming this operation. */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "PSK identity already parsed" ) ); + /* Update p to skip the PSK identity. ssl_parse_encrypted_pms + * won't actually use it, but maintain p anyway for robustness. */ + p += ssl->conf->psk_identity_len + 2; + } + else +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); @@ -3662,7 +3922,8 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); } - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, ciphersuite_info->key_exchange ) ) != 0 ) @@ -3781,21 +4042,10 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) } /* Read the message without adding it to the checksum */ - do { - - if( ( ret = mbedtls_ssl_read_record_layer( ssl ) ) != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); - return( ret ); - } - - ret = mbedtls_ssl_handle_message_type( ssl ); - - } while( MBEDTLS_ERR_SSL_NON_FATAL == ret ); - + ret = mbedtls_ssl_read_record( ssl, 0 /* no checksum update */ ); if( 0 != ret ) { - MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), ret ); + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record" ), ret ); return( ret ); } @@ -3961,7 +4211,7 @@ static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl ) if( ( ret = ssl->conf->f_ticket_write( ssl->conf->p_ticket, ssl->session_negotiate, ssl->out_msg + 10, - ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN, + ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN, &tlen, &lifetime ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_write", ret ); @@ -3984,9 +4234,9 @@ static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl ) */ ssl->handshake->new_session_ticket = 0; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } @@ -4015,10 +4265,10 @@ int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) { - if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) return( ret ); } -#endif +#endif /* MBEDTLS_SSL_PROTO_DTLS */ switch( ssl->state ) { diff --git a/app/mbedtls/library/ssl_ticket.c b/app/mbedtls/library/ssl_ticket.c index 555c7b63bf..8492c19a8c 100644 --- a/app/mbedtls/library/ssl_ticket.c +++ b/app/mbedtls/library/ssl_ticket.c @@ -36,14 +36,10 @@ #endif #include "mbedtls/ssl_ticket.h" +#include "mbedtls/platform_util.h" #include -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * Initialze context */ @@ -83,7 +79,7 @@ static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx, mbedtls_cipher_get_key_bitlen( &key->ctx ), MBEDTLS_ENCRYPT ); - mbedtls_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); return( ret ); } @@ -483,7 +479,7 @@ void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) mbedtls_mutex_free( &ctx->mutex ); #endif - mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); } #endif /* MBEDTLS_SSL_TICKET_C */ diff --git a/app/mbedtls/library/ssl_tls.c b/app/mbedtls/library/ssl_tls.c index 6956b5f31b..b8f35fec5d 100644 --- a/app/mbedtls/library/ssl_tls.c +++ b/app/mbedtls/library/ssl_tls.c @@ -46,6 +46,7 @@ #include "mbedtls/debug.h" #include "mbedtls/ssl.h" #include "mbedtls/ssl_internal.h" +#include "mbedtls/platform_util.h" #include @@ -53,10 +54,8 @@ #include "mbedtls/oid.h" #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl ); +static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ); /* Length of the "epoch" field in the record header */ static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl ) @@ -100,7 +99,101 @@ static int ssl_check_timer( mbedtls_ssl_context *ssl ) return( 0 ); } +static void ssl_update_out_pointers( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ); +static void ssl_update_in_pointers( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ); + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + #if defined(MBEDTLS_SSL_PROTO_DTLS) + +/* Forward declarations for functions related to message buffering. */ +static void ssl_buffering_free( mbedtls_ssl_context *ssl ); +static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl, + uint8_t slot ); +static void ssl_free_buffered_record( mbedtls_ssl_context *ssl ); +static int ssl_load_buffered_message( mbedtls_ssl_context *ssl ); +static int ssl_load_buffered_record( mbedtls_ssl_context *ssl ); +static int ssl_buffer_message( mbedtls_ssl_context *ssl ); +static int ssl_buffer_future_record( mbedtls_ssl_context *ssl ); +static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl ); + +static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl ); +static size_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl ) +{ + size_t mtu = ssl_get_current_mtu( ssl ); + + if( mtu != 0 && mtu < MBEDTLS_SSL_OUT_BUFFER_LEN ) + return( mtu ); + + return( MBEDTLS_SSL_OUT_BUFFER_LEN ); +} + +static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl ) +{ + size_t const bytes_written = ssl->out_left; + size_t const mtu = ssl_get_maximum_datagram_size( ssl ); + + /* Double-check that the write-index hasn't gone + * past what we can transmit in a single datagram. */ + if( bytes_written > mtu ) + { + /* Should never happen... */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( (int) ( mtu - bytes_written ) ); +} + +static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl ) +{ + int ret; + size_t remaining, expansion; + size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl ); + + if( max_len > mfl ) + max_len = mfl; + + /* By the standard (RFC 6066 Sect. 4), the MFL extension + * only limits the maximum record payload size, so in theory + * we would be allowed to pack multiple records of payload size + * MFL into a single datagram. However, this would mean that there's + * no way to explicitly communicate MTU restrictions to the peer. + * + * The following reduction of max_len makes sure that we never + * write datagrams larger than MFL + Record Expansion Overhead. + */ + if( max_len <= ssl->out_left ) + return( 0 ); + + max_len -= ssl->out_left; +#endif + + ret = ssl_get_remaining_space_in_datagram( ssl ); + if( ret < 0 ) + return( ret ); + remaining = (size_t) ret; + + ret = mbedtls_ssl_get_record_expansion( ssl ); + if( ret < 0 ) + return( ret ); + expansion = (size_t) ret; + + if( remaining <= expansion ) + return( 0 ); + + remaining -= expansion; + if( remaining >= max_len ) + remaining = max_len; + + return( (int) remaining ); +} + /* * Double the retransmit timeout value, within the allowed range, * returning -1 if the maximum value has already been reached. @@ -112,6 +205,18 @@ static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max ) return( -1 ); + /* Implement the final paragraph of RFC 6347 section 4.1.1.1 + * in the following way: after the initial transmission and a first + * retransmission, back off to a temporary estimated MTU of 508 bytes. + * This value is guaranteed to be deliverable (if not guaranteed to be + * delivered) of any compliant IPv4 (and IPv6) network, and should work + * on most non-IP stacks too. */ + if( ssl->handshake->retransmit_timeout != ssl->conf->hs_timeout_min ) + { + ssl->handshake->mtu = 508; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "mtu autoreduction to %d bytes", ssl->handshake->mtu ) ); + } + new_timeout = 2 * ssl->handshake->retransmit_timeout; /* Avoid arithmetic overflow and range overflow */ @@ -145,14 +250,24 @@ static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) * } MaxFragmentLength; * and we add 0 -> extension unused */ -static unsigned int mfl_code_to_length[MBEDTLS_SSL_MAX_FRAG_LEN_INVALID] = +static unsigned int ssl_mfl_code_to_length( int mfl ) { - MBEDTLS_SSL_MAX_CONTENT_LEN, /* MBEDTLS_SSL_MAX_FRAG_LEN_NONE */ - 512, /* MBEDTLS_SSL_MAX_FRAG_LEN_512 */ - 1024, /* MBEDTLS_SSL_MAX_FRAG_LEN_1024 */ - 2048, /* MBEDTLS_SSL_MAX_FRAG_LEN_2048 */ - 4096, /* MBEDTLS_SSL_MAX_FRAG_LEN_4096 */ -}; + switch( mfl ) + { + case MBEDTLS_SSL_MAX_FRAG_LEN_NONE: + return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ); + case MBEDTLS_SSL_MAX_FRAG_LEN_512: + return 512; + case MBEDTLS_SSL_MAX_FRAG_LEN_1024: + return 1024; + case MBEDTLS_SSL_MAX_FRAG_LEN_2048: + return 2048; + case MBEDTLS_SSL_MAX_FRAG_LEN_4096: + return 4096; + default: + return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ); + } +} #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ #if defined(MBEDTLS_SSL_CLI_C) @@ -269,8 +384,8 @@ static int ssl3_prf( const unsigned char *secret, size_t slen, mbedtls_md5_free( &md5 ); mbedtls_sha1_free( &sha1 ); - mbedtls_zeroize( padding, sizeof( padding ) ); - mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); + mbedtls_platform_zeroize( padding, sizeof( padding ) ); + mbedtls_platform_zeroize( sha1sum, sizeof( sha1sum ) ); return( ret ); } @@ -367,8 +482,8 @@ static int tls1_prf( const unsigned char *secret, size_t slen, mbedtls_md_free( &md_ctx ); - mbedtls_zeroize( tmp, sizeof( tmp ) ); - mbedtls_zeroize( h_i, sizeof( h_i ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); return( 0 ); } @@ -432,8 +547,8 @@ static int tls_prf_generic( mbedtls_md_type_t md_type, mbedtls_md_free( &md_ctx ); - mbedtls_zeroize( tmp, sizeof( tmp ) ); - mbedtls_zeroize( h_i, sizeof( h_i ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); return( 0 ); } @@ -642,7 +757,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) return( ret ); } - mbedtls_zeroize( handshake->premaster, sizeof(handshake->premaster) ); + mbedtls_platform_zeroize( handshake->premaster, + sizeof(handshake->premaster) ); } else MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); @@ -653,7 +769,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) memcpy( tmp, handshake->randbytes, 64 ); memcpy( handshake->randbytes, tmp + 32, 32 ); memcpy( handshake->randbytes + 32, tmp, 32 ); - mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); /* * SSLv3: @@ -681,7 +797,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 ); MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 ); - mbedtls_zeroize( handshake->randbytes, sizeof( handshake->randbytes ) ); + mbedtls_platform_zeroize( handshake->randbytes, + sizeof( handshake->randbytes ) ); /* * Determine the appropriate key, IV and MAC length. @@ -690,18 +807,32 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) transform->keylen = cipher_info->key_bitlen / 8; if( cipher_info->mode == MBEDTLS_MODE_GCM || - cipher_info->mode == MBEDTLS_MODE_CCM ) + cipher_info->mode == MBEDTLS_MODE_CCM || + cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY ) { + size_t taglen, explicit_ivlen; + transform->maclen = 0; mac_key_len = 0; + /* All modes haves 96-bit IVs; + * GCM and CCM has 4 implicit and 8 explicit bytes + * ChachaPoly has all 12 bytes implicit + */ transform->ivlen = 12; - transform->fixed_ivlen = 4; + if( cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY ) + transform->fixed_ivlen = 12; + else + transform->fixed_ivlen = 4; + + /* All modes have 128-bit tags, except CCM_8 (ciphersuite flag) */ + taglen = transform->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; - /* Minimum length is expicit IV + tag */ - transform->minlen = transform->ivlen - transform->fixed_ivlen - + ( transform->ciphersuite_info->flags & - MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16 ); + + /* Minimum length of encrypted record */ + explicit_ivlen = transform->ivlen - transform->fixed_ivlen; + transform->minlen = explicit_ivlen + taglen; } else { @@ -948,7 +1079,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_CIPHER_MODE_CBC */ - mbedtls_zeroize( keyblk, sizeof( keyblk ) ); + mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) ); #if defined(MBEDTLS_ZLIB_SUPPORT) // Initialize compression @@ -958,11 +1089,11 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) if( ssl->compress_buf == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) ); - ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_BUFFER_LEN ); + ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_COMPRESS_BUFFER_LEN ); if( ssl->compress_buf == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", - MBEDTLS_SSL_BUFFER_LEN ) ); + MBEDTLS_SSL_COMPRESS_BUFFER_LEN ) ); return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); } } @@ -1202,7 +1333,8 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exch *(p++) = (unsigned char)( zlen ); p += zlen; - MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ @@ -1277,7 +1409,7 @@ static void ssl_mac( mbedtls_md_context_t *md_ctx, #if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ ( defined(MBEDTLS_CIPHER_MODE_CBC) && \ - ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) ) + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C)) ) #define SSL_SOME_MODES_USE_MAC #endif @@ -1323,14 +1455,6 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", ssl->out_msg, ssl->out_msglen ); - if( ssl->out_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %u too large, maximum %d", - (unsigned) ssl->out_msglen, - MBEDTLS_SSL_MAX_CONTENT_LEN ) ); - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - } - /* * Add MAC before if needed */ @@ -1420,17 +1544,26 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) } else #endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ -#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) +#if defined(MBEDTLS_GCM_C) || \ + defined(MBEDTLS_CCM_C) || \ + defined(MBEDTLS_CHACHAPOLY_C) if( mode == MBEDTLS_MODE_GCM || - mode == MBEDTLS_MODE_CCM ) + mode == MBEDTLS_MODE_CCM || + mode == MBEDTLS_MODE_CHACHAPOLY ) { int ret; size_t enc_msglen, olen; unsigned char *enc_msg; unsigned char add_data[13]; - unsigned char taglen = ssl->transform_out->ciphersuite_info->flags & + unsigned char iv[12]; + mbedtls_ssl_transform *transform = ssl->transform_out; + unsigned char taglen = transform->ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + size_t explicit_ivlen = transform->ivlen - transform->fixed_ivlen; + /* + * Prepare additional authenticated data + */ memcpy( add_data, ssl->out_ctr, 8 ); add_data[8] = ssl->out_msgtype; mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, @@ -1438,44 +1571,57 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF; add_data[12] = ssl->out_msglen & 0xFF; - MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", - add_data, 13 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data for AEAD", add_data, 13 ); /* * Generate IV */ - if( ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen != 8 ) + if( transform->ivlen == 12 && transform->fixed_ivlen == 4 ) + { + /* GCM and CCM: fixed || explicit (=seqnum) */ + memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); + memcpy( iv + transform->fixed_ivlen, ssl->out_ctr, 8 ); + memcpy( ssl->out_iv, ssl->out_ctr, 8 ); + + } + else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 ) + { + /* ChachaPoly: fixed XOR sequence number */ + unsigned char i; + + memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); + + for( i = 0; i < 8; i++ ) + iv[i+4] ^= ssl->out_ctr[i]; + } + else { /* Reminder if we ever add an AEAD mode with a different size */ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - memcpy( ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, - ssl->out_ctr, 8 ); - memcpy( ssl->out_iv, ssl->out_ctr, 8 ); - - MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->out_iv, - ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)", + iv, transform->ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (transmitted)", + ssl->out_iv, explicit_ivlen ); /* - * Fix pointer positions and message length with added IV + * Fix message length with added IV */ enc_msg = ssl->out_msg; enc_msglen = ssl->out_msglen; - ssl->out_msglen += ssl->transform_out->ivlen - - ssl->transform_out->fixed_ivlen; + ssl->out_msglen += explicit_ivlen; MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " - "including %d bytes of padding", - ssl->out_msglen, 0 ) ); + "including 0 bytes of padding", + ssl->out_msglen ) ); /* * Encrypt and authenticate */ - if( ( ret = mbedtls_cipher_auth_encrypt( &ssl->transform_out->cipher_ctx_enc, - ssl->transform_out->iv_enc, - ssl->transform_out->ivlen, + if( ( ret = mbedtls_cipher_auth_encrypt( &transform->cipher_ctx_enc, + iv, transform->ivlen, add_data, 13, enc_msg, enc_msglen, enc_msg, &olen, @@ -1499,7 +1645,7 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) else #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ #if defined(MBEDTLS_CIPHER_MODE_CBC) && \ - ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) ) if( mode == MBEDTLS_MODE_CBC ) { int ret; @@ -1619,7 +1765,7 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) } else #endif /* MBEDTLS_CIPHER_MODE_CBC && - ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C || MBEDTLS_ARIA_C ) */ { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); @@ -1639,7 +1785,6 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) { - size_t i; mbedtls_cipher_mode_t mode; int auth_done = 0; #if defined(SSL_SOME_MODES_USE_MAC) @@ -1689,20 +1834,27 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) } else #endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ -#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) +#if defined(MBEDTLS_GCM_C) || \ + defined(MBEDTLS_CCM_C) || \ + defined(MBEDTLS_CHACHAPOLY_C) if( mode == MBEDTLS_MODE_GCM || - mode == MBEDTLS_MODE_CCM ) + mode == MBEDTLS_MODE_CCM || + mode == MBEDTLS_MODE_CHACHAPOLY ) { int ret; size_t dec_msglen, olen; unsigned char *dec_msg; unsigned char *dec_msg_result; unsigned char add_data[13]; - unsigned char taglen = ssl->transform_in->ciphersuite_info->flags & + unsigned char iv[12]; + mbedtls_ssl_transform *transform = ssl->transform_in; + unsigned char taglen = transform->ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; - size_t explicit_iv_len = ssl->transform_in->ivlen - - ssl->transform_in->fixed_ivlen; + size_t explicit_iv_len = transform->ivlen - transform->fixed_ivlen; + /* + * Compute and update sizes + */ if( ssl->in_msglen < explicit_iv_len + taglen ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) " @@ -1716,6 +1868,9 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) dec_msg_result = ssl->in_msg; ssl->in_msglen = dec_msglen; + /* + * Prepare additional authenticated data + */ memcpy( add_data, ssl->in_ctr, 8 ); add_data[8] = ssl->in_msgtype; mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, @@ -1723,23 +1878,43 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF; add_data[12] = ssl->in_msglen & 0xFF; - MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", - add_data, 13 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data for AEAD", add_data, 13 ); + + /* + * Prepare IV + */ + if( transform->ivlen == 12 && transform->fixed_ivlen == 4 ) + { + /* GCM and CCM: fixed || explicit (transmitted) */ + memcpy( iv, transform->iv_dec, transform->fixed_ivlen ); + memcpy( iv + transform->fixed_ivlen, ssl->in_iv, 8 ); + + } + else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 ) + { + /* ChachaPoly: fixed XOR sequence number */ + unsigned char i; + + memcpy( iv, transform->iv_dec, transform->fixed_ivlen ); - memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen, - ssl->in_iv, - ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen ); + for( i = 0; i < 8; i++ ) + iv[i+4] ^= ssl->in_ctr[i]; + } + else + { + /* Reminder if we ever add an AEAD mode with a different size */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } - MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec, - ssl->transform_in->ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", iv, transform->ivlen ); MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, taglen ); /* * Decrypt and authenticate */ if( ( ret = mbedtls_cipher_auth_decrypt( &ssl->transform_in->cipher_ctx_dec, - ssl->transform_in->iv_dec, - ssl->transform_in->ivlen, + iv, transform->ivlen, add_data, 13, dec_msg, dec_msglen, dec_msg_result, &olen, @@ -1763,7 +1938,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) else #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ #if defined(MBEDTLS_CIPHER_MODE_CBC) && \ - ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) ) if( mode == MBEDTLS_MODE_CBC ) { /* @@ -1857,6 +2032,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) */ if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) { + unsigned char i; dec_msglen -= ssl->transform_in->ivlen; ssl->in_msglen -= ssl->transform_in->ivlen; @@ -1931,19 +2107,20 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) */ size_t pad_count = 0, real_count = 1; size_t padding_idx = ssl->in_msglen - padlen; + size_t i; /* * Padding is guaranteed to be incorrect if: * 1. padlen > ssl->in_msglen * - * 2. padding_idx > MBEDTLS_SSL_MAX_CONTENT_LEN + + * 2. padding_idx > MBEDTLS_SSL_IN_CONTENT_LEN + * ssl->transform_in->maclen * * In both cases we reset padding_idx to a safe value (0) to * prevent out-of-buffer reads. */ correct &= ( padlen <= ssl->in_msglen ); - correct &= ( padding_idx <= MBEDTLS_SSL_MAX_CONTENT_LEN + + correct &= ( padding_idx <= MBEDTLS_SSL_IN_CONTENT_LEN + ssl->transform_in->maclen ); padding_idx *= correct; @@ -1975,7 +2152,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) } else #endif /* MBEDTLS_CIPHER_MODE_CBC && - ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C || MBEDTLS_ARIA_C ) */ { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); @@ -2183,6 +2360,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) else #endif { + unsigned char i; for( i = 8; i > ssl_ep_len( ssl ); i-- ) if( ++ssl->in_ctr[i - 1] != 0 ) break; @@ -2232,7 +2410,7 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl ) ssl->transform_out->ctx_deflate.next_in = msg_pre; ssl->transform_out->ctx_deflate.avail_in = len_pre; ssl->transform_out->ctx_deflate.next_out = msg_post; - ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_BUFFER_LEN - bytes_written; + ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_OUT_BUFFER_LEN - bytes_written; ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH ); if( ret != Z_OK ) @@ -2241,7 +2419,7 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); } - ssl->out_msglen = MBEDTLS_SSL_BUFFER_LEN - + ssl->out_msglen = MBEDTLS_SSL_OUT_BUFFER_LEN - ssl->transform_out->ctx_deflate.avail_out - bytes_written; MBEDTLS_SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", @@ -2279,7 +2457,7 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) ssl->transform_in->ctx_inflate.next_in = msg_pre; ssl->transform_in->ctx_inflate.avail_in = len_pre; ssl->transform_in->ctx_inflate.next_out = msg_post; - ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_BUFFER_LEN - + ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_IN_BUFFER_LEN - header_bytes; ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH ); @@ -2289,7 +2467,7 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); } - ssl->in_msglen = MBEDTLS_SSL_BUFFER_LEN - + ssl->in_msglen = MBEDTLS_SSL_IN_BUFFER_LEN - ssl->transform_in->ctx_inflate.avail_out - header_bytes; MBEDTLS_SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", @@ -2364,7 +2542,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } - if( nb_want > MBEDTLS_SSL_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) ) + if( nb_want > MBEDTLS_SSL_IN_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); @@ -2428,7 +2606,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) } /* - * A record can't be split accross datagrams. If we need to read but + * A record can't be split across datagrams. If we need to read but * are not at the beginning of a new record, the caller did something * wrong. */ @@ -2444,10 +2622,13 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) * that will end up being dropped. */ if( ssl_check_timer( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "timer has expired" ) ); ret = MBEDTLS_ERR_SSL_TIMEOUT; + } else { - len = MBEDTLS_SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf ); + len = MBEDTLS_SSL_IN_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf ); if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) timeout = ssl->handshake->retransmit_timeout; @@ -2569,7 +2750,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) { int ret; - unsigned char *buf, i; + unsigned char *buf; MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) ); @@ -2592,8 +2773,7 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d", mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) ); - buf = ssl->out_hdr + mbedtls_ssl_hdr_len( ssl ) + - ssl->out_msglen - ssl->out_left; + buf = ssl->out_hdr - ssl->out_left; ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left ); MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret ); @@ -2612,16 +2792,17 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) ssl->out_left -= ret; } - for( i = 8; i > ssl_ep_len( ssl ); i-- ) - if( ++ssl->out_ctr[i - 1] != 0 ) - break; - - /* The loop goes to its end iff the counter is wrapping */ - if( i == ssl_ep_len( ssl ) ) +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) ); - return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + ssl->out_hdr = ssl->out_buf; + } + else +#endif + { + ssl->out_hdr = ssl->out_buf + 8; } + ssl_update_out_pointers( ssl, ssl->transform_out ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); @@ -2638,6 +2819,9 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) static int ssl_flight_append( mbedtls_ssl_context *ssl ) { mbedtls_ssl_flight_item *msg; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_flight_append" ) ); + MBEDTLS_SSL_DEBUG_BUF( 4, "message appended to flight", + ssl->out_msg, ssl->out_msglen ); /* Allocate space for current message */ if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL ) @@ -2671,6 +2855,7 @@ static int ssl_flight_append( mbedtls_ssl_context *ssl ) cur->next = msg; } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_flight_append" ) ); return( 0 ); } @@ -2719,19 +2904,12 @@ static void ssl_swap_epochs( mbedtls_ssl_context *ssl ) ssl->handshake->alt_transform_out = tmp_transform; /* Swap epoch + sequence_number */ - memcpy( tmp_out_ctr, ssl->out_ctr, 8 ); - memcpy( ssl->out_ctr, ssl->handshake->alt_out_ctr, 8 ); + memcpy( tmp_out_ctr, ssl->cur_out_ctr, 8 ); + memcpy( ssl->cur_out_ctr, ssl->handshake->alt_out_ctr, 8 ); memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 ); /* Adjust to the newly activated transform */ - if( ssl->transform_out != NULL && - ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) - { - ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen - - ssl->transform_out->fixed_ivlen; - } - else - ssl->out_msg = ssl->out_iv; + ssl_update_out_pointers( ssl, ssl->transform_out ); #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) if( mbedtls_ssl_hw_record_activate != NULL ) @@ -2747,20 +2925,38 @@ static void ssl_swap_epochs( mbedtls_ssl_context *ssl ) /* * Retransmit the current flight of messages. + */ +int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) ); + + ret = mbedtls_ssl_flight_transmit( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) ); + + return( ret ); +} + +/* + * Transmit or retransmit the current flight of messages. * * Need to remember the current message in case flush_output returns * WANT_WRITE, causing us to exit this function and come back later. * This function must be called until state is no longer SENDING. */ -int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) +int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ) { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) ); + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) ); if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise resending" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise flight transmission" ) ); ssl->handshake->cur_msg = ssl->handshake->flight; + ssl->handshake->cur_msg_p = ssl->handshake->flight->p + 12; ssl_swap_epochs( ssl ); ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING; @@ -2768,33 +2964,129 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) while( ssl->handshake->cur_msg != NULL ) { - int ret; - mbedtls_ssl_flight_item *cur = ssl->handshake->cur_msg; + size_t max_frag_len; + const mbedtls_ssl_flight_item * const cur = ssl->handshake->cur_msg; + + int const is_finished = + ( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && + cur->p[0] == MBEDTLS_SSL_HS_FINISHED ); + + uint8_t const force_flush = ssl->disable_datagram_packing == 1 ? + SSL_FORCE_FLUSH : SSL_DONT_FORCE_FLUSH; /* Swap epochs before sending Finished: we can't do it after * sending ChangeCipherSpec, in case write returns WANT_READ. * Must be done before copying, may change out_msg pointer */ - if( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && - cur->p[0] == MBEDTLS_SSL_HS_FINISHED ) + if( is_finished && ssl->handshake->cur_msg_p == ( cur->p + 12 ) ) { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "swap epochs to send finished message" ) ); ssl_swap_epochs( ssl ); } - memcpy( ssl->out_msg, cur->p, cur->len ); - ssl->out_msglen = cur->len; - ssl->out_msgtype = cur->type; + ret = ssl_get_remaining_payload_in_datagram( ssl ); + if( ret < 0 ) + return( ret ); + max_frag_len = (size_t) ret; + + /* CCS is copied as is, while HS messages may need fragmentation */ + if( cur->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + if( max_frag_len == 0 ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + continue; + } + + memcpy( ssl->out_msg, cur->p, cur->len ); + ssl->out_msglen = cur->len; + ssl->out_msgtype = cur->type; + + /* Update position inside current message */ + ssl->handshake->cur_msg_p += cur->len; + } + else + { + const unsigned char * const p = ssl->handshake->cur_msg_p; + const size_t hs_len = cur->len - 12; + const size_t frag_off = p - ( cur->p + 12 ); + const size_t rem_len = hs_len - frag_off; + size_t cur_hs_frag_len, max_hs_frag_len; + + if( ( max_frag_len < 12 ) || ( max_frag_len == 12 && hs_len != 0 ) ) + { + if( is_finished ) + ssl_swap_epochs( ssl ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + continue; + } + max_hs_frag_len = max_frag_len - 12; + + cur_hs_frag_len = rem_len > max_hs_frag_len ? + max_hs_frag_len : rem_len; + + if( frag_off == 0 && cur_hs_frag_len != hs_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "fragmenting handshake message (%u > %u)", + (unsigned) cur_hs_frag_len, + (unsigned) max_hs_frag_len ) ); + } + + /* Messages are stored with handshake headers as if not fragmented, + * copy beginning of headers then fill fragmentation fields. + * Handshake headers: type(1) len(3) seq(2) f_off(3) f_len(3) */ + memcpy( ssl->out_msg, cur->p, 6 ); + + ssl->out_msg[6] = ( ( frag_off >> 16 ) & 0xff ); + ssl->out_msg[7] = ( ( frag_off >> 8 ) & 0xff ); + ssl->out_msg[8] = ( ( frag_off ) & 0xff ); - ssl->handshake->cur_msg = cur->next; + ssl->out_msg[ 9] = ( ( cur_hs_frag_len >> 16 ) & 0xff ); + ssl->out_msg[10] = ( ( cur_hs_frag_len >> 8 ) & 0xff ); + ssl->out_msg[11] = ( ( cur_hs_frag_len ) & 0xff ); - MBEDTLS_SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "handshake header", ssl->out_msg, 12 ); + + /* Copy the handshake message content and set records fields */ + memcpy( ssl->out_msg + 12, p, cur_hs_frag_len ); + ssl->out_msglen = cur_hs_frag_len + 12; + ssl->out_msgtype = cur->type; + + /* Update position inside current message */ + ssl->handshake->cur_msg_p += cur_hs_frag_len; + } + + /* If done with the current message move to the next one if any */ + if( ssl->handshake->cur_msg_p >= cur->p + cur->len ) + { + if( cur->next != NULL ) + { + ssl->handshake->cur_msg = cur->next; + ssl->handshake->cur_msg_p = cur->next->p + 12; + } + else + { + ssl->handshake->cur_msg = NULL; + ssl->handshake->cur_msg_p = NULL; + } + } - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + /* Actually send the message out */ + if( ( ret = mbedtls_ssl_write_record( ssl, force_flush ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); return( ret ); } } + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + /* Update state and set timer */ if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; else @@ -2803,7 +3095,7 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); } - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_flight_transmit" ) ); return( 0 ); } @@ -2821,6 +3113,12 @@ void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ) /* The next incoming flight will start with this msg_seq */ ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq; + /* We don't want to remember CCS's across flight boundaries. */ + ssl->handshake->buffering.seen_ccs = 0; + + /* Clear future message buffering structure. */ + ssl_buffering_free( ssl ); + /* Cancel timer */ ssl_set_timer( ssl, 0 ); @@ -2852,43 +3150,102 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_SSL_PROTO_DTLS */ /* - * Record layer functions + * Handshake layer functions */ /* - * Write current record. - * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg. + * Write (DTLS: or queue) current handshake (including CCS) message. + * + * - fill in handshake headers + * - update handshake checksum + * - DTLS: save message for resending + * - then pass to the record layer + * + * DTLS: except for HelloRequest, messages are only queued, and will only be + * actually sent when calling flight_transmit() or resend(). + * + * Inputs: + * - ssl->out_msglen: 4 + actual handshake message len + * (4 is the size of handshake headers for TLS) + * - ssl->out_msg[0]: the handshake type (ClientHello, ServerHello, etc) + * - ssl->out_msg + 4: the handshake message body + * + * Outputs, ie state before passing to flight_append() or write_record(): + * - ssl->out_msglen: the length of the record contents + * (including handshake headers but excluding record headers) + * - ssl->out_msg: the record contents (handshake headers + content) */ -int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) +int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) { - int ret, done = 0, out_msg_type; - size_t len = ssl->out_msglen; + int ret; + const size_t hs_len = ssl->out_msglen - 4; + const unsigned char hs_type = ssl->out_msg[0]; - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write handshake message" ) ); + + /* + * Sanity checks + */ + if( ssl->out_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->out_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + /* In SSLv3, the client might send a NoCertificate alert. */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C) + if( ! ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->out_msgtype == MBEDTLS_SSL_MSG_ALERT && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) ) +#endif /* MBEDTLS_SSL_PROTO_SSL3 && MBEDTLS_SSL_SRV_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + + /* Whenever we send anything different from a + * HelloRequest we should be in a handshake - double check. */ + if( ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) && + ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && ssl->handshake != NULL && ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) { - ; /* Skip special handshake treatment when resending */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - else #endif - if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) - { - out_msg_type = ssl->out_msg[0]; - if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST && - ssl->handshake == NULL ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); - } + /* Double-check that we did not exceed the bounds + * of the outgoing record buffer. + * This should never fail as the various message + * writing functions must obey the bounds of the + * outgoing record buffer, but better be safe. + * + * Note: We deliberately do not check for the MTU or MFL here. + */ + if( ssl->out_msglen > MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record too large: " + "size %u, maximum %u", + (unsigned) ssl->out_msglen, + (unsigned) MBEDTLS_SSL_OUT_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } - ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 ); - ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 ); - ssl->out_msg[3] = (unsigned char)( ( len - 4 ) ); + /* + * Fill handshake headers + */ + if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + ssl->out_msg[1] = (unsigned char)( hs_len >> 16 ); + ssl->out_msg[2] = (unsigned char)( hs_len >> 8 ); + ssl->out_msg[3] = (unsigned char)( hs_len ); /* * DTLS has additional fields in the Handshake layer, @@ -2901,21 +3258,20 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { /* Make room for the additional DTLS fields */ - if( MBEDTLS_SSL_MAX_CONTENT_LEN - ssl->out_msglen < 8 ) + if( MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen < 8 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS handshake message too large: " "size %u, maximum %u", - (unsigned) ( ssl->in_hslen - 4 ), - (unsigned) ( MBEDTLS_SSL_MAX_CONTENT_LEN - 12 ) ) ); + (unsigned) ( hs_len ), + (unsigned) ( MBEDTLS_SSL_OUT_CONTENT_LEN - 12 ) ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } - memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 ); + memmove( ssl->out_msg + 12, ssl->out_msg + 4, hs_len ); ssl->out_msglen += 8; - len += 8; /* Write message_seq and update it, except for HelloRequest */ - if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) { ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF; ssl->out_msg[5] = ( ssl->handshake->out_msg_seq ) & 0xFF; @@ -2927,23 +3283,23 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) ssl->out_msg[5] = 0; } - /* We don't fragment, so frag_offset = 0 and frag_len = len */ + /* Handshake hashes are computed without fragmentation, + * so set frag_offset = 0 and frag_len = hs_len for now */ memset( ssl->out_msg + 6, 0x00, 3 ); memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 ); } #endif /* MBEDTLS_SSL_PROTO_DTLS */ - if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) - ssl->handshake->update_checksum( ssl, ssl->out_msg, len ); + /* Update running hashes of handshake messages seen */ + if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + ssl->handshake->update_checksum( ssl, ssl->out_msg, ssl->out_msglen ); } - /* Save handshake and CCS messages for resending */ + /* Either send now, or just save to be sent (and resent) later */ #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && - ssl->handshake != NULL && - ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING && - ( ssl->out_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC || - ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) ) + ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) ) { if( ( ret = ssl_flight_append( ssl ) ) != 0 ) { @@ -2951,7 +3307,40 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) return( ret ); } } + else #endif + { + if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write handshake message" ) ); + + return( 0 ); +} + +/* + * Record layer functions + */ + +/* + * Write current record. + * + * Uses: + * - ssl->out_msgtype: type of the message (AppData, Handshake, Alert, CCS) + * - ssl->out_msglen: length of the record content (excl headers) + * - ssl->out_msg: record content + */ +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) +{ + int ret, done = 0; + size_t len = ssl->out_msglen; + uint8_t flush = force_flush; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) ); #if defined(MBEDTLS_ZLIB_SUPPORT) if( ssl->transform_out != NULL && @@ -2985,10 +3374,14 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ if( !done ) { + unsigned i; + size_t protected_record_size; + ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, ssl->conf->transport, ssl->out_hdr + 1 ); + memcpy( ssl->out_ctr, ssl->cur_out_ctr, 8 ); ssl->out_len[0] = (unsigned char)( len >> 8 ); ssl->out_len[1] = (unsigned char)( len ); @@ -3005,21 +3398,79 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) ssl->out_len[1] = (unsigned char)( len ); } - ssl->out_left = mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen; + protected_record_size = len + mbedtls_ssl_hdr_len( ssl ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* In case of DTLS, double-check that we don't exceed + * the remaining space in the datagram. */ + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ret = ssl_get_remaining_space_in_datagram( ssl ); + if( ret < 0 ) + return( ret ); + + if( protected_record_size > (size_t) ret ) + { + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, " - "version = [%d:%d], msglen = %d", - ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2], - ( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) ); + "version = [%d:%d], msglen = %d", + ssl->out_hdr[0], ssl->out_hdr[1], + ssl->out_hdr[2], len ) ); MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network", - ssl->out_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen ); - } + ssl->out_hdr, protected_record_size ); - if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); - return( ret ); + ssl->out_left += protected_record_size; + ssl->out_hdr += protected_record_size; + ssl_update_out_pointers( ssl, ssl->transform_out ); + + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->cur_out_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == ssl_ep_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + flush == SSL_DONT_FORCE_FLUSH ) + { + size_t remaining; + ret = ssl_get_remaining_payload_in_datagram( ssl ); + if( ret < 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_remaining_payload_in_datagram", + ret ); + return( ret ); + } + + remaining = (size_t) ret; + if( remaining == 0 ) + { + flush = SSL_FORCE_FLUSH; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Still %u bytes available in current datagram", (unsigned) remaining ) ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( ( flush == SSL_FORCE_FLUSH ) && + ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); } MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write record" ) ); @@ -3028,6 +3479,52 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) } #if defined(MBEDTLS_SSL_PROTO_DTLS) + +static int ssl_hs_is_proper_fragment( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_msglen < ssl->in_hslen || + memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 || + memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 ) + { + return( 1 ); + } + return( 0 ); +} + +static uint32_t ssl_get_hs_frag_len( mbedtls_ssl_context const *ssl ) +{ + return( ( ssl->in_msg[9] << 16 ) | + ( ssl->in_msg[10] << 8 ) | + ssl->in_msg[11] ); +} + +static uint32_t ssl_get_hs_frag_off( mbedtls_ssl_context const *ssl ) +{ + return( ( ssl->in_msg[6] << 16 ) | + ( ssl->in_msg[7] << 8 ) | + ssl->in_msg[8] ); +} + +static int ssl_check_hs_header( mbedtls_ssl_context const *ssl ) +{ + uint32_t msg_len, frag_off, frag_len; + + msg_len = ssl_get_hs_total_len( ssl ); + frag_off = ssl_get_hs_frag_off( ssl ); + frag_len = ssl_get_hs_frag_len( ssl ); + + if( frag_off > msg_len ) + return( -1 ); + + if( frag_len > msg_len - frag_off ) + return( -1 ); + + if( frag_len + 12 > ssl->in_msglen ) + return( -1 ); + + return( 0 ); +} + /* * Mark bits in bitmask (used for DTLS HS reassembly) */ @@ -3089,162 +3586,29 @@ static int ssl_bitmask_check( unsigned char *mask, size_t len ) return( 0 ); } -/* - * Reassemble fragmented DTLS handshake messages. - * - * Use a temporary buffer for reassembly, divided in two parts: - * - the first holds the reassembled message (including handshake header), - * - the second holds a bitmask indicating which parts of the message - * (excluding headers) have been received so far. - */ -static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl ) +/* msg_len does not include the handshake header */ +static size_t ssl_get_reassembly_buffer_size( size_t msg_len, + unsigned add_bitmap ) { - unsigned char *msg, *bitmask; - size_t frag_len, frag_off; - size_t msg_len = ssl->in_hslen - 12; /* Without headers */ + size_t alloc_len; - if( ssl->handshake == NULL ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) ); - return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); - } - - /* - * For first fragment, check size and allocate buffer - */ - if( ssl->handshake->hs_msg == NULL ) - { - size_t alloc_len; - - MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d", - msg_len ) ); - - if( ssl->in_hslen > MBEDTLS_SSL_MAX_CONTENT_LEN ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too large" ) ); - return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); - } - - /* The bitmask needs one bit per byte of message excluding header */ - alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 ); - - ssl->handshake->hs_msg = mbedtls_calloc( 1, alloc_len ); - if( ssl->handshake->hs_msg == NULL ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", alloc_len ) ); - return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); - } - - /* Prepare final header: copy msg_type, length and message_seq, - * then add standardised fragment_offset and fragment_length */ - memcpy( ssl->handshake->hs_msg, ssl->in_msg, 6 ); - memset( ssl->handshake->hs_msg + 6, 0, 3 ); - memcpy( ssl->handshake->hs_msg + 9, - ssl->handshake->hs_msg + 1, 3 ); - } - else - { - /* Make sure msg_type and length are consistent */ - if( memcmp( ssl->handshake->hs_msg, ssl->in_msg, 4 ) != 0 ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment header mismatch" ) ); - return( MBEDTLS_ERR_SSL_INVALID_RECORD ); - } - } - - msg = ssl->handshake->hs_msg + 12; - bitmask = msg + msg_len; - - /* - * Check and copy current fragment - */ - frag_off = ( ssl->in_msg[6] << 16 ) | - ( ssl->in_msg[7] << 8 ) | - ssl->in_msg[8]; - frag_len = ( ssl->in_msg[9] << 16 ) | - ( ssl->in_msg[10] << 8 ) | - ssl->in_msg[11]; - - if( frag_off + frag_len > msg_len ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment offset/len: %d + %d > %d", - frag_off, frag_len, msg_len ) ); - return( MBEDTLS_ERR_SSL_INVALID_RECORD ); - } - - if( frag_len + 12 > ssl->in_msglen ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment length: %d + 12 > %d", - frag_len, ssl->in_msglen ) ); - return( MBEDTLS_ERR_SSL_INVALID_RECORD ); - } - - MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d", - frag_off, frag_len ) ); - - memcpy( msg + frag_off, ssl->in_msg + 12, frag_len ); - ssl_bitmask_set( bitmask, frag_off, frag_len ); - - /* - * Do we have the complete message by now? - * If yes, finalize it, else ask to read the next record. - */ - if( ssl_bitmask_check( bitmask, msg_len ) != 0 ) - { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "message is not complete yet" ) ); - return( MBEDTLS_ERR_SSL_WANT_READ ); - } - - MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake message completed" ) ); - - if( frag_len + 12 < ssl->in_msglen ) - { - /* - * We'got more handshake messages in the same record. - * This case is not handled now because no know implementation does - * that and it's hard to test, so we prefer to fail cleanly for now. - */ - MBEDTLS_SSL_DEBUG_MSG( 1, ( "last fragment not alone in its record" ) ); - return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); - } - - if( ssl->in_left > ssl->next_record_offset ) - { - /* - * We've got more data in the buffer after the current record, - * that we don't want to overwrite. Move it before writing the - * reassembled message, and adjust in_left and next_record_offset. - */ - unsigned char *cur_remain = ssl->in_hdr + ssl->next_record_offset; - unsigned char *new_remain = ssl->in_msg + ssl->in_hslen; - size_t remain_len = ssl->in_left - ssl->next_record_offset; - - /* First compute and check new lengths */ - ssl->next_record_offset = new_remain - ssl->in_hdr; - ssl->in_left = ssl->next_record_offset + remain_len; - - if( ssl->in_left > MBEDTLS_SSL_BUFFER_LEN - - (size_t)( ssl->in_hdr - ssl->in_buf ) ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "reassembled message too large for buffer" ) ); - return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); - } - - memmove( new_remain, cur_remain, remain_len ); - } + alloc_len = 12; /* Handshake header */ + alloc_len += msg_len; /* Content buffer */ - memcpy( ssl->in_msg, ssl->handshake->hs_msg, ssl->in_hslen ); + if( add_bitmap ) + alloc_len += msg_len / 8 + ( msg_len % 8 != 0 ); /* Bitmap */ - mbedtls_zeroize( ssl->handshake->hs_msg, ssl->in_hslen ); - mbedtls_free( ssl->handshake->hs_msg ); - ssl->handshake->hs_msg = NULL; + return( alloc_len ); +} - MBEDTLS_SSL_DEBUG_BUF( 3, "reassembled handshake message", - ssl->in_msg, ssl->in_hslen ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ - return( 0 ); +static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ) +{ + return( ( ssl->in_msg[1] << 16 ) | + ( ssl->in_msg[2] << 8 ) | + ssl->in_msg[3] ); } -#endif /* MBEDTLS_SSL_PROTO_DTLS */ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) { @@ -3255,10 +3619,7 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_INVALID_RECORD ); } - ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + ( - ( ssl->in_msg[1] << 16 ) | - ( ssl->in_msg[2] << 8 ) | - ssl->in_msg[3] ); + ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + ssl_get_hs_total_len( ssl ); MBEDTLS_SSL_DEBUG_MSG( 3, ( "handshake message: msglen =" " %d, type = %d, hslen = %d", @@ -3270,10 +3631,26 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) int ret; unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5]; - /* ssl->handshake is NULL when receiving ClientHello for renego */ + if( ssl_check_hs_header( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid handshake header" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + if( ssl->handshake != NULL && - recv_msg_seq != ssl->handshake->in_msg_seq ) + ( ( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + recv_msg_seq != ssl->handshake->in_msg_seq ) || + ( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) ) ) { + if( recv_msg_seq > ssl->handshake->in_msg_seq ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received future handshake message of sequence number %u (next %u)", + recv_msg_seq, + ssl->handshake->in_msg_seq ) ); + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); + } + /* Retransmit only on last message from previous flight, to avoid * too many retransmissions. * Besides, No sane server ever retransmits HelloVerifyRequest */ @@ -3299,24 +3676,18 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) ssl->handshake->in_msg_seq ) ); } - return( MBEDTLS_ERR_SSL_WANT_READ ); + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); } /* Wait until message completion to increment in_msg_seq */ - /* Reassemble if current message is fragmented or reassembly is - * already in progress */ - if( ssl->in_msglen < ssl->in_hslen || - memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 || - memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 || - ( ssl->handshake != NULL && ssl->handshake->hs_msg != NULL ) ) + /* Message reassembly is handled alongside buffering of future + * messages; the commonality is that both handshake fragments and + * future messages cannot be forwarded immediately to the + * handshake logic layer. */ + if( ssl_hs_is_proper_fragment( ssl ) == 1 ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) ); - - if( ( ret = ssl_reassemble_dtls_handshake( ssl ) ) != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "ssl_reassemble_dtls_handshake", ret ); - return( ret ); - } + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); } } else @@ -3333,9 +3704,9 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ) { + mbedtls_ssl_handshake_params * const hs = ssl->handshake; - if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && - ssl->handshake != NULL ) + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && hs != NULL ) { ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); } @@ -3345,7 +3716,29 @@ void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && ssl->handshake != NULL ) { - ssl->handshake->in_msg_seq++; + unsigned offset; + mbedtls_ssl_hs_buffer *hs_buf; + + /* Increment handshake sequence number */ + hs->in_msg_seq++; + + /* + * Clear up handshake buffering and reassembly structure. + */ + + /* Free first entry */ + ssl_buffering_free_slot( ssl, 0 ); + + /* Shift all other entries */ + for( offset = 0, hs_buf = &hs->buffering.hs[0]; + offset + 1 < MBEDTLS_SSL_MAX_BUFFERED_HS; + offset++, hs_buf++ ) + { + *hs_buf = *(hs_buf + 1); + } + + /* Create a fresh last entry */ + memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) ); } #endif } @@ -3598,7 +3991,7 @@ static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl ) ssl->conf->p_cookie, ssl->cli_id, ssl->cli_id_len, ssl->in_buf, ssl->in_left, - ssl->out_buf, MBEDTLS_SSL_MAX_CONTENT_LEN, &len ); + ssl->out_buf, MBEDTLS_SSL_OUT_CONTENT_LEN, &len ); MBEDTLS_SSL_DEBUG_RET( 2, "ssl_check_dtls_clihlo_cookie", ret ); @@ -3695,88 +4088,30 @@ static int ssl_parse_record_header( mbedtls_ssl_context *ssl ) } /* Check length against the size of our buffer */ - if( ssl->in_msglen > MBEDTLS_SSL_BUFFER_LEN + if( ssl->in_msglen > MBEDTLS_SSL_IN_BUFFER_LEN - (size_t)( ssl->in_msg - ssl->in_buf ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); return( MBEDTLS_ERR_SSL_INVALID_RECORD ); } - /* Check length against bounds of the current transform and version */ - if( ssl->transform_in == NULL ) - { - if( ssl->in_msglen < 1 || - ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); - return( MBEDTLS_ERR_SSL_INVALID_RECORD ); - } - } - else - { - if( ssl->in_msglen < ssl->transform_in->minlen ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); - return( MBEDTLS_ERR_SSL_INVALID_RECORD ); - } - -#if defined(MBEDTLS_SSL_PROTO_SSL3) - if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && - ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_MAX_CONTENT_LEN ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); - return( MBEDTLS_ERR_SSL_INVALID_RECORD ); - } -#endif -#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ - defined(MBEDTLS_SSL_PROTO_TLS1_2) - /* - * TLS encrypted messages can have up to 256 bytes of padding - */ - if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 && - ssl->in_msglen > ssl->transform_in->minlen + - MBEDTLS_SSL_MAX_CONTENT_LEN + 256 ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); - return( MBEDTLS_ERR_SSL_INVALID_RECORD ); - } -#endif - } - /* - * DTLS-related tests done last, because most of them may result in - * silently dropping the record (but not the whole datagram), and we only - * want to consider that after ensuring that the "basic" fields (type, - * version, length) are sane. + * DTLS-related tests. + * Check epoch before checking length constraint because + * the latter varies with the epoch. E.g., if a ChangeCipherSpec + * message gets duplicated before the corresponding Finished message, + * the second ChangeCipherSpec should be discarded because it belongs + * to an old epoch, but not because its length is shorter than + * the minimum record length for packets using the new record transform. + * Note that these two kinds of failures are handled differently, + * as an unexpected record is silently skipped but an invalid + * record leads to the entire datagram being dropped. */ #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1]; - /* Drop unexpected ChangeCipherSpec messages */ - if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && - ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC && - ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) ); - return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); - } - - /* Drop unexpected ApplicationData records, - * except at the beginning of renegotiations */ - if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA && - ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER -#if defined(MBEDTLS_SSL_RENEGOTIATION) - && ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && - ssl->state == MBEDTLS_SSL_SERVER_HELLO ) -#endif - ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) ); - return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); - } - /* Check epoch (and sequence number) with DTLS */ if( rec_epoch != ssl->in_epoch ) { @@ -3804,7 +4139,16 @@ static int ssl_parse_record_header( mbedtls_ssl_context *ssl ) } else #endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + { + /* Consider buffering the record. */ + if( rec_epoch == (unsigned int) ssl->in_epoch + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Consider record for buffering" ) ); + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); + } + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } } #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) @@ -3816,9 +4160,65 @@ static int ssl_parse_record_header( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); } #endif + + /* Drop unexpected ApplicationData records, + * except at the beginning of renegotiations */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA && + ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->state == MBEDTLS_SSL_SERVER_HELLO ) +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } } #endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* Check length against bounds of the current transform and version */ + if( ssl->transform_in == NULL ) + { + if( ssl->in_msglen < 1 || + ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + else + { + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * TLS encrypted messages can have up to 256 bytes of padding + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 && + ssl->in_msglen > ssl->transform_in->minlen + + MBEDTLS_SSL_IN_CONTENT_LEN + 256 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif + } + return( 0 ); } @@ -3859,7 +4259,7 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", ssl->in_msg, ssl->in_msglen ); - if( ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + if( ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); return( MBEDTLS_ERR_SSL_INVALID_RECORD ); @@ -3897,7 +4297,14 @@ static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ); * RFC 6347 4.1.2.7) and continue reading until a valid record is found. * */ -int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ) + +/* Helper functions for mbedtls_ssl_read_record(). */ +static int ssl_consume_current_message( mbedtls_ssl_context *ssl ); +static int ssl_get_next_record( mbedtls_ssl_context *ssl ); +static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, + unsigned update_hs_digest ) { int ret; @@ -3907,30 +4314,71 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ) { do { - if( ( ret = mbedtls_ssl_read_record_layer( ssl ) ) != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); + ret = ssl_consume_current_message( ssl ); + if( ret != 0 ) return( ret ); + + if( ssl_record_is_in_progress( ssl ) == 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + int have_buffered = 0; + + /* We only check for buffered messages if the + * current datagram is fully consumed. */ + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl_next_record_is_in_datagram( ssl ) == 0 ) + { + if( ssl_load_buffered_message( ssl ) == 0 ) + have_buffered = 1; + } + + if( have_buffered == 0 ) +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + { + ret = ssl_get_next_record( ssl ); + if( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ) + continue; + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_get_next_record" ), ret ); + return( ret ); + } + } } ret = mbedtls_ssl_handle_message_type( ssl ); - } while( MBEDTLS_ERR_SSL_NON_FATAL == ret ); +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE ) + { + /* Buffer future message */ + ret = ssl_buffer_message( ssl ); + if( ret != 0 ) + return( ret ); + + ret = MBEDTLS_ERR_SSL_CONTINUE_PROCESSING; + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + } while( MBEDTLS_ERR_SSL_NON_FATAL == ret || + MBEDTLS_ERR_SSL_CONTINUE_PROCESSING == ret ); if( 0 != ret ) { - MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), ret ); return( ret ); } - if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + update_hs_digest == 1 ) { mbedtls_ssl_update_handshake_status( ssl ); } } else { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= reuse previously read message" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "reuse previously read message" ) ); ssl->keep_current_message = 0; } @@ -3939,13 +4387,350 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ) return( 0 ); } -int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl ) { - int ret; + if( ssl->in_left > ssl->next_record_offset ) + return( 1 ); + + return( 0 ); +} + +static int ssl_load_buffered_message( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + mbedtls_ssl_hs_buffer * hs_buf; + int ret = 0; + + if( hs == NULL ) + return( -1 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_messsage" ) ); + + if( ssl->state == MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC || + ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) + { + /* Check if we have seen a ChangeCipherSpec before. + * If yes, synthesize a CCS record. */ + if( !hs->buffering.seen_ccs ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "CCS not seen in the current flight" ) ); + ret = -1; + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Injecting buffered CCS message" ) ); + ssl->in_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC; + ssl->in_msglen = 1; + ssl->in_msg[0] = 1; + + /* As long as they are equal, the exact value doesn't matter. */ + ssl->in_left = 0; + ssl->next_record_offset = 0; + + hs->buffering.seen_ccs = 0; + goto exit; + } + +#if defined(MBEDTLS_DEBUG_C) + /* Debug only */ + { + unsigned offset; + for( offset = 1; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ ) + { + hs_buf = &hs->buffering.hs[offset]; + if( hs_buf->is_valid == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Future message with sequence number %u %s buffered.", + hs->in_msg_seq + offset, + hs_buf->is_complete ? "fully" : "partially" ) ); + } + } + } +#endif /* MBEDTLS_DEBUG_C */ + + /* Check if we have buffered and/or fully reassembled the + * next handshake message. */ + hs_buf = &hs->buffering.hs[0]; + if( ( hs_buf->is_valid == 1 ) && ( hs_buf->is_complete == 1 ) ) + { + /* Synthesize a record containing the buffered HS message. */ + size_t msg_len = ( hs_buf->data[1] << 16 ) | + ( hs_buf->data[2] << 8 ) | + hs_buf->data[3]; + + /* Double-check that we haven't accidentally buffered + * a message that doesn't fit into the input buffer. */ + if( msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message has been buffered - load" ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered handshake message (incl. header)", + hs_buf->data, msg_len + 12 ); + + ssl->in_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->in_hslen = msg_len + 12; + ssl->in_msglen = msg_len + 12; + memcpy( ssl->in_msg, hs_buf->data, ssl->in_hslen ); + + ret = 0; + goto exit; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message %u not or only partially bufffered", + hs->in_msg_seq ) ); + } + + ret = -1; + +exit: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_message" ) ); + return( ret ); +} + +static int ssl_buffer_make_space( mbedtls_ssl_context *ssl, + size_t desired ) +{ + int offset; + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Attempt to free buffered messages to have %u bytes available", + (unsigned) desired ) ); + + /* Get rid of future records epoch first, if such exist. */ + ssl_free_buffered_record( ssl ); + + /* Check if we have enough space available now. */ + if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing future epoch record" ) ); + return( 0 ); + } + + /* We don't have enough space to buffer the next expected handshake + * message. Remove buffers used for future messages to gain space, + * starting with the most distant one. */ + for( offset = MBEDTLS_SSL_MAX_BUFFERED_HS - 1; + offset >= 0; offset-- ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Free buffering slot %d to make space for reassembly of next handshake message", + offset ) ); + + ssl_buffering_free_slot( ssl, (uint8_t) offset ); + + /* Check if we have enough space available now. */ + if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing buffered HS messages" ) ); + return( 0 ); + } + } + + return( -1 ); +} + +static int ssl_buffer_message( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + + if( hs == NULL ) + return( 0 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_buffer_message" ) ); + + switch( ssl->in_msgtype ) + { + case MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Remember CCS message" ) ); + + hs->buffering.seen_ccs = 1; + break; + + case MBEDTLS_SSL_MSG_HANDSHAKE: + { + unsigned recv_msg_seq_offset; + unsigned recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5]; + mbedtls_ssl_hs_buffer *hs_buf; + size_t msg_len = ssl->in_hslen - 12; + + /* We should never receive an old handshake + * message - double-check nonetheless. */ + if( recv_msg_seq < ssl->handshake->in_msg_seq ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + recv_msg_seq_offset = recv_msg_seq - ssl->handshake->in_msg_seq; + if( recv_msg_seq_offset >= MBEDTLS_SSL_MAX_BUFFERED_HS ) + { + /* Silently ignore -- message too far in the future */ + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "Ignore future HS message with sequence number %u, " + "buffering window %u - %u", + recv_msg_seq, ssl->handshake->in_msg_seq, + ssl->handshake->in_msg_seq + MBEDTLS_SSL_MAX_BUFFERED_HS - 1 ) ); + + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering HS message with sequence number %u, offset %u ", + recv_msg_seq, recv_msg_seq_offset ) ); + + hs_buf = &hs->buffering.hs[ recv_msg_seq_offset ]; + + /* Check if the buffering for this seq nr has already commenced. */ + if( !hs_buf->is_valid ) + { + size_t reassembly_buf_sz; + + hs_buf->is_fragmented = + ( ssl_hs_is_proper_fragment( ssl ) == 1 ); + + /* We copy the message back into the input buffer + * after reassembly, so check that it's not too large. + * This is an implementation-specific limitation + * and not one from the standard, hence it is not + * checked in ssl_check_hs_header(). */ + if( msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + /* Ignore message */ + goto exit; + } + + /* Check if we have enough space to buffer the message. */ + if( hs->buffering.total_bytes_buffered > + MBEDTLS_SSL_DTLS_MAX_BUFFERING ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + reassembly_buf_sz = ssl_get_reassembly_buffer_size( msg_len, + hs_buf->is_fragmented ); + + if( reassembly_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) + { + if( recv_msg_seq_offset > 0 ) + { + /* If we can't buffer a future message because + * of space limitations -- ignore. */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n", + (unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + goto exit; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- attempt to make space by freeing buffered future messages\n", + (unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + } + + if( ssl_buffer_make_space( ssl, reassembly_buf_sz ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reassembly of next message of size %u (%u with bitmap) would exceed the compile-time limit %u (already %u bytes buffered) -- fail\n", + (unsigned) msg_len, + (unsigned) reassembly_buf_sz, + MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + ret = MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; + goto exit; + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d", + msg_len ) ); + + hs_buf->data = mbedtls_calloc( 1, reassembly_buf_sz ); + if( hs_buf->data == NULL ) + { + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + hs_buf->data_len = reassembly_buf_sz; + + /* Prepare final header: copy msg_type, length and message_seq, + * then add standardised fragment_offset and fragment_length */ + memcpy( hs_buf->data, ssl->in_msg, 6 ); + memset( hs_buf->data + 6, 0, 3 ); + memcpy( hs_buf->data + 9, hs_buf->data + 1, 3 ); + + hs_buf->is_valid = 1; + + hs->buffering.total_bytes_buffered += reassembly_buf_sz; + } + else + { + /* Make sure msg_type and length are consistent */ + if( memcmp( hs_buf->data, ssl->in_msg, 4 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Fragment header mismatch - ignore" ) ); + /* Ignore */ + goto exit; + } + } + + if( !hs_buf->is_complete ) + { + size_t frag_len, frag_off; + unsigned char * const msg = hs_buf->data + 12; + + /* + * Check and copy current fragment + */ + + /* Validation of header fields already done in + * mbedtls_ssl_prepare_handshake_record(). */ + frag_off = ssl_get_hs_frag_off( ssl ); + frag_len = ssl_get_hs_frag_len( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d", + frag_off, frag_len ) ); + memcpy( msg + frag_off, ssl->in_msg + 12, frag_len ); + + if( hs_buf->is_fragmented ) + { + unsigned char * const bitmask = msg + msg_len; + ssl_bitmask_set( bitmask, frag_off, frag_len ); + hs_buf->is_complete = ( ssl_bitmask_check( bitmask, + msg_len ) == 0 ); + } + else + { + hs_buf->is_complete = 1; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message %scomplete", + hs_buf->is_complete ? "" : "not yet " ) ); + } + + break; + } + + default: + /* We don't buffer other types of messages. */ + break; + } + +exit: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_buffer_message" ) ); + return( ret ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_consume_current_message( mbedtls_ssl_context *ssl ) +{ /* - * Step A - * * Consume last content-layer message and potentially * update in_msglen which keeps track of the contents' * consumption state. @@ -3957,11 +4742,6 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) * (2) Alert messages: * Consume whole record content, in_msglen = 0. * - * NOTE: This needs to be fixed, since like for - * handshake messages it is allowed to have - * multiple alerts witin a single record. - * Internal reference IOTSSL-1321. - * * (3) Change cipher spec: * Consume whole record content, in_msglen = 0. * @@ -3989,12 +4769,12 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) */ /* Notes: - * (1) in_hslen is *NOT* necessarily the size of the + * (1) in_hslen is not necessarily the size of the * current handshake content: If DTLS handshake * fragmentation is used, that's the fragment * size instead. Using the total handshake message - * size here is FAULTY and should be changed at - * some point. Internal reference IOTSSL-1414. + * size here is faulty and should be changed at + * some point. * (2) While it doesn't seem to cause problems, one * has to be very careful not to assume that in_hslen * is always <= in_msglen in a sensible communication. @@ -4011,47 +4791,182 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen, ssl->in_msglen ); - MBEDTLS_SSL_DEBUG_BUF( 4, "remaining content in record", - ssl->in_msg, ssl->in_msglen ); - } - else - { - ssl->in_msglen = 0; - } + MBEDTLS_SSL_DEBUG_BUF( 4, "remaining content in record", + ssl->in_msg, ssl->in_msglen ); + } + else + { + ssl->in_msglen = 0; + } + + ssl->in_hslen = 0; + } + /* Case (4): Application data */ + else if( ssl->in_offt != NULL ) + { + return( 0 ); + } + /* Everything else (CCS & Alerts) */ + else + { + ssl->in_msglen = 0; + } + + return( 0 ); +} + +static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_msglen > 0 ) + return( 1 ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +static void ssl_free_buffered_record( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + if( hs == NULL ) + return; + + if( hs->buffering.future_record.data != NULL ) + { + hs->buffering.total_bytes_buffered -= + hs->buffering.future_record.len; + + mbedtls_free( hs->buffering.future_record.data ); + hs->buffering.future_record.data = NULL; + } +} + +static int ssl_load_buffered_record( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + unsigned char * rec; + size_t rec_len; + unsigned rec_epoch; - ssl->in_hslen = 0; + if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 0 ); + + if( hs == NULL ) + return( 0 ); + + rec = hs->buffering.future_record.data; + rec_len = hs->buffering.future_record.len; + rec_epoch = hs->buffering.future_record.epoch; + + if( rec == NULL ) + return( 0 ); + + /* Only consider loading future records if the + * input buffer is empty. */ + if( ssl_next_record_is_in_datagram( ssl ) == 1 ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_record" ) ); + + if( rec_epoch != ssl->in_epoch ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffered record not from current epoch." ) ); + goto exit; } - /* Case (4): Application data */ - else if( ssl->in_offt != NULL ) + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Found buffered record from current epoch - load" ) ); + + /* Double-check that the record is not too large */ + if( rec_len > MBEDTLS_SSL_IN_BUFFER_LEN - + (size_t)( ssl->in_hdr - ssl->in_buf ) ) { - return( 0 ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - /* Everything else (CCS & Alerts) */ - else + + memcpy( ssl->in_hdr, rec, rec_len ); + ssl->in_left = rec_len; + ssl->next_record_offset = 0; + + ssl_free_buffered_record( ssl ); + +exit: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_record" ) ); + return( 0 ); +} + +static int ssl_buffer_future_record( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + size_t const rec_hdr_len = 13; + size_t const total_buf_sz = rec_hdr_len + ssl->in_msglen; + + /* Don't buffer future records outside handshakes. */ + if( hs == NULL ) + return( 0 ); + + /* Only buffer handshake records (we are only interested + * in Finished messages). */ + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + return( 0 ); + + /* Don't buffer more than one future epoch record. */ + if( hs->buffering.future_record.data != NULL ) + return( 0 ); + + /* Don't buffer record if there's not enough buffering space remaining. */ + if( total_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) { - ssl->in_msglen = 0; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future epoch record of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n", + (unsigned) total_buf_sz, MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + return( 0 ); } - /* - * Step B - * - * Fetch and decode new record if current one is fully consumed. - * - */ + /* Buffer record */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffer record from epoch %u", + ssl->in_epoch + 1 ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered record", ssl->in_hdr, + rec_hdr_len + ssl->in_msglen ); - if( ssl->in_msglen > 0 ) + /* ssl_parse_record_header() only considers records + * of the next epoch as candidates for buffering. */ + hs->buffering.future_record.epoch = ssl->in_epoch + 1; + hs->buffering.future_record.len = total_buf_sz; + + hs->buffering.future_record.data = + mbedtls_calloc( 1, hs->buffering.future_record.len ); + if( hs->buffering.future_record.data == NULL ) { - /* There's something left to be processed in the current record. */ + /* If we run out of RAM trying to buffer a + * record from the next epoch, just ignore. */ return( 0 ); } - /* Need to fetch a new record */ + memcpy( hs->buffering.future_record.data, ssl->in_hdr, total_buf_sz ); -#if defined(MBEDTLS_SSL_PROTO_DTLS) -read_record_header: -#endif + hs->buffering.total_bytes_buffered += total_buf_sz; + return( 0 ); +} + +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_get_next_record( mbedtls_ssl_context *ssl ) +{ + int ret; - /* Current record either fully processed or to be discarded. */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* We might have buffered a future record; if so, + * and if the epoch matches now, load it. + * On success, this call will set ssl->in_left to + * the length of the buffered record, so that + * the calls to ssl_fetch_input() below will + * essentially be no-ops. */ + ret = ssl_load_buffered_record( ssl ); + if( ret != 0 ) + return( ret ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) ) ) != 0 ) { @@ -4065,6 +4980,16 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT ) { + if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE ) + { + ret = ssl_buffer_future_record( ssl ); + if( ret != 0 ) + return( ret ); + + /* Fall through to handling of unexpected records */ + ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD; + } + if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ) { /* Skip unexpected record (but not whole datagram) */ @@ -4085,7 +5010,7 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) } /* Get next record */ - goto read_record_header; + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); } #endif return( ret ); @@ -4104,7 +5029,13 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) /* Done reading this record, get ready for the next one */ #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { ssl->next_record_offset = ssl->in_msglen + mbedtls_ssl_hdr_len( ssl ); + if( ssl->next_record_offset < ssl->in_left ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "more than one record within datagram" ) ); + } + } else #endif ssl->in_left = 0; @@ -4151,7 +5082,7 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) ssl->in_left = 0; MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record (mac)" ) ); - goto read_record_header; + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); } return( ret ); @@ -4172,46 +5103,6 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) } } - /* - * When we sent the last flight of the handshake, we MUST respond to a - * retransmit of the peer's previous flight with a retransmit. (In - * practice, only the Finished message will make it, other messages - * including CCS use the old transform so they're dropped as invalid.) - * - * If the record we received is not a handshake message, however, it - * means the peer received our last flight so we can clean up - * handshake info. - * - * This check needs to be done before prepare_handshake() due to an edge - * case: if the client immediately requests renegotiation, this - * finishes the current handshake first, avoiding the new ClientHello - * being mistaken for an ancient message in the current handshake. - */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && - ssl->handshake != NULL && - ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) - { - if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && - ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) - { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "received retransmit of last flight" ) ); - - if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); - return( ret ); - } - - return( MBEDTLS_ERR_SSL_WANT_READ ); - } - else - { - ssl_handshake_wrapup_free_hs_transform( ssl ); - } - } -#endif - return( 0 ); } @@ -4230,6 +5121,39 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) } } + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + if( ssl->in_msglen != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, len: %d", + ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->in_msg[0] != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, content: %02x", + ssl->in_msg[0] ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) + { + if( ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping ChangeCipherSpec outside handshake" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received out-of-order ChangeCipherSpec - remember" ) ); + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); + } +#endif + } + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) { if( ssl->in_msglen != 2 ) @@ -4266,7 +5190,7 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no_cert" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no renegotiation alert" ) ); /* Will be handled when trying to parse ServerHello */ return( 0 ); } @@ -4288,6 +5212,15 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) return MBEDTLS_ERR_SSL_NON_FATAL; } +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ssl_handshake_wrapup_free_hs_transform( ssl ); + } +#endif + return( 0 ); } @@ -4322,7 +5255,7 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, ssl->out_msg[0] = level; ssl->out_msg[1] = message; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); return( ret ); @@ -4462,10 +5395,10 @@ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) while( crt != NULL ) { n = crt->raw.len; - if( n > MBEDTLS_SSL_MAX_CONTENT_LEN - 3 - i ) + if( n > MBEDTLS_SSL_OUT_CONTENT_LEN - 3 - i ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", - i + 3 + n, MBEDTLS_SSL_MAX_CONTENT_LEN ) ); + i + 3 + n, MBEDTLS_SSL_OUT_CONTENT_LEN ) ); return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE ); } @@ -4491,9 +5424,9 @@ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) ssl->state++; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } @@ -4502,60 +5435,16 @@ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) return( ret ); } -int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +/* + * Once the certificate message is read, parse it into a cert chain and + * perform basic checks, but leave actual verification to the caller + */ +static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl ) { - int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + int ret; size_t i, n; - const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; - int authmode = ssl->conf->authmode; uint8_t alert; - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); - - if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) - { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); - ssl->state++; - return( 0 ); - } - -#if defined(MBEDTLS_SSL_SRV_C) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) - { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); - ssl->state++; - return( 0 ); - } - -#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) - if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) - authmode = ssl->handshake->sni_authmode; -#endif - - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - authmode == MBEDTLS_SSL_VERIFY_NONE ) - { - ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY; - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); - ssl->state++; - return( 0 ); - } -#endif - - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) - { - /* mbedtls_ssl_read_record may have sent an alert already. We - let it decide whether to alert. */ - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); - return( ret ); - } - - ssl->state++; - #if defined(MBEDTLS_SSL_SRV_C) #if defined(MBEDTLS_SSL_PROTO_SSL3) /* @@ -4575,10 +5464,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) one. The client should know what's going on, so we don't send an alert. */ ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; - if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) - return( 0 ); - else - return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); } } #endif /* MBEDTLS_SSL_PROTO_SSL3 */ @@ -4599,10 +5485,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) one. The client should know what's going on, so we don't send an alert. */ ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; - if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) - return( 0 ); - else - return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); } } #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ @@ -4752,6 +5635,94 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ + return( 0 ); +} + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ssl_ciphersuite_t * const ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET + ? ssl->handshake->sni_authmode + : ssl->conf->authmode; +#else + const int authmode = ssl->conf->authmode; +#endif + void *rs_ctx = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + + ssl->state++; + return( 0 ); + } +#endif + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled && + ssl->handshake->ecrs_state == ssl_ecrs_crt_verify ) + { + goto crt_verify; + } +#endif + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + /* mbedtls_ssl_read_record may have sent an alert already. We + let it decide whether to alert. */ + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ( ret = ssl_parse_certificate_chain( ssl ) ) != 0 ) + { +#if defined(MBEDTLS_SSL_SRV_C) + if( ret == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE && + authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + { + ret = 0; + } +#endif + + ssl->state++; + return( ret ); + } + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled) + ssl->handshake->ecrs_state = ssl_ecrs_crt_verify; + +crt_verify: + if( ssl->handshake->ecrs_enabled) + rs_ctx = &ssl->handshake->ecrs_ctx; +#endif + if( authmode != MBEDTLS_SSL_VERIFY_NONE ) { mbedtls_x509_crt *ca_chain; @@ -4773,19 +5744,24 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) /* * Main check: verify certificate */ - ret = mbedtls_x509_crt_verify_with_profile( + ret = mbedtls_x509_crt_verify_restartable( ssl->session_negotiate->peer_cert, ca_chain, ca_crl, ssl->conf->cert_profile, ssl->hostname, &ssl->session_negotiate->verify_result, - ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx ); if( ret != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); } +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ); +#endif + /* * Secondary checks: always done, but change 'ret' only if it was 0 */ @@ -4838,6 +5814,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) if( ret != 0 ) { + uint8_t alert; + /* The certificate may have been rejected for several reasons. Pick one and send the corresponding alert. Which alert to send may be a subject of debate in some cases. */ @@ -4880,6 +5858,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_DEBUG_C */ } + ssl->state++; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); return( ret ); @@ -4904,9 +5884,9 @@ int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ) ssl->state++; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } @@ -4921,7 +5901,7 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) ); - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); @@ -4935,13 +5915,8 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); } - if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); - mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); - return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); - } + /* CCS records are only accepted if they have length 1 and content '1', + * so we don't need to check this here. */ /* * Switch to our negotiated transform and session parameters for inbound @@ -4971,16 +5946,7 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_SSL_PROTO_DTLS */ memset( ssl->in_ctr, 0, 8 ); - /* - * Set the in_msg pointer to the correct location based on IV length - */ - if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) - { - ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen - - ssl->transform_negotiate->fixed_ivlen; - } - else - ssl->in_msg = ssl->in_iv; + ssl_update_in_pointers( ssl, ssl->transform_negotiate ); #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) if( mbedtls_ssl_hw_record_activate != NULL ) @@ -5171,9 +6137,9 @@ static void ssl_calc_finished_ssl( mbedtls_md5_free( &md5 ); mbedtls_sha1_free( &sha1 ); - mbedtls_zeroize( padbuf, sizeof( padbuf ) ); - mbedtls_zeroize( md5sum, sizeof( md5sum ) ); - mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_platform_zeroize( md5sum, sizeof( md5sum ) ); + mbedtls_platform_zeroize( sha1sum, sizeof( sha1sum ) ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); } @@ -5232,7 +6198,7 @@ static void ssl_calc_finished_tls( mbedtls_md5_free( &md5 ); mbedtls_sha1_free( &sha1 ); - mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); } @@ -5282,7 +6248,7 @@ static void ssl_calc_finished_tls_sha256( mbedtls_sha256_free( &sha256 ); - mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); } @@ -5331,7 +6297,7 @@ static void ssl_calc_finished_tls_sha384( mbedtls_sha512_free( &sha512 ); - mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); } @@ -5345,7 +6311,7 @@ static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) /* * Free our handshake params */ - mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_handshake_free( ssl ); mbedtls_free( ssl->handshake ); ssl->handshake = NULL; @@ -5431,16 +6397,7 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); - /* - * Set the out_msg pointer to the correct location based on IV length - */ - if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) - { - ssl->out_msg = ssl->out_iv + ssl->transform_negotiate->ivlen - - ssl->transform_negotiate->fixed_ivlen; - } - else - ssl->out_msg = ssl->out_iv; + ssl_update_out_pointers( ssl, ssl->transform_negotiate ); ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->conf->endpoint ); @@ -5492,14 +6449,14 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) /* Remember current epoch settings for resending */ ssl->handshake->alt_transform_out = ssl->transform_out; - memcpy( ssl->handshake->alt_out_ctr, ssl->out_ctr, 8 ); + memcpy( ssl->handshake->alt_out_ctr, ssl->cur_out_ctr, 8 ); /* Set sequence_number to zero */ - memset( ssl->out_ctr + 2, 0, 6 ); + memset( ssl->cur_out_ctr + 2, 0, 6 ); /* Increment epoch */ for( i = 2; i > 0; i-- ) - if( ++ssl->out_ctr[i - 1] != 0 ) + if( ++ssl->cur_out_ctr[i - 1] != 0 ) break; /* The loop goes to its end iff the counter is wrapping */ @@ -5511,7 +6468,7 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) } else #endif /* MBEDTLS_SSL_PROTO_DTLS */ - memset( ssl->out_ctr, 0, 8 ); + memset( ssl->cur_out_ctr, 0, 8 ); ssl->transform_out = ssl->transform_negotiate; ssl->session_out = ssl->session_negotiate; @@ -5532,11 +6489,20 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) mbedtls_ssl_send_flight_completed( ssl ); #endif - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); return( ret ); } +#endif MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); @@ -5559,7 +6525,7 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 ); - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); @@ -5671,6 +6637,10 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) #endif #endif +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + mbedtls_x509_crt_restart_init( &handshake->ecrs_ctx ); +#endif + #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET; #endif @@ -5700,7 +6670,7 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) if( ssl->session_negotiate ) mbedtls_ssl_session_free( ssl->session_negotiate ); if( ssl->handshake ) - mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_handshake_free( ssl ); /* * Either the pointers are now NULL or cleared properly and can be freed. @@ -5790,6 +6760,78 @@ static int ssl_cookie_check_dummy( void *ctx, } #endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ +/* Once ssl->out_hdr as the address of the beginning of the + * next outgoing record is set, deduce the other pointers. + * + * Note: For TLS, we save the implicit record sequence number + * (entering MAC computation) in the 8 bytes before ssl->out_hdr, + * and the caller has to make sure there's space for this. + */ + +static void ssl_update_out_pointers( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_ctr = ssl->out_hdr + 3; + ssl->out_len = ssl->out_hdr + 11; + ssl->out_iv = ssl->out_hdr + 13; + } + else +#endif + { + ssl->out_ctr = ssl->out_hdr - 8; + ssl->out_len = ssl->out_hdr + 3; + ssl->out_iv = ssl->out_hdr + 5; + } + + /* Adjust out_msg to make space for explicit IV, if used. */ + if( transform != NULL && + ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + transform->ivlen - transform->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; +} + +/* Once ssl->in_hdr as the address of the beginning of the + * next incoming record is set, deduce the other pointers. + * + * Note: For TLS, we save the implicit record sequence number + * (entering MAC computation) in the 8 bytes before ssl->in_hdr, + * and the caller has to make sure there's space for this. + */ + +static void ssl_update_in_pointers( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->in_ctr = ssl->in_hdr + 3; + ssl->in_len = ssl->in_hdr + 11; + ssl->in_iv = ssl->in_hdr + 13; + } + else +#endif + { + ssl->in_ctr = ssl->in_hdr - 8; + ssl->in_len = ssl->in_hdr + 3; + ssl->in_iv = ssl->in_hdr + 5; + } + + /* Offset in_msg from in_iv to allow space for explicit IV, if used. */ + if( transform != NULL && + ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->in_msg = ssl->in_iv + transform->ivlen - transform->fixed_ivlen; + } + else + ssl->in_msg = ssl->in_iv; +} + /* * Initialize an SSL context */ @@ -5801,57 +6843,59 @@ void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) /* * Setup an SSL context */ + +static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl ) +{ + /* Set the incoming and outgoing record pointers. */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + ssl->in_hdr = ssl->in_buf; + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + { + ssl->out_hdr = ssl->out_buf + 8; + ssl->in_hdr = ssl->in_buf + 8; + } + + /* Derive other internal pointers. */ + ssl_update_out_pointers( ssl, NULL /* no transform enabled */ ); + ssl_update_in_pointers ( ssl, NULL /* no transform enabled */ ); +} + int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf ) { int ret; - const size_t len = MBEDTLS_SSL_BUFFER_LEN; ssl->conf = conf; /* * Prepare base structures */ - ssl->in_buf = NULL; + + /* Set to NULL in case of an error condition */ ssl->out_buf = NULL; - if( ( ssl-> in_buf = mbedtls_calloc( 1, len ) ) == NULL || - ( ssl->out_buf = mbedtls_calloc( 1, len ) ) == NULL ) + + ssl->in_buf = mbedtls_calloc( 1, MBEDTLS_SSL_IN_BUFFER_LEN ); + if( ssl->in_buf == NULL ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", len ) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_IN_BUFFER_LEN) ); ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; goto error; } -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->out_buf = mbedtls_calloc( 1, MBEDTLS_SSL_OUT_BUFFER_LEN ); + if( ssl->out_buf == NULL ) { - ssl->out_hdr = ssl->out_buf; - ssl->out_ctr = ssl->out_buf + 3; - ssl->out_len = ssl->out_buf + 11; - ssl->out_iv = ssl->out_buf + 13; - ssl->out_msg = ssl->out_buf + 13; - - ssl->in_hdr = ssl->in_buf; - ssl->in_ctr = ssl->in_buf + 3; - ssl->in_len = ssl->in_buf + 11; - ssl->in_iv = ssl->in_buf + 13; - ssl->in_msg = ssl->in_buf + 13; + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_OUT_BUFFER_LEN) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto error; } - else -#endif - { - ssl->out_ctr = ssl->out_buf; - ssl->out_hdr = ssl->out_buf + 8; - ssl->out_len = ssl->out_buf + 11; - ssl->out_iv = ssl->out_buf + 13; - ssl->out_msg = ssl->out_buf + 13; - ssl->in_ctr = ssl->in_buf; - ssl->in_hdr = ssl->in_buf + 8; - ssl->in_len = ssl->in_buf + 11; - ssl->in_iv = ssl->in_buf + 13; - ssl->in_msg = ssl->in_buf + 13; - } + ssl_reset_in_out_pointers( ssl ); if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) goto error; @@ -5893,6 +6937,11 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) { int ret; +#if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || \ + !defined(MBEDTLS_SSL_SRV_C) + ((void) partial); +#endif + ssl->state = MBEDTLS_SSL_HELLO_REQUEST; /* Cancel any possibly running timer */ @@ -5909,12 +6958,10 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION; ssl->in_offt = NULL; + ssl_reset_in_out_pointers( ssl ); - ssl->in_msg = ssl->in_buf + 13; ssl->in_msgtype = 0; ssl->in_msglen = 0; - if( partial == 0 ) - ssl->in_left = 0; #if defined(MBEDTLS_SSL_PROTO_DTLS) ssl->next_record_offset = 0; ssl->in_epoch = 0; @@ -5928,7 +6975,6 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) ssl->keep_current_message = 0; - ssl->out_msg = ssl->out_buf + 13; ssl->out_msgtype = 0; ssl->out_msglen = 0; ssl->out_left = 0; @@ -5937,16 +6983,23 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) ssl->split_done = 0; #endif + memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) ); + ssl->transform_in = NULL; ssl->transform_out = NULL; ssl->session_in = NULL; ssl->session_out = NULL; - memset( ssl->out_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); + memset( ssl->out_buf, 0, MBEDTLS_SSL_OUT_BUFFER_LEN ); +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) if( partial == 0 ) - memset( ssl->in_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + { + ssl->in_left = 0; + memset( ssl->in_buf, 0, MBEDTLS_SSL_IN_BUFFER_LEN ); + } #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) if( mbedtls_ssl_hw_record_reset != NULL ) @@ -5979,7 +7032,9 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) #endif #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) if( partial == 0 ) +#endif { mbedtls_free( ssl->cli_id ); ssl->cli_id = NULL; @@ -6030,7 +7085,15 @@ void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limi #endif #if defined(MBEDTLS_SSL_PROTO_DTLS) -void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max ) + +void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl, + unsigned allow_packing ) +{ + ssl->disable_datagram_packing = !allow_packing; +} + +void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, + uint32_t min, uint32_t max ) { conf->hs_timeout_min = min; conf->hs_timeout_max = max; @@ -6080,6 +7143,13 @@ void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, ssl->f_recv_timeout = f_recv_timeout; } +#if defined(MBEDTLS_SSL_PROTO_DTLS) +void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu ) +{ + ssl->mtu = mtu; +} +#endif + void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ) { conf->read_timeout = timeout; @@ -6271,14 +7341,14 @@ int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, /* Identity len will be encoded on two bytes */ if( ( psk_identity_len >> 16 ) != 0 || - psk_identity_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + psk_identity_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) { return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } if( conf->psk != NULL ) { - mbedtls_zeroize( conf->psk, conf->psk_len ); + mbedtls_platform_zeroize( conf->psk, conf->psk_len ); mbedtls_free( conf->psk ); conf->psk = NULL; @@ -6321,7 +7391,8 @@ int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, if( ssl->handshake->psk != NULL ) { - mbedtls_zeroize( ssl->handshake->psk, ssl->handshake->psk_len ); + mbedtls_platform_zeroize( ssl->handshake->psk, + ssl->handshake->psk_len ); mbedtls_free( ssl->handshake->psk ); ssl->handshake->psk_len = 0; } @@ -6451,7 +7522,7 @@ int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) if( ssl->hostname != NULL ) { - mbedtls_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) ); mbedtls_free( ssl->hostname ); } @@ -6571,7 +7642,7 @@ void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 ) int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ) { if( mfl_code >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID || - mfl_code_to_length[mfl_code] > MBEDTLS_SSL_MAX_CONTENT_LEN ) + ssl_mfl_code_to_length( mfl_code ) > MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ) { return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } @@ -6650,6 +7721,43 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, } #endif +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +void mbedtls_ssl_conf_async_private_cb( + mbedtls_ssl_config *conf, + mbedtls_ssl_async_sign_t *f_async_sign, + mbedtls_ssl_async_decrypt_t *f_async_decrypt, + mbedtls_ssl_async_resume_t *f_async_resume, + mbedtls_ssl_async_cancel_t *f_async_cancel, + void *async_config_data ) +{ + conf->f_async_sign_start = f_async_sign; + conf->f_async_decrypt_start = f_async_decrypt; + conf->f_async_resume = f_async_resume; + conf->f_async_cancel = f_async_cancel; + conf->p_async_config_data = async_config_data; +} + +void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ) +{ + return( conf->p_async_config_data ); +} + +void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl ) +{ + if( ssl->handshake == NULL ) + return( NULL ); + else + return( ssl->handshake->user_async_ctx ); +} + +void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl, + void *ctx ) +{ + if( ssl->handshake != NULL ) + ssl->handshake->user_async_ctx = ctx; +} +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + /* * SSL get accessors */ @@ -6658,6 +7766,61 @@ size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); } +int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ) +{ + /* + * Case A: We're currently holding back + * a message for further processing. + */ + + if( ssl->keep_current_message == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: record held back for processing" ) ); + return( 1 ); + } + + /* + * Case B: Further records are pending in the current datagram. + */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->in_left > ssl->next_record_offset ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: more records within current datagram" ) ); + return( 1 ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* + * Case C: A handshake message is being processed. + */ + + if( ssl->in_hslen > 0 && ssl->in_hslen < ssl->in_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: more handshake messages within current record" ) ); + return( 1 ); + } + + /* + * Case D: An application data message is being processed + */ + if( ssl->in_offt != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: application data record is being processed" ) ); + return( 1 ); + } + + /* + * In all other cases, the rest of the message can be dropped. + * As in ssl_get_next_record, this needs to be adapted if + * we implement support for multiple alerts in single records. + */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: nothing pending" ) ); + return( 0 ); +} + uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ) { if( ssl->session != NULL ) @@ -6733,6 +7896,7 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) { case MBEDTLS_MODE_GCM: case MBEDTLS_MODE_CCM: + case MBEDTLS_MODE_CHACHAPOLY: case MBEDTLS_MODE_STREAM: transform_expansion = transform->minlen; break; @@ -6775,21 +7939,91 @@ size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) /* * Assume mfl_code is correct since it was checked when set */ - max_len = mfl_code_to_length[ssl->conf->mfl_code]; + max_len = ssl_mfl_code_to_length( ssl->conf->mfl_code ); - /* - * Check if a smaller max length was negotiated - */ + /* Check if a smaller max length was negotiated */ if( ssl->session_out != NULL && - mfl_code_to_length[ssl->session_out->mfl_code] < max_len ) + ssl_mfl_code_to_length( ssl->session_out->mfl_code ) < max_len ) + { + max_len = ssl_mfl_code_to_length( ssl->session_out->mfl_code ); + } + + /* During a handshake, use the value being negotiated */ + if( ssl->session_negotiate != NULL && + ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ) < max_len ) { - max_len = mfl_code_to_length[ssl->session_out->mfl_code]; + max_len = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ); } - return max_len; + return( max_len ); } #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl ) +{ + /* Return unlimited mtu for client hello messages to avoid fragmentation. */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ssl->state == MBEDTLS_SSL_CLIENT_HELLO || + ssl->state == MBEDTLS_SSL_SERVER_HELLO ) ) + return ( 0 ); + + if( ssl->handshake == NULL || ssl->handshake->mtu == 0 ) + return( ssl->mtu ); + + if( ssl->mtu == 0 ) + return( ssl->handshake->mtu ); + + return( ssl->mtu < ssl->handshake->mtu ? + ssl->mtu : ssl->handshake->mtu ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ) +{ + size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; + +#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \ + !defined(MBEDTLS_SSL_PROTO_DTLS) + (void) ssl; +#endif + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl ); + + if( max_len > mfl ) + max_len = mfl; +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl_get_current_mtu( ssl ) != 0 ) + { + const size_t mtu = ssl_get_current_mtu( ssl ); + const int ret = mbedtls_ssl_get_record_expansion( ssl ); + const size_t overhead = (size_t) ret; + + if( ret < 0 ) + return( ret ); + + if( mtu <= overhead ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "MTU too low for record expansion" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + if( max_len > mtu - overhead ) + max_len = mtu - overhead; + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \ + !defined(MBEDTLS_SSL_PROTO_DTLS) + ((void) ssl); +#endif + + return( (int) max_len ); +} + #if defined(MBEDTLS_X509_CRT_PARSE_C) const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ) { @@ -6877,9 +8111,9 @@ static int ssl_write_hello_request( mbedtls_ssl_context *ssl ) ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_REQUEST; - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); return( ret ); } @@ -7009,7 +8243,7 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl ) in_ctr_cmp = memcmp( ssl->in_ctr + ep_len, ssl->conf->renego_period + ep_len, 8 - ep_len ); - out_ctr_cmp = memcmp( ssl->out_ctr + ep_len, + out_ctr_cmp = memcmp( ssl->cur_out_ctr + ep_len, ssl->conf->renego_period + ep_len, 8 - ep_len ); if( in_ctr_cmp <= 0 && out_ctr_cmp <= 0 ) @@ -7044,7 +8278,7 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) if( ssl->handshake != NULL && ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) { - if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) return( ret ); } } @@ -7083,7 +8317,8 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) } } - if( ssl->in_offt == NULL ) + /* Loop as long as no application data record is available */ + while( ssl->in_offt == NULL ) { /* Start timer if not already running */ if( ssl->f_get_timer != NULL && @@ -7092,7 +8327,7 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) ssl_set_timer( ssl, ssl->conf->read_timeout ); } - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) return( 0 ); @@ -7107,7 +8342,7 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) /* * OpenSSL sends empty messages to randomize the IV */ - if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) { if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) return( 0 ); @@ -7137,7 +8372,9 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) /* With DTLS, drop the packet (probably from last handshake) */ #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - return( MBEDTLS_ERR_SSL_WANT_READ ); + { + continue; + } #endif return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); } @@ -7152,7 +8389,9 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) /* With DTLS, drop the packet (probably from last handshake) */ #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - return( MBEDTLS_ERR_SSL_WANT_READ ); + { + continue; + } #endif return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); } @@ -7225,7 +8464,25 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) } } - return( MBEDTLS_ERR_SSL_WANT_READ ); + /* At this point, we don't know whether the renegotiation has been + * completed or not. The cases to consider are the following: + * 1) The renegotiation is complete. In this case, no new record + * has been read yet. + * 2) The renegotiation is incomplete because the client received + * an application data record while awaiting the ServerHello. + * 3) The renegotiation is incomplete because the client received + * a non-handshake, non-application data message while awaiting + * the ServerHello. + * In each of these case, looping will be the proper action: + * - For 1), the next iteration will read a new record and check + * if it's application data. + * - For 2), the loop condition isn't satisfied as application data + * is present, hence continue is the same as break + * - For 3), the loop condition is satisfied and read_record + * will re-deliver the message that was held back by the client + * when expecting the ServerHello. + */ + continue; } #if defined(MBEDTLS_SSL_RENEGOTIATION) else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) @@ -7318,12 +8575,15 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) static int ssl_write_real( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) { - int ret; -#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - size_t max_len = mbedtls_ssl_get_max_frag_len( ssl ); -#else - size_t max_len = MBEDTLS_SSL_MAX_CONTENT_LEN; -#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + int ret = mbedtls_ssl_get_max_out_record_payload( ssl ); + const size_t max_len = (size_t) ret; + + if( ret < 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_max_out_record_payload", ret ); + return( ret ); + } + if( len > max_len ) { #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -7364,7 +8624,7 @@ static int ssl_write_real( mbedtls_ssl_context *ssl, ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; memcpy( ssl->out_msg, buf, len ); - if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); return( ret ); @@ -7499,7 +8759,7 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) mbedtls_md_free( &transform->md_ctx_enc ); mbedtls_md_free( &transform->md_ctx_dec ); - mbedtls_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); + mbedtls_platform_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); } #if defined(MBEDTLS_X509_CRT_PARSE_C) @@ -7516,11 +8776,57 @@ static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) } #endif /* MBEDTLS_X509_CRT_PARSE_C */ -void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ) +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +static void ssl_buffering_free( mbedtls_ssl_context *ssl ) +{ + unsigned offset; + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + + if( hs == NULL ) + return; + + ssl_free_buffered_record( ssl ); + + for( offset = 0; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ ) + ssl_buffering_free_slot( ssl, offset ); +} + +static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl, + uint8_t slot ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + mbedtls_ssl_hs_buffer * const hs_buf = &hs->buffering.hs[slot]; + + if( slot >= MBEDTLS_SSL_MAX_BUFFERED_HS ) + return; + + if( hs_buf->is_valid == 1 ) + { + hs->buffering.total_bytes_buffered -= hs_buf->data_len; + mbedtls_platform_zeroize( hs_buf->data, hs_buf->data_len ); + mbedtls_free( hs_buf->data ); + memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) ); + } +} + +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) { + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + if( handshake == NULL ) return; +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if( ssl->conf->f_async_cancel != NULL && handshake->async_in_progress != 0 ) + { + ssl->conf->f_async_cancel( ssl ); + handshake->async_in_progress = 0; + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) mbedtls_md5_free( &handshake->fin_md5 ); @@ -7559,7 +8865,7 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ) #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) if( handshake->psk != NULL ) { - mbedtls_zeroize( handshake->psk, handshake->psk_len ); + mbedtls_platform_zeroize( handshake->psk, handshake->psk_len ); mbedtls_free( handshake->psk ); } #endif @@ -7583,13 +8889,18 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ) } #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx ); +#endif + #if defined(MBEDTLS_SSL_PROTO_DTLS) mbedtls_free( handshake->verify_cookie ); - mbedtls_free( handshake->hs_msg ); ssl_flight_free( handshake->flight ); + ssl_buffering_free( ssl ); #endif - mbedtls_zeroize( handshake, sizeof( mbedtls_ssl_handshake_params ) ); + mbedtls_platform_zeroize( handshake, + sizeof( mbedtls_ssl_handshake_params ) ); } void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) @@ -7609,7 +8920,7 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) mbedtls_free( session->ticket ); #endif - mbedtls_zeroize( session, sizeof( mbedtls_ssl_session ) ); + mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) ); } /* @@ -7624,20 +8935,20 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) if( ssl->out_buf != NULL ) { - mbedtls_zeroize( ssl->out_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_platform_zeroize( ssl->out_buf, MBEDTLS_SSL_OUT_BUFFER_LEN ); mbedtls_free( ssl->out_buf ); } if( ssl->in_buf != NULL ) { - mbedtls_zeroize( ssl->in_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_platform_zeroize( ssl->in_buf, MBEDTLS_SSL_IN_BUFFER_LEN ); mbedtls_free( ssl->in_buf ); } #if defined(MBEDTLS_ZLIB_SUPPORT) if( ssl->compress_buf != NULL ) { - mbedtls_zeroize( ssl->compress_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_platform_zeroize( ssl->compress_buf, MBEDTLS_SSL_COMPRESS_BUFFER_LEN ); mbedtls_free( ssl->compress_buf ); } #endif @@ -7650,7 +8961,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) if( ssl->handshake ) { - mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_handshake_free( ssl ); mbedtls_ssl_transform_free( ssl->transform_negotiate ); mbedtls_ssl_session_free( ssl->session_negotiate ); @@ -7668,7 +8979,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_X509_CRT_PARSE_C) if( ssl->hostname != NULL ) { - mbedtls_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) ); mbedtls_free( ssl->hostname ); } #endif @@ -7688,7 +8999,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= free" ) ); /* Actually clear after last debug message */ - mbedtls_zeroize( ssl, sizeof( mbedtls_ssl_context ) ); + mbedtls_platform_zeroize( ssl, sizeof( mbedtls_ssl_context ) ); } /* @@ -7732,8 +9043,12 @@ static int ssl_preset_suiteb_hashes[] = { #if defined(MBEDTLS_ECP_C) static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = { +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) MBEDTLS_ECP_DP_SECP256R1, +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) MBEDTLS_ECP_DP_SECP384R1, +#endif MBEDTLS_ECP_DP_NONE }; #endif @@ -7915,11 +9230,17 @@ void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ) #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) if( conf->psk != NULL ) { - mbedtls_zeroize( conf->psk, conf->psk_len ); - mbedtls_zeroize( conf->psk_identity, conf->psk_identity_len ); + mbedtls_platform_zeroize( conf->psk, conf->psk_len ); mbedtls_free( conf->psk ); - mbedtls_free( conf->psk_identity ); + conf->psk = NULL; conf->psk_len = 0; + } + + if( conf->psk_identity != NULL ) + { + mbedtls_platform_zeroize( conf->psk_identity, conf->psk_identity_len ); + mbedtls_free( conf->psk_identity ); + conf->psk_identity = NULL; conf->psk_identity_len = 0; } #endif @@ -7928,7 +9249,7 @@ void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ) ssl_key_cert_free( conf->key_cert ); #endif - mbedtls_zeroize( conf, sizeof( mbedtls_ssl_config ) ); + mbedtls_platform_zeroize( conf, sizeof( mbedtls_ssl_config ) ); } #if defined(MBEDTLS_PK_C) && \ @@ -8411,13 +9732,14 @@ int mbedtls_ssl_get_key_exchange_md_ssl_tls( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_2) int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, - unsigned char *output, - unsigned char *data, size_t data_len, - mbedtls_md_type_t md_alg ) + unsigned char *hash, size_t *hashlen, + unsigned char *data, size_t data_len, + mbedtls_md_type_t md_alg ) { int ret = 0; mbedtls_md_context_t ctx; const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + *hashlen = mbedtls_md_get_size( md_info ); mbedtls_md_init( &ctx ); @@ -8448,7 +9770,7 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_update", ret ); goto exit; } - if( ( ret = mbedtls_md_finish( &ctx, output ) ) != 0 ) + if( ( ret = mbedtls_md_finish( &ctx, hash ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_finish", ret ); goto exit; diff --git a/app/mbedtls/library/threading.c b/app/mbedtls/library/threading.c index f1c37245c7..7c90c7c595 100644 --- a/app/mbedtls/library/threading.c +++ b/app/mbedtls/library/threading.c @@ -19,6 +19,14 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ +/* + * Ensure gmtime_r is available even with -std=c99; must be defined before + * config.h, which pulls in glibc's features.h. Harmless on other platforms. + */ +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 200112L +#endif + #if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/config.h" #else @@ -29,6 +37,36 @@ #include "mbedtls/threading.h" +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) + +#if !defined(_WIN32) && (defined(unix) || \ + defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \ + defined(__MACH__))) +#include +#endif /* !_WIN32 && (unix || __unix || __unix__ || + * (__APPLE__ && __MACH__)) */ + +#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) +/* + * This is a convenience shorthand macro to avoid checking the long + * preprocessor conditions above. Ideally, we could expose this macro in + * platform_util.h and simply use it in platform_util.c, threading.c and + * threading.h. However, this macro is not part of the Mbed TLS public API, so + * we keep it private by only defining it in this file + */ + +#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) +#define THREADING_USE_GMTIME +#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */ + +#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */ + +#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */ + #if defined(MBEDTLS_THREADING_PTHREAD) static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex ) { @@ -114,7 +152,7 @@ void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * #if defined(MBEDTLS_FS_IO) mbedtls_mutex_init( &mbedtls_threading_readdir_mutex ); #endif -#if defined(MBEDTLS_HAVE_TIME_DATE) +#if defined(THREADING_USE_GMTIME) mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex ); #endif } @@ -127,7 +165,7 @@ void mbedtls_threading_free_alt( void ) #if defined(MBEDTLS_FS_IO) mbedtls_mutex_free( &mbedtls_threading_readdir_mutex ); #endif -#if defined(MBEDTLS_HAVE_TIME_DATE) +#if defined(THREADING_USE_GMTIME) mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex ); #endif } @@ -142,7 +180,7 @@ void mbedtls_threading_free_alt( void ) #if defined(MBEDTLS_FS_IO) mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT; #endif -#if defined(MBEDTLS_HAVE_TIME_DATE) +#if defined(THREADING_USE_GMTIME) mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT; #endif diff --git a/app/mbedtls/library/timing.c b/app/mbedtls/library/timing.c index 8b9038326e..009516a6e3 100644 --- a/app/mbedtls/library/timing.c +++ b/app/mbedtls/library/timing.c @@ -39,7 +39,8 @@ #if !defined(MBEDTLS_TIMING_ALT) #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ - !defined(__APPLE__) && !defined(_WIN32) + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" #endif @@ -50,7 +51,6 @@ #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) #include -#include #include struct _hr_time diff --git a/app/mbedtls/library/version.c b/app/mbedtls/library/version.c index 6ca80d4695..fd96750885 100644 --- a/app/mbedtls/library/version.c +++ b/app/mbedtls/library/version.c @@ -30,7 +30,7 @@ #include "mbedtls/version.h" #include -unsigned int mbedtls_version_get_number() +unsigned int mbedtls_version_get_number( void ) { return( MBEDTLS_VERSION_NUMBER ); } diff --git a/app/mbedtls/library/version_features.c b/app/mbedtls/library/version_features.c index da47e3d753..3b67b2be85 100644 --- a/app/mbedtls/library/version_features.c +++ b/app/mbedtls/library/version_features.c @@ -39,6 +39,9 @@ static const char *features[] = { #if defined(MBEDTLS_NO_UDBL_DIVISION) "MBEDTLS_NO_UDBL_DIVISION", #endif /* MBEDTLS_NO_UDBL_DIVISION */ +#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION) + "MBEDTLS_NO_64BIT_MULTIPLICATION", +#endif /* MBEDTLS_NO_64BIT_MULTIPLICATION */ #if defined(MBEDTLS_HAVE_SSE2) "MBEDTLS_HAVE_SSE2", #endif /* MBEDTLS_HAVE_SSE2 */ @@ -81,6 +84,12 @@ static const char *features[] = { #if defined(MBEDTLS_DEPRECATED_REMOVED) "MBEDTLS_DEPRECATED_REMOVED", #endif /* MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_CHECK_PARAMS) + "MBEDTLS_CHECK_PARAMS", +#endif /* MBEDTLS_CHECK_PARAMS */ +#if defined(MBEDTLS_CHECK_PARAMS_ASSERT) + "MBEDTLS_CHECK_PARAMS_ASSERT", +#endif /* MBEDTLS_CHECK_PARAMS_ASSERT */ #if defined(MBEDTLS_TIMING_ALT) "MBEDTLS_TIMING_ALT", #endif /* MBEDTLS_TIMING_ALT */ @@ -90,6 +99,9 @@ static const char *features[] = { #if defined(MBEDTLS_ARC4_ALT) "MBEDTLS_ARC4_ALT", #endif /* MBEDTLS_ARC4_ALT */ +#if defined(MBEDTLS_ARIA_ALT) + "MBEDTLS_ARIA_ALT", +#endif /* MBEDTLS_ARIA_ALT */ #if defined(MBEDTLS_BLOWFISH_ALT) "MBEDTLS_BLOWFISH_ALT", #endif /* MBEDTLS_BLOWFISH_ALT */ @@ -99,6 +111,12 @@ static const char *features[] = { #if defined(MBEDTLS_CCM_ALT) "MBEDTLS_CCM_ALT", #endif /* MBEDTLS_CCM_ALT */ +#if defined(MBEDTLS_CHACHA20_ALT) + "MBEDTLS_CHACHA20_ALT", +#endif /* MBEDTLS_CHACHA20_ALT */ +#if defined(MBEDTLS_CHACHAPOLY_ALT) + "MBEDTLS_CHACHAPOLY_ALT", +#endif /* MBEDTLS_CHACHAPOLY_ALT */ #if defined(MBEDTLS_CMAC_ALT) "MBEDTLS_CMAC_ALT", #endif /* MBEDTLS_CMAC_ALT */ @@ -114,6 +132,9 @@ static const char *features[] = { #if defined(MBEDTLS_GCM_ALT) "MBEDTLS_GCM_ALT", #endif /* MBEDTLS_GCM_ALT */ +#if defined(MBEDTLS_NIST_KW_ALT) + "MBEDTLS_NIST_KW_ALT", +#endif /* MBEDTLS_NIST_KW_ALT */ #if defined(MBEDTLS_MD2_ALT) "MBEDTLS_MD2_ALT", #endif /* MBEDTLS_MD2_ALT */ @@ -123,6 +144,9 @@ static const char *features[] = { #if defined(MBEDTLS_MD5_ALT) "MBEDTLS_MD5_ALT", #endif /* MBEDTLS_MD5_ALT */ +#if defined(MBEDTLS_POLY1305_ALT) + "MBEDTLS_POLY1305_ALT", +#endif /* MBEDTLS_POLY1305_ALT */ #if defined(MBEDTLS_RIPEMD160_ALT) "MBEDTLS_RIPEMD160_ALT", #endif /* MBEDTLS_RIPEMD160_ALT */ @@ -237,6 +261,9 @@ static const char *features[] = { #if defined(MBEDTLS_AES_ROM_TABLES) "MBEDTLS_AES_ROM_TABLES", #endif /* MBEDTLS_AES_ROM_TABLES */ +#if defined(MBEDTLS_AES_FEWER_TABLES) + "MBEDTLS_AES_FEWER_TABLES", +#endif /* MBEDTLS_AES_FEWER_TABLES */ #if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) "MBEDTLS_CAMELLIA_SMALL_MEMORY", #endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ @@ -249,6 +276,12 @@ static const char *features[] = { #if defined(MBEDTLS_CIPHER_MODE_CTR) "MBEDTLS_CIPHER_MODE_CTR", #endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) + "MBEDTLS_CIPHER_MODE_OFB", +#endif /* MBEDTLS_CIPHER_MODE_OFB */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) + "MBEDTLS_CIPHER_MODE_XTS", +#endif /* MBEDTLS_CIPHER_MODE_XTS */ #if defined(MBEDTLS_CIPHER_NULL_CIPHER) "MBEDTLS_CIPHER_NULL_CIPHER", #endif /* MBEDTLS_CIPHER_NULL_CIPHER */ @@ -264,12 +297,18 @@ static const char *features[] = { #if defined(MBEDTLS_CIPHER_PADDING_ZEROS) "MBEDTLS_CIPHER_PADDING_ZEROS", #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ +#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) + "MBEDTLS_CTR_DRBG_USE_128_BIT_KEY", +#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */ #if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES) "MBEDTLS_ENABLE_WEAK_CIPHERSUITES", #endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ #if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) "MBEDTLS_REMOVE_ARC4_CIPHERSUITES", #endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */ +#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES) + "MBEDTLS_REMOVE_3DES_CIPHERSUITES", +#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */ #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) "MBEDTLS_ECP_DP_SECP192R1_ENABLED", #endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ @@ -306,9 +345,15 @@ static const char *features[] = { #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) "MBEDTLS_ECP_DP_CURVE25519_ENABLED", #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + "MBEDTLS_ECP_DP_CURVE448_ENABLED", +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ #if defined(MBEDTLS_ECP_NIST_OPTIM) "MBEDTLS_ECP_NIST_OPTIM", #endif /* MBEDTLS_ECP_NIST_OPTIM */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + "MBEDTLS_ECP_RESTARTABLE", +#endif /* MBEDTLS_ECP_RESTARTABLE */ #if defined(MBEDTLS_ECDSA_DETERMINISTIC) "MBEDTLS_ECDSA_DETERMINISTIC", #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ @@ -396,6 +441,9 @@ static const char *features[] = { #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) "MBEDTLS_SSL_ALL_ALERT_MESSAGES", #endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + "MBEDTLS_SSL_ASYNC_PRIVATE", +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_SSL_DEBUG_ALL) "MBEDTLS_SSL_DEBUG_ALL", #endif /* MBEDTLS_SSL_DEBUG_ALL */ @@ -525,12 +573,21 @@ static const char *features[] = { #if defined(MBEDTLS_CAMELLIA_C) "MBEDTLS_CAMELLIA_C", #endif /* MBEDTLS_CAMELLIA_C */ +#if defined(MBEDTLS_ARIA_C) + "MBEDTLS_ARIA_C", +#endif /* MBEDTLS_ARIA_C */ #if defined(MBEDTLS_CCM_C) "MBEDTLS_CCM_C", #endif /* MBEDTLS_CCM_C */ #if defined(MBEDTLS_CERTS_C) "MBEDTLS_CERTS_C", #endif /* MBEDTLS_CERTS_C */ +#if defined(MBEDTLS_CHACHA20_C) + "MBEDTLS_CHACHA20_C", +#endif /* MBEDTLS_CHACHA20_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + "MBEDTLS_CHACHAPOLY_C", +#endif /* MBEDTLS_CHACHAPOLY_C */ #if defined(MBEDTLS_CIPHER_C) "MBEDTLS_CIPHER_C", #endif /* MBEDTLS_CIPHER_C */ @@ -573,9 +630,15 @@ static const char *features[] = { #if defined(MBEDTLS_HAVEGE_C) "MBEDTLS_HAVEGE_C", #endif /* MBEDTLS_HAVEGE_C */ +#if defined(MBEDTLS_HKDF_C) + "MBEDTLS_HKDF_C", +#endif /* MBEDTLS_HKDF_C */ #if defined(MBEDTLS_HMAC_DRBG_C) "MBEDTLS_HMAC_DRBG_C", #endif /* MBEDTLS_HMAC_DRBG_C */ +#if defined(MBEDTLS_NIST_KW_C) + "MBEDTLS_NIST_KW_C", +#endif /* MBEDTLS_NIST_KW_C */ #if defined(MBEDTLS_MD_C) "MBEDTLS_MD_C", #endif /* MBEDTLS_MD_C */ @@ -627,6 +690,9 @@ static const char *features[] = { #if defined(MBEDTLS_PLATFORM_C) "MBEDTLS_PLATFORM_C", #endif /* MBEDTLS_PLATFORM_C */ +#if defined(MBEDTLS_POLY1305_C) + "MBEDTLS_POLY1305_C", +#endif /* MBEDTLS_POLY1305_C */ #if defined(MBEDTLS_RIPEMD160_C) "MBEDTLS_RIPEMD160_C", #endif /* MBEDTLS_RIPEMD160_C */ diff --git a/app/mbedtls/library/x509.c b/app/mbedtls/library/x509.c index 264c7fb0c6..2e0b0e8f6c 100644 --- a/app/mbedtls/library/x509.c +++ b/app/mbedtls/library/x509.c @@ -59,19 +59,23 @@ #define mbedtls_snprintf snprintf #endif - #if defined(MBEDTLS_HAVE_TIME) #include "mbedtls/platform_time.h" #endif - -#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) -#include -#else +#if defined(MBEDTLS_HAVE_TIME_DATE) +#include "mbedtls/platform_util.h" #include #endif -#define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); } -#define CHECK_RANGE(min, max, val) if( val < min || val > max ){ return( ret ); } +#define CHECK(code) if( ( ret = ( code ) ) != 0 ){ return( ret ); } +#define CHECK_RANGE(min, max, val) \ + do \ + { \ + if( ( val ) < ( min ) || ( val ) > ( max ) ) \ + { \ + return( ret ); \ + } \ + } while( 0 ) /* * CertificateSerialNumber ::= INTEGER @@ -119,7 +123,7 @@ int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, } /* - * Parse an algorithm identifier with (optional) paramaters + * Parse an algorithm identifier with (optional) parameters */ int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *alg, mbedtls_x509_buf *params ) @@ -357,6 +361,8 @@ static int x509_get_attr_type_value( unsigned char **p, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + end = *p + len; + if( ( end - *p ) < 1 ) return( MBEDTLS_ERR_X509_INVALID_NAME + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); @@ -390,6 +396,12 @@ static int x509_get_attr_type_value( unsigned char **p, val->p = *p; *p += val->len; + if( *p != end ) + { + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + cur->next = NULL; return( 0 ); @@ -696,30 +708,25 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50 * be either manually updated or extensions should be parsed!) */ int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, - mbedtls_x509_buf *ext, int tag ) + mbedtls_x509_buf *ext, int tag ) { int ret; size_t len; - if( *p == end ) - return( 0 ); - - ext->tag = **p; - - if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, - MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ) ) != 0 ) - return( ret ); + /* Extension structure use EXPLICIT tagging. That is, the actual + * `Extensions` structure is wrapped by a tag-length pair using + * the respective context-specific tag. */ + ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); - ext->p = *p; - end = *p + ext->len; + ext->tag = MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag; + ext->p = *p; + end = *p + ext->len; /* * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - * - * Extension ::= SEQUENCE { - * extnID OBJECT IDENTIFIER, - * critical BOOLEAN DEFAULT FALSE, - * extnValue OCTET STRING } */ if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) @@ -894,36 +901,14 @@ int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ) * Set the time structure to the current time. * Return 0 on success, non-zero on failure. */ -#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) -static int x509_get_current_time( mbedtls_x509_time *now ) -{ - SYSTEMTIME st; - - GetSystemTime( &st ); - - now->year = st.wYear; - now->mon = st.wMonth; - now->day = st.wDay; - now->hour = st.wHour; - now->min = st.wMinute; - now->sec = st.wSecond; - - return( 0 ); -} -#else static int x509_get_current_time( mbedtls_x509_time *now ) { - struct tm *lt; + struct tm *lt, tm_buf; mbedtls_time_t tt; int ret = 0; -#if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - tt = mbedtls_time( NULL ); - lt = gmtime( &tt ); + lt = mbedtls_platform_gmtime_r( &tt, &tm_buf ); if( lt == NULL ) ret = -1; @@ -937,14 +922,8 @@ static int x509_get_current_time( mbedtls_x509_time *now ) now->sec = lt->tm_sec; } -#if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - return( ret ); } -#endif /* _WIN32 && !EFIX64 && !EFI32 */ /* * Return 0 if before <= after, 1 otherwise @@ -1032,8 +1011,8 @@ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) */ int mbedtls_x509_self_test( int verbose ) { + int ret = 0; #if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C) - int ret; uint32_t flags; mbedtls_x509_crt cacert; mbedtls_x509_crt clicert; @@ -1041,6 +1020,7 @@ int mbedtls_x509_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( " X.509 certificate load: " ); + mbedtls_x509_crt_init( &cacert ); mbedtls_x509_crt_init( &clicert ); ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt, @@ -1050,11 +1030,9 @@ int mbedtls_x509_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( ret ); + goto cleanup; } - mbedtls_x509_crt_init( &cacert ); - ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt, mbedtls_test_ca_crt_len ); if( ret != 0 ) @@ -1062,7 +1040,7 @@ int mbedtls_x509_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( ret ); + goto cleanup; } if( verbose != 0 ) @@ -1074,20 +1052,19 @@ int mbedtls_x509_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( ret ); + goto cleanup; } if( verbose != 0 ) mbedtls_printf( "passed\n\n"); +cleanup: mbedtls_x509_crt_free( &cacert ); mbedtls_x509_crt_free( &clicert ); - - return( 0 ); #else ((void) verbose); - return( 0 ); #endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ + return( ret ); } #endif /* MBEDTLS_SELF_TEST */ diff --git a/app/mbedtls/library/x509_create.c b/app/mbedtls/library/x509_create.c index df20ec8ebd..546e8fa1a9 100644 --- a/app/mbedtls/library/x509_create.c +++ b/app/mbedtls/library/x509_create.c @@ -33,48 +33,84 @@ #include +/* Structure linking OIDs for X.509 DN AttributeTypes to their + * string representations and default string encodings used by Mbed TLS. */ typedef struct { - const char *name; - size_t name_len; - const char*oid; + const char *name; /* String representation of AttributeType, e.g. + * "CN" or "emailAddress". */ + size_t name_len; /* Length of 'name', without trailing 0 byte. */ + const char *oid; /* String representation of OID of AttributeType, + * as per RFC 5280, Appendix A.1. */ + int default_tag; /* The default character encoding used for the + * given attribute type, e.g. + * MBEDTLS_ASN1_UTF8_STRING for UTF-8. */ } x509_attr_descriptor_t; #define ADD_STRLEN( s ) s, sizeof( s ) - 1 +/* X.509 DN attributes from RFC 5280, Appendix A.1. */ static const x509_attr_descriptor_t x509_attrs[] = { - { ADD_STRLEN( "CN" ), MBEDTLS_OID_AT_CN }, - { ADD_STRLEN( "commonName" ), MBEDTLS_OID_AT_CN }, - { ADD_STRLEN( "C" ), MBEDTLS_OID_AT_COUNTRY }, - { ADD_STRLEN( "countryName" ), MBEDTLS_OID_AT_COUNTRY }, - { ADD_STRLEN( "O" ), MBEDTLS_OID_AT_ORGANIZATION }, - { ADD_STRLEN( "organizationName" ), MBEDTLS_OID_AT_ORGANIZATION }, - { ADD_STRLEN( "L" ), MBEDTLS_OID_AT_LOCALITY }, - { ADD_STRLEN( "locality" ), MBEDTLS_OID_AT_LOCALITY }, - { ADD_STRLEN( "R" ), MBEDTLS_OID_PKCS9_EMAIL }, - { ADD_STRLEN( "OU" ), MBEDTLS_OID_AT_ORG_UNIT }, - { ADD_STRLEN( "organizationalUnitName" ), MBEDTLS_OID_AT_ORG_UNIT }, - { ADD_STRLEN( "ST" ), MBEDTLS_OID_AT_STATE }, - { ADD_STRLEN( "stateOrProvinceName" ), MBEDTLS_OID_AT_STATE }, - { ADD_STRLEN( "emailAddress" ), MBEDTLS_OID_PKCS9_EMAIL }, - { ADD_STRLEN( "serialNumber" ), MBEDTLS_OID_AT_SERIAL_NUMBER }, - { ADD_STRLEN( "postalAddress" ), MBEDTLS_OID_AT_POSTAL_ADDRESS }, - { ADD_STRLEN( "postalCode" ), MBEDTLS_OID_AT_POSTAL_CODE }, - { ADD_STRLEN( "dnQualifier" ), MBEDTLS_OID_AT_DN_QUALIFIER }, - { ADD_STRLEN( "title" ), MBEDTLS_OID_AT_TITLE }, - { ADD_STRLEN( "surName" ), MBEDTLS_OID_AT_SUR_NAME }, - { ADD_STRLEN( "SN" ), MBEDTLS_OID_AT_SUR_NAME }, - { ADD_STRLEN( "givenName" ), MBEDTLS_OID_AT_GIVEN_NAME }, - { ADD_STRLEN( "GN" ), MBEDTLS_OID_AT_GIVEN_NAME }, - { ADD_STRLEN( "initials" ), MBEDTLS_OID_AT_INITIALS }, - { ADD_STRLEN( "pseudonym" ), MBEDTLS_OID_AT_PSEUDONYM }, - { ADD_STRLEN( "generationQualifier" ), MBEDTLS_OID_AT_GENERATION_QUALIFIER }, - { ADD_STRLEN( "domainComponent" ), MBEDTLS_OID_DOMAIN_COMPONENT }, - { ADD_STRLEN( "DC" ), MBEDTLS_OID_DOMAIN_COMPONENT }, - { NULL, 0, NULL } + { ADD_STRLEN( "CN" ), + MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "commonName" ), + MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "C" ), + MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "countryName" ), + MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "O" ), + MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "organizationName" ), + MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "L" ), + MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "locality" ), + MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "R" ), + MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING }, + { ADD_STRLEN( "OU" ), + MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "organizationalUnitName" ), + MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "ST" ), + MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "stateOrProvinceName" ), + MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "emailAddress" ), + MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING }, + { ADD_STRLEN( "serialNumber" ), + MBEDTLS_OID_AT_SERIAL_NUMBER, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "postalAddress" ), + MBEDTLS_OID_AT_POSTAL_ADDRESS, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "postalCode" ), + MBEDTLS_OID_AT_POSTAL_CODE, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "dnQualifier" ), + MBEDTLS_OID_AT_DN_QUALIFIER, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "title" ), + MBEDTLS_OID_AT_TITLE, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "surName" ), + MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "SN" ), + MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "givenName" ), + MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "GN" ), + MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "initials" ), + MBEDTLS_OID_AT_INITIALS, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "pseudonym" ), + MBEDTLS_OID_AT_PSEUDONYM, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "generationQualifier" ), + MBEDTLS_OID_AT_GENERATION_QUALIFIER, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "domainComponent" ), + MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING }, + { ADD_STRLEN( "DC" ), + MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING }, + { NULL, 0, NULL, MBEDTLS_ASN1_NULL } }; -static const char *x509_at_oid_from_name( const char *name, size_t name_len ) +static const x509_attr_descriptor_t *x509_attr_descr_from_name( const char *name, size_t name_len ) { const x509_attr_descriptor_t *cur; @@ -83,7 +119,10 @@ static const char *x509_at_oid_from_name( const char *name, size_t name_len ) strncmp( cur->name, name, name_len ) == 0 ) break; - return( cur->oid ); + if ( cur->name == NULL ) + return( NULL ); + + return( cur ); } int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ) @@ -92,6 +131,7 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na const char *s = name, *c = s; const char *end = s + strlen( s ); const char *oid = NULL; + const x509_attr_descriptor_t* attr_descr = NULL; int in_tag = 1; char data[MBEDTLS_X509_MAX_DN_NAME_SIZE]; char *d = data; @@ -103,12 +143,13 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na { if( in_tag && *c == '=' ) { - if( ( oid = x509_at_oid_from_name( s, c - s ) ) == NULL ) + if( ( attr_descr = x509_attr_descr_from_name( s, c - s ) ) == NULL ) { ret = MBEDTLS_ERR_X509_UNKNOWN_OID; goto exit; } + oid = attr_descr->oid; s = c + 1; in_tag = 0; d = data; @@ -127,13 +168,19 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na } else if( !in_tag && ( *c == ',' || c == end ) ) { - if( mbedtls_asn1_store_named_data( head, oid, strlen( oid ), - (unsigned char *) data, - d - data ) == NULL ) + mbedtls_asn1_named_data* cur = + mbedtls_asn1_store_named_data( head, oid, strlen( oid ), + (unsigned char *) data, + d - data ); + + if(cur == NULL ) { return( MBEDTLS_ERR_X509_ALLOC_FAILED ); } + // set tagType + cur->val.tag = attr_descr->default_tag; + while( c < end && *(c + 1) == ' ' ) c++; @@ -192,46 +239,40 @@ int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, * * AttributeValue ::= ANY DEFINED BY AttributeType */ -static int x509_write_name( unsigned char **p, unsigned char *start, - const char *oid, size_t oid_len, - const unsigned char *name, size_t name_len ) +static int x509_write_name( unsigned char **p, unsigned char *start, mbedtls_asn1_named_data* cur_name) { int ret; size_t len = 0; - - // Write PrintableString for all except MBEDTLS_OID_PKCS9_EMAIL - // - if( MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_EMAIL ) == oid_len && - memcmp( oid, MBEDTLS_OID_PKCS9_EMAIL, oid_len ) == 0 ) - { - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_ia5_string( p, start, - (const char *) name, - name_len ) ); - } - else - { - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_printable_string( p, start, - (const char *) name, - name_len ) ); - } - + const char *oid = (const char*)cur_name->oid.p; + size_t oid_len = cur_name->oid.len; + const unsigned char *name = cur_name->val.p; + size_t name_len = cur_name->val.len; + + // Write correct string tag and value + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tagged_string( p, start, + cur_name->val.tag, + (const char *) name, + name_len ) ); // Write OID // - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, + oid_len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | - MBEDTLS_ASN1_SEQUENCE ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ); return( (int) len ); } int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, - mbedtls_asn1_named_data *first ) + mbedtls_asn1_named_data *first ) { int ret; size_t len = 0; @@ -239,9 +280,7 @@ int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, while( cur != NULL ) { - MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p, - cur->oid.len, - cur->val.p, cur->val.len ) ); + MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, cur ) ); cur = cur->next; } diff --git a/app/mbedtls/library/x509_crl.c b/app/mbedtls/library/x509_crl.c index b0f39d428b..00f8545d7c 100644 --- a/app/mbedtls/library/x509_crl.c +++ b/app/mbedtls/library/x509_crl.c @@ -39,6 +39,7 @@ #include "mbedtls/x509_crl.h" #include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" #include @@ -66,11 +67,6 @@ #include #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * Version ::= INTEGER { v1(0), v2(1) } */ @@ -107,17 +103,17 @@ static int x509_get_crl_ext( unsigned char **p, { int ret; + if( *p == end ) + return( 0 ); + /* * crlExtensions [0] EXPLICIT Extensions OPTIONAL * -- if present, version MUST be v2 */ if( ( ret = mbedtls_x509_get_ext( p, end, ext, 0 ) ) != 0 ) - { - if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) - return( 0 ); - return( ret ); - } + + end = ext->p + ext->len; while( *p < end ) { @@ -616,7 +612,7 @@ int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ) ret = mbedtls_x509_crl_parse( chain, buf, n ); - mbedtls_zeroize( buf, n ); + mbedtls_platform_zeroize( buf, n ); mbedtls_free( buf ); return( ret ); @@ -737,7 +733,7 @@ void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ) { name_prv = name_cur; name_cur = name_cur->next; - mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); mbedtls_free( name_prv ); } @@ -746,13 +742,14 @@ void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ) { entry_prv = entry_cur; entry_cur = entry_cur->next; - mbedtls_zeroize( entry_prv, sizeof( mbedtls_x509_crl_entry ) ); + mbedtls_platform_zeroize( entry_prv, + sizeof( mbedtls_x509_crl_entry ) ); mbedtls_free( entry_prv ); } if( crl_cur->raw.p != NULL ) { - mbedtls_zeroize( crl_cur->raw.p, crl_cur->raw.len ); + mbedtls_platform_zeroize( crl_cur->raw.p, crl_cur->raw.len ); mbedtls_free( crl_cur->raw.p ); } @@ -766,7 +763,7 @@ void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ) crl_prv = crl_cur; crl_cur = crl_cur->next; - mbedtls_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) ); + mbedtls_platform_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) ); if( crl_prv != crl ) mbedtls_free( crl_prv ); } diff --git a/app/mbedtls/library/x509_crt.c b/app/mbedtls/library/x509_crt.c index d64d7279a5..9c2e36547e 100644 --- a/app/mbedtls/library/x509_crt.c +++ b/app/mbedtls/library/x509_crt.c @@ -27,6 +27,8 @@ * * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + * + * [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf */ #if !defined(MBEDTLS_CONFIG_FILE) @@ -39,6 +41,7 @@ #include "mbedtls/x509_crt.h" #include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" #include @@ -75,10 +78,18 @@ #endif /* !_WIN32 || EFIX64 || EFI32 */ #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +/* + * Item in a verification chain: cert and flags for it + */ +typedef struct { + mbedtls_x509_crt *crt; + uint32_t flags; +} x509_crt_verify_chain_item; + +/* + * Max size of verification chain: end-entity + intermediates + trusted root + */ +#define X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 ) /* * Default profile @@ -147,7 +158,7 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = /* * Check md_alg against profile - * Return 0 if md_alg acceptable for this profile, -1 otherwise + * Return 0 if md_alg is acceptable for this profile, -1 otherwise */ static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, mbedtls_md_type_t md_alg ) @@ -163,7 +174,7 @@ static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, /* * Check pk_alg against profile - * Return 0 if pk_alg acceptable for this profile, -1 otherwise + * Return 0 if pk_alg is acceptable for this profile, -1 otherwise */ static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, mbedtls_pk_type_t pk_alg ) @@ -179,12 +190,13 @@ static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, /* * Check key against profile - * Return 0 if pk_alg acceptable for this profile, -1 otherwise + * Return 0 if pk is acceptable for this profile, -1 otherwise */ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, - mbedtls_pk_type_t pk_alg, const mbedtls_pk_context *pk ) { + const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type( pk ); + #if defined(MBEDTLS_RSA_C) if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) { @@ -200,7 +212,7 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) { - mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; + const mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; if( gid == MBEDTLS_ECP_DP_NONE ) return( -1 ); @@ -215,6 +227,153 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, return( -1 ); } +/* + * Like memcmp, but case-insensitive and always returns -1 if different + */ +static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) +{ + size_t i; + unsigned char diff; + const unsigned char *n1 = s1, *n2 = s2; + + for( i = 0; i < len; i++ ) + { + diff = n1[i] ^ n2[i]; + + if( diff == 0 ) + continue; + + if( diff == 32 && + ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || + ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) + { + continue; + } + + return( -1 ); + } + + return( 0 ); +} + +/* + * Return 0 if name matches wildcard, -1 otherwise + */ +static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) +{ + size_t i; + size_t cn_idx = 0, cn_len = strlen( cn ); + + /* We can't have a match if there is no wildcard to match */ + if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + return( -1 ); + + for( i = 0; i < cn_len; ++i ) + { + if( cn[i] == '.' ) + { + cn_idx = i; + break; + } + } + + if( cn_idx == 0 ) + return( -1 ); + + if( cn_len - cn_idx == name->len - 1 && + x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 strings, case-insensitive, and allowing for some encoding + * variations (but not all). + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) +{ + if( a->tag == b->tag && + a->len == b->len && + memcmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + a->len == b->len && + x509_memcasecmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 Names (aka rdnSequence). + * + * See RFC 5280 section 7.1, though we don't implement the whole algorithm: + * we sometimes return unequal when the full algorithm would return equal, + * but never the other way. (In particular, we don't do Unicode normalisation + * or space folding.) + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) +{ + /* Avoid recursion, it might not be optimised by the compiler */ + while( a != NULL || b != NULL ) + { + if( a == NULL || b == NULL ) + return( -1 ); + + /* type */ + if( a->oid.tag != b->oid.tag || + a->oid.len != b->oid.len || + memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) + { + return( -1 ); + } + + /* value */ + if( x509_string_cmp( &a->val, &b->val ) != 0 ) + return( -1 ); + + /* structure of the list of sets */ + if( a->next_merged != b->next_merged ) + return( -1 ); + + a = a->next; + b = b->next; + } + + /* a == NULL == b */ + return( 0 ); +} + +/* + * Reset (init or clear) a verify_chain + */ +static void x509_crt_verify_chain_reset( + mbedtls_x509_crt_verify_chain *ver_chain ) +{ + size_t i; + + for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ ) + { + ver_chain->items[i].crt = NULL; + ver_chain->items[i].flags = (uint32_t) -1; + } + + ver_chain->len = 0; +} + /* * Version ::= INTEGER { v1(0), v2(1), v3(2) } */ @@ -234,7 +393,7 @@ static int x509_get_version( unsigned char **p, return( 0 ); } - return( ret ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } end = *p + len; @@ -301,7 +460,7 @@ static int x509_get_uid( unsigned char **p, if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) return( 0 ); - return( ret ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } uid->p = *p; @@ -540,14 +699,13 @@ static int x509_get_crt_ext( unsigned char **p, size_t len; unsigned char *end_ext_data, *end_ext_octet; - if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) - { - if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) - return( 0 ); + if( *p == end ) + return( 0 ); + if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) return( ret ); - } + end = crt->v3_ext.p + crt->v3_ext.len; while( *p < end ) { /* @@ -1104,7 +1262,7 @@ int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) ret = mbedtls_x509_crt_parse( chain, buf, n ); - mbedtls_zeroize( buf, n ); + mbedtls_platform_zeroize( buf, n ); mbedtls_free( buf ); return( ret ); @@ -1280,7 +1438,7 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, } #define CERT_TYPE(type,name) \ - if( ns_cert_type & type ) \ + if( ns_cert_type & (type) ) \ PRINT_ITEM( name ); static int x509_info_cert_type( char **buf, size_t *size, @@ -1307,7 +1465,7 @@ static int x509_info_cert_type( char **buf, size_t *size, } #define KEY_USAGE(code,name) \ - if( key_usage & code ) \ + if( key_usage & (code) ) \ PRINT_ITEM( name ); static int x509_info_key_usage( char **buf, size_t *size, @@ -1364,204 +1522,75 @@ static int x509_info_ext_key_usage( char **buf, size_t *size, } /* - * Like memcmp, but case-insensitive and always returns -1 if different + * Return an informational string about the certificate. */ -static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) +#define BEFORE_COLON 18 +#define BC "18" +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ) { - size_t i; - unsigned char diff; - const unsigned char *n1 = s1, *n2 = s2; + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; - for( i = 0; i < len; i++ ) + p = buf; + n = size; + + if( NULL == crt ) { - diff = n1[i] ^ n2[i]; + ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; - if( diff == 0 ) - continue; + return( (int) ( size - n ) ); + } - if( diff == 32 && - ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || - ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) - { - continue; - } + ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", + prefix, crt->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_snprintf( p, n, "%sserial number : ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; - return( -1 ); - } + ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; - return( 0 ); -} + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; -/* - * Return 0 if name matches wildcard, -1 otherwise - */ -static int x509_check_wildcard( const char *cn, mbedtls_x509_buf *name ) -{ - size_t i; - size_t cn_idx = 0, cn_len = strlen( cn ); + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; - if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) - return( 0 ); + ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_from.year, crt->valid_from.mon, + crt->valid_from.day, crt->valid_from.hour, + crt->valid_from.min, crt->valid_from.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; - for( i = 0; i < cn_len; ++i ) - { - if( cn[i] == '.' ) - { - cn_idx = i; - break; - } - } + ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_to.year, crt->valid_to.mon, + crt->valid_to.day, crt->valid_to.hour, + crt->valid_to.min, crt->valid_to.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; - if( cn_idx == 0 ) - return( -1 ); + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; - if( cn_len - cn_idx == name->len - 1 && - x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, + crt->sig_md, crt->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* Key size */ + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) { - return( 0 ); - } - - return( -1 ); -} - -/* - * Compare two X.509 strings, case-insensitive, and allowing for some encoding - * variations (but not all). - * - * Return 0 if equal, -1 otherwise. - */ -static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) -{ - if( a->tag == b->tag && - a->len == b->len && - memcmp( a->p, b->p, b->len ) == 0 ) - { - return( 0 ); - } - - if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && - ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && - a->len == b->len && - x509_memcasecmp( a->p, b->p, b->len ) == 0 ) - { - return( 0 ); - } - - return( -1 ); -} - -/* - * Compare two X.509 Names (aka rdnSequence). - * - * See RFC 5280 section 7.1, though we don't implement the whole algorithm: - * we sometimes return unequal when the full algorithm would return equal, - * but never the other way. (In particular, we don't do Unicode normalisation - * or space folding.) - * - * Return 0 if equal, -1 otherwise. - */ -static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) -{ - /* Avoid recursion, it might not be optimised by the compiler */ - while( a != NULL || b != NULL ) - { - if( a == NULL || b == NULL ) - return( -1 ); - - /* type */ - if( a->oid.tag != b->oid.tag || - a->oid.len != b->oid.len || - memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) - { - return( -1 ); - } - - /* value */ - if( x509_string_cmp( &a->val, &b->val ) != 0 ) - return( -1 ); - - /* structure of the list of sets */ - if( a->next_merged != b->next_merged ) - return( -1 ); - - a = a->next; - b = b->next; - } - - /* a == NULL == b */ - return( 0 ); -} - -/* - * Return an informational string about the certificate. - */ -#define BEFORE_COLON 18 -#define BC "18" -int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, - const mbedtls_x509_crt *crt ) -{ - int ret; - size_t n; - char *p; - char key_size_str[BEFORE_COLON]; - - p = buf; - n = size; - - if( NULL == crt ) - { - ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); - MBEDTLS_X509_SAFE_SNPRINTF; - - return( (int) ( size - n ) ); - } - - ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", - prefix, crt->version ); - MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "%sserial number : ", - prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ - "%04d-%02d-%02d %02d:%02d:%02d", prefix, - crt->valid_from.year, crt->valid_from.mon, - crt->valid_from.day, crt->valid_from.hour, - crt->valid_from.min, crt->valid_from.sec ); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ - "%04d-%02d-%02d %02d:%02d:%02d", prefix, - crt->valid_to.year, crt->valid_to.mon, - crt->valid_to.day, crt->valid_to.hour, - crt->valid_to.min, crt->valid_to.sec ); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, - crt->sig_md, crt->sig_opts ); - MBEDTLS_X509_SAFE_SNPRINTF; - - /* Key size */ - if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, - mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) - { - return( ret ); + return( ret ); } ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, @@ -1819,7 +1848,7 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, break; } - if( x509_profile_check_key( profile, crl_list->sig_pk, &ca->pk ) != 0 ) + if( x509_profile_check_key( profile, &ca->pk ) != 0 ) flags |= MBEDTLS_X509_BADCERT_BAD_KEY; if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, @@ -1855,16 +1884,52 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, } #endif /* MBEDTLS_X509_CRL_PARSE_C */ +/* + * Check the signature of a certificate by its parent + */ +static int x509_crt_check_signature( const mbedtls_x509_crt *child, + mbedtls_x509_crt *parent, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + const mbedtls_md_info_t *md_info; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + + /* Skip expensive computation on obvious mismatch */ + if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) ) + return( -1 ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA ) + { + return( mbedtls_pk_verify_restartable( &parent->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len, &rs_ctx->pk ) ); + } +#else + (void) rs_ctx; +#endif + + return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) ); +} + /* * Check if 'parent' is a suitable parent (signing CA) for 'child'. * Return 0 if yes, -1 if not. * * top means parent is a locally-trusted certificate - * bottom means child is the end entity cert */ static int x509_crt_check_parent( const mbedtls_x509_crt *child, const mbedtls_x509_crt *parent, - int top, int bottom ) + int top ) { int need_ca_bit; @@ -1879,14 +1944,6 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child, if( top && parent->version < 3 ) need_ca_bit = 0; - /* Exception: self-signed end-entity certs that are locally trusted. */ - if( top && bottom && - child->raw.len == parent->raw.len && - memcmp( child->raw.p, parent->raw.p, child->raw.len ) == 0 ) - { - need_ca_bit = 0; - } - if( need_ca_bit && ! parent->ca_istrue ) return( -1 ); @@ -1902,301 +1959,538 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child, } /* - * Verify a certificate with no parent inside the chain - * (either the parent is a trusted root, or there is no parent) + * Find a suitable parent for child in candidates, or return NULL. + * + * Here suitable is defined as: + * 1. subject name matches child's issuer + * 2. if necessary, the CA bit is set and key usage allows signing certs + * 3. for trusted roots, the signature is correct + * (for intermediates, the signature is checked and the result reported) + * 4. pathlen constraints are satisfied + * + * If there's a suitable candidate which is also time-valid, return the first + * such. Otherwise, return the first suitable candidate (or NULL if there is + * none). * - * See comments for mbedtls_x509_crt_verify_with_profile() - * (also for notation used below) + * The rationale for this rule is that someone could have a list of trusted + * roots with two versions on the same root with different validity periods. + * (At least one user reported having such a list and wanted it to just work.) + * The reason we don't just require time-validity is that generally there is + * only one version, and if it's expired we want the flags to state that + * rather than NOT_TRUSTED, as would be the case if we required it here. * - * This function is called in two cases: - * - child was found to have a parent in trusted roots, in which case we're - * called with trust_ca pointing directly to that parent (not the full list) - * - this is cases 1, 2 and 3 of the comment on verify_with_profile() - * - case 1 is special as child and trust_ca point to copies of the same - * certificate then - * - child was found to have no parent either in the chain or in trusted CAs - * - this is cases 4 and 5 of the comment on verify_with_profile() + * The rationale for rule 3 (signature for trusted roots) is that users might + * have two versions of the same CA with different keys in their list, and the + * way we select the correct one is by checking the signature (as we don't + * rely on key identifier extensions). (This is one way users might choose to + * handle key rollover, another relies on self-issued certs, see [SIRO].) * - * For historical reasons, the function currently does not assume that - * trust_ca points directly to the right root in the first case, and it - * doesn't know in which case it starts, so it always starts by searching for - * a parent in trust_ca. + * Arguments: + * - [in] child: certificate for which we're looking for a parent + * - [in] candidates: chained list of potential parents + * - [out] r_parent: parent found (or NULL) + * - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0 + * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top + * of the chain, 0 otherwise + * - [in] path_cnt: number of intermediates seen so far + * - [in] self_cnt: number of self-signed intermediates seen so far + * (will never be greater than path_cnt) + * - [in-out] rs_ctx: context for restarting operations + * + * Return value: + * - 0 on success + * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise */ -static int x509_crt_verify_top( - mbedtls_x509_crt *child, mbedtls_x509_crt *trust_ca, - mbedtls_x509_crl *ca_crl, - const mbedtls_x509_crt_profile *profile, - int path_cnt, int self_cnt, uint32_t *flags, - int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), - void *p_vrfy ) +static int x509_crt_find_parent_in( + mbedtls_x509_crt *child, + mbedtls_x509_crt *candidates, + mbedtls_x509_crt **r_parent, + int *r_signature_is_good, + int top, + unsigned path_cnt, + unsigned self_cnt, + mbedtls_x509_crt_restart_ctx *rs_ctx ) { int ret; - uint32_t ca_flags = 0; - int check_path_cnt; - unsigned char hash[MBEDTLS_MD_MAX_SIZE]; - const mbedtls_md_info_t *md_info; - mbedtls_x509_crt *future_past_ca = NULL; - - if( mbedtls_x509_time_is_past( &child->valid_to ) ) - *flags |= MBEDTLS_X509_BADCERT_EXPIRED; - - if( mbedtls_x509_time_is_future( &child->valid_from ) ) - *flags |= MBEDTLS_X509_BADCERT_FUTURE; + mbedtls_x509_crt *parent, *fallback_parent; + int signature_is_good, fallback_signature_is_good; - if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_MD; - - if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_PK; +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* did we have something in progress? */ + if( rs_ctx != NULL && rs_ctx->parent != NULL ) + { + /* restore saved state */ + parent = rs_ctx->parent; + fallback_parent = rs_ctx->fallback_parent; + fallback_signature_is_good = rs_ctx->fallback_signature_is_good; - /* - * Child is the top of the chain. Check against the trust_ca list. - */ - *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + /* clear saved state */ + rs_ctx->parent = NULL; + rs_ctx->fallback_parent = NULL; + rs_ctx->fallback_signature_is_good = 0; - md_info = mbedtls_md_info_from_type( child->sig_md ); - if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) - { - /* Note: this can't happen except after an internal error */ - /* Cannot check signature, no need to try any CA */ - trust_ca = NULL; + /* resume where we left */ + goto check_signature; } +#endif + + fallback_parent = NULL; + fallback_signature_is_good = 0; - for( /* trust_ca */ ; trust_ca != NULL; trust_ca = trust_ca->next ) + for( parent = candidates; parent != NULL; parent = parent->next ) { - if( x509_crt_check_parent( child, trust_ca, 1, path_cnt == 0 ) != 0 ) + /* basic parenting skills (name, CA bit, key usage) */ + if( x509_crt_check_parent( child, parent, top ) != 0 ) continue; - check_path_cnt = path_cnt + 1; - - /* - * Reduce check_path_cnt to check against if top of the chain is - * the same as the trusted CA - */ - if( child->subject_raw.len == trust_ca->subject_raw.len && - memcmp( child->subject_raw.p, trust_ca->subject_raw.p, - child->subject_raw.len ) == 0 ) + /* +1 because stored max_pathlen is 1 higher that the actual value */ + if( parent->max_pathlen > 0 && + (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) { - check_path_cnt--; + continue; } - /* Self signed certificates do not count towards the limit */ - if( trust_ca->max_pathlen > 0 && - trust_ca->max_pathlen < check_path_cnt - self_cnt ) + /* Signature */ +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +check_signature: +#endif + ret = x509_crt_check_signature( child, parent, rs_ctx ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) { - continue; + /* save state */ + rs_ctx->parent = parent; + rs_ctx->fallback_parent = fallback_parent; + rs_ctx->fallback_signature_is_good = fallback_signature_is_good; + + return( ret ); } +#else + (void) ret; +#endif - if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &trust_ca->pk, - child->sig_md, hash, mbedtls_md_get_size( md_info ), - child->sig.p, child->sig.len ) != 0 ) - { + signature_is_good = ret == 0; + if( top && ! signature_is_good ) continue; - } - if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) || - mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) + /* optional time check */ + if( mbedtls_x509_time_is_past( &parent->valid_to ) || + mbedtls_x509_time_is_future( &parent->valid_from ) ) { - if ( future_past_ca == NULL ) - future_past_ca = trust_ca; + if( fallback_parent == NULL ) + { + fallback_parent = parent; + fallback_signature_is_good = signature_is_good; + } continue; } + *r_parent = parent; + *r_signature_is_good = signature_is_good; + break; } - if( trust_ca != NULL || ( trust_ca = future_past_ca ) != NULL ) + if( parent == NULL ) { - /* - * Top of chain is signed by a trusted CA - */ - *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; - - if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + *r_parent = fallback_parent; + *r_signature_is_good = fallback_signature_is_good; } - /* - * If top of chain is not the same as the trusted CA send a verify request - * to the callback for any issues with validity and CRL presence for the - * trusted CA certificate. - */ - if( trust_ca != NULL && - ( child->subject_raw.len != trust_ca->subject_raw.len || - memcmp( child->subject_raw.p, trust_ca->subject_raw.p, - child->subject_raw.len ) != 0 ) ) + return( 0 ); +} + +/* + * Find a parent in trusted CAs or the provided chain, or return NULL. + * + * Searches in trusted CAs first, and return the first suitable parent found + * (see find_parent_in() for definition of suitable). + * + * Arguments: + * - [in] child: certificate for which we're looking for a parent, followed + * by a chain of possible intermediates + * - [in] trust_ca: list of locally trusted certificates + * - [out] parent: parent found (or NULL) + * - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0 + * - [out] signature_is_good: 1 if child signature by parent is valid, or 0 + * - [in] path_cnt: number of links in the chain so far (EE -> ... -> child) + * - [in] self_cnt: number of self-signed certs in the chain so far + * (will always be no greater than path_cnt) + * - [in-out] rs_ctx: context for restarting operations + * + * Return value: + * - 0 on success + * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise + */ +static int x509_crt_find_parent( + mbedtls_x509_crt *child, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crt **parent, + int *parent_is_trusted, + int *signature_is_good, + unsigned path_cnt, + unsigned self_cnt, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_x509_crt *search_list; + + *parent_is_trusted = 1; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* restore then clear saved state if we have some stored */ + if( rs_ctx != NULL && rs_ctx->parent_is_trusted != -1 ) { -#if defined(MBEDTLS_X509_CRL_PARSE_C) - /* Check trusted CA's CRL for the chain's top crt */ - *flags |= x509_crt_verifycrl( child, trust_ca, ca_crl, profile ); -#else - ((void) ca_crl); + *parent_is_trusted = rs_ctx->parent_is_trusted; + rs_ctx->parent_is_trusted = -1; + } #endif - if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) ) - ca_flags |= MBEDTLS_X509_BADCERT_EXPIRED; + while( 1 ) { + search_list = *parent_is_trusted ? trust_ca : child->next; - if( mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) - ca_flags |= MBEDTLS_X509_BADCERT_FUTURE; + ret = x509_crt_find_parent_in( child, search_list, + parent, signature_is_good, + *parent_is_trusted, + path_cnt, self_cnt, rs_ctx ); - if( NULL != f_vrfy ) +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) { - if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, - &ca_flags ) ) != 0 ) - { - return( ret ); - } + /* save state */ + rs_ctx->parent_is_trusted = *parent_is_trusted; + return( ret ); } +#else + (void) ret; +#endif + + /* stop here if found or already in second iteration */ + if( *parent != NULL || *parent_is_trusted == 0 ) + break; + + /* prepare second iteration */ + *parent_is_trusted = 0; } - /* Call callback on top cert */ - if( NULL != f_vrfy ) + /* extra precaution against mistakes in the caller */ + if( *parent == NULL ) { - if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) - return( ret ); + *parent_is_trusted = 0; + *signature_is_good = 0; } - *flags |= ca_flags; - return( 0 ); } /* - * Verify a certificate with a parent inside the chain + * Check if an end-entity certificate is locally trusted * - * See comments for mbedtls_x509_crt_verify_with_profile() + * Currently we require such certificates to be self-signed (actually only + * check for self-issued as self-signatures are not checked) */ -static int x509_crt_verify_child( - mbedtls_x509_crt *child, mbedtls_x509_crt *parent, - mbedtls_x509_crt *trust_ca, mbedtls_x509_crl *ca_crl, - const mbedtls_x509_crt_profile *profile, - int path_cnt, int self_cnt, uint32_t *flags, - int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), - void *p_vrfy ) +static int x509_crt_check_ee_locally_trusted( + mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca ) { - int ret; - uint32_t parent_flags = 0; - unsigned char hash[MBEDTLS_MD_MAX_SIZE]; - mbedtls_x509_crt *grandparent; - const mbedtls_md_info_t *md_info; + mbedtls_x509_crt *cur; - /* Counting intermediate self signed certificates */ - if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 ) - self_cnt++; + /* must be self-issued */ + if( x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) + return( -1 ); - /* path_cnt is 0 for the first intermediate CA */ - if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) + /* look for an exact match with trusted cert */ + for( cur = trust_ca; cur != NULL; cur = cur->next ) { - /* return immediately as the goal is to avoid unbounded recursion */ - return( MBEDTLS_ERR_X509_FATAL_ERROR ); + if( crt->raw.len == cur->raw.len && + memcmp( crt->raw.p, cur->raw.p, crt->raw.len ) == 0 ) + { + return( 0 ); + } } - if( mbedtls_x509_time_is_past( &child->valid_to ) ) - *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + /* too bad */ + return( -1 ); +} - if( mbedtls_x509_time_is_future( &child->valid_from ) ) - *flags |= MBEDTLS_X509_BADCERT_FUTURE; +/* + * Build and verify a certificate chain + * + * Given a peer-provided list of certificates EE, C1, ..., Cn and + * a list of trusted certs R1, ... Rp, try to build and verify a chain + * EE, Ci1, ... Ciq [, Rj] + * such that every cert in the chain is a child of the next one, + * jumping to a trusted root as early as possible. + * + * Verify that chain and return it with flags for all issues found. + * + * Special cases: + * - EE == Rj -> return a one-element list containing it + * - EE, Ci1, ..., Ciq cannot be continued with a trusted root + * -> return that chain with NOT_TRUSTED set on Ciq + * + * Tests for (aspects of) this function should include at least: + * - trusted EE + * - EE -> trusted root + * - EE -> intermediate CA -> trusted root + * - if relevant: EE untrusted + * - if relevant: EE -> intermediate, untrusted + * with the aspect under test checked at each relevant level (EE, int, root). + * For some aspects longer chains are required, but usually length 2 is + * enough (but length 1 is not in general). + * + * Arguments: + * - [in] crt: the cert list EE, C1, ..., Cn + * - [in] trust_ca: the trusted list R1, ..., Rp + * - [in] ca_crl, profile: as in verify_with_profile() + * - [out] ver_chain: the built and verified chain + * Only valid when return value is 0, may contain garbage otherwise! + * Restart note: need not be the same when calling again to resume. + * - [in-out] rs_ctx: context for restarting operations + * + * Return value: + * - non-zero if the chain could not be fully built and examined + * - 0 is the chain was successfully built and examined, + * even if it was found to be invalid + */ +static int x509_crt_verify_chain( + mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + mbedtls_x509_crt_verify_chain *ver_chain, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + /* Don't initialize any of those variables here, so that the compiler can + * catch potential issues with jumping ahead when restarting */ + int ret; + uint32_t *flags; + mbedtls_x509_crt_verify_chain_item *cur; + mbedtls_x509_crt *child; + mbedtls_x509_crt *parent; + int parent_is_trusted; + int child_is_trusted; + int signature_is_good; + unsigned self_cnt; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* resume if we had an operation in progress */ + if( rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent ) + { + /* restore saved state */ + *ver_chain = rs_ctx->ver_chain; /* struct copy */ + self_cnt = rs_ctx->self_cnt; + + /* restore derived state */ + cur = &ver_chain->items[ver_chain->len - 1]; + child = cur->crt; + flags = &cur->flags; + + goto find_parent; + } +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + + child = crt; + self_cnt = 0; + parent_is_trusted = 0; + child_is_trusted = 0; + + while( 1 ) { + /* Add certificate to the verification chain */ + cur = &ver_chain->items[ver_chain->len]; + cur->crt = child; + cur->flags = 0; + ver_chain->len++; + flags = &cur->flags; + + /* Check time-validity (all certificates) */ + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + /* Stop here for trusted roots (but not for trusted EE certs) */ + if( child_is_trusted ) + return( 0 ); - if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + /* Check signature algorithm: MD & PK algs */ + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; - if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; - md_info = mbedtls_md_info_from_type( child->sig_md ); - if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) - { - /* Note: this can't happen except after an internal error */ - *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; - } - else - { - if( x509_profile_check_key( profile, child->sig_pk, &parent->pk ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + /* Special case: EE certs that are locally trusted */ + if( ver_chain->len == 1 && + x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) + { + return( 0 ); + } + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +find_parent: +#endif + /* Look for a parent in trusted CAs or up the chain */ + ret = x509_crt_find_parent( child, trust_ca, &parent, + &parent_is_trusted, &signature_is_good, + ver_chain->len - 1, self_cnt, rs_ctx ); - if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, - child->sig_md, hash, mbedtls_md_get_size( md_info ), - child->sig.p, child->sig.len ) != 0 ) +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + /* save state */ + rs_ctx->in_progress = x509_crt_rs_find_parent; + rs_ctx->self_cnt = self_cnt; + rs_ctx->ver_chain = *ver_chain; /* struct copy */ + + return( ret ); + } +#else + (void) ret; +#endif + + /* No parent? We're done here */ + if( parent == NULL ) { *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + return( 0 ); + } + + /* Count intermediate self-issued (not necessarily self-signed) certs. + * These can occur with some strategies for key rollover, see [SIRO], + * and should be excluded from max_pathlen checks. */ + if( ver_chain->len != 1 && + x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + { + self_cnt++; } - } + + /* path_cnt is 0 for the first intermediate CA, + * and if parent is trusted it's not an intermediate CA */ + if( ! parent_is_trusted && + ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) + { + /* return immediately to avoid overflow the chain array */ + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + } + + /* signature was checked while searching parent */ + if( ! signature_is_good ) + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + /* check size of signing key */ + if( x509_profile_check_key( profile, &parent->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; #if defined(MBEDTLS_X509_CRL_PARSE_C) - /* Check trusted CA's CRL for the given crt */ - *flags |= x509_crt_verifycrl(child, parent, ca_crl, profile ); + /* Check trusted CA's CRL for the given crt */ + *flags |= x509_crt_verifycrl( child, parent, ca_crl, profile ); +#else + (void) ca_crl; #endif - /* Look for a grandparent in trusted CAs */ - for( grandparent = trust_ca; - grandparent != NULL; - grandparent = grandparent->next ) + /* prepare for next iteration */ + child = parent; + parent = NULL; + child_is_trusted = parent_is_trusted; + signature_is_good = 0; + } +} + +/* + * Check for CN match + */ +static int x509_crt_check_cn( const mbedtls_x509_buf *name, + const char *cn, size_t cn_len ) +{ + /* try exact match */ + if( name->len == cn_len && + x509_memcasecmp( cn, name->p, cn_len ) == 0 ) { - if( x509_crt_check_parent( parent, grandparent, - 0, path_cnt == 0 ) == 0 ) - break; + return( 0 ); } - if( grandparent != NULL ) + /* try wildcard match */ + if( x509_check_wildcard( cn, name ) == 0 ) { - ret = x509_crt_verify_top( parent, grandparent, ca_crl, profile, - path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); - if( ret != 0 ) - return( ret ); + return( 0 ); } - else + + return( -1 ); +} + +/* + * Verify the requested CN - only call this if cn is not NULL! + */ +static void x509_crt_verify_name( const mbedtls_x509_crt *crt, + const char *cn, + uint32_t *flags ) +{ + const mbedtls_x509_name *name; + const mbedtls_x509_sequence *cur; + size_t cn_len = strlen( cn ); + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { - /* Look for a grandparent upwards the chain */ - for( grandparent = parent->next; - grandparent != NULL; - grandparent = grandparent->next ) + for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next ) { - /* +2 because the current step is not yet accounted for - * and because max_pathlen is one higher than it should be. - * Also self signed certificates do not count to the limit. */ - if( grandparent->max_pathlen > 0 && - grandparent->max_pathlen < 2 + path_cnt - self_cnt ) - { - continue; - } - - if( x509_crt_check_parent( parent, grandparent, - 0, path_cnt == 0 ) == 0 ) + if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 ) break; } - /* Is our parent part of the chain or at the top? */ - if( grandparent != NULL ) - { - ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, - profile, path_cnt + 1, self_cnt, &parent_flags, - f_vrfy, p_vrfy ); - if( ret != 0 ) - return( ret ); - } - else + if( cur == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + else + { + for( name = &crt->subject; name != NULL; name = name->next ) { - ret = x509_crt_verify_top( parent, trust_ca, ca_crl, profile, - path_cnt + 1, self_cnt, &parent_flags, - f_vrfy, p_vrfy ); - if( ret != 0 ) - return( ret ); + if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 && + x509_crt_check_cn( &name->val, cn, cn_len ) == 0 ) + { + break; + } } + + if( name == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; } +} - /* child is verified to be a child of the parent, call verify callback */ - if( NULL != f_vrfy ) - if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) - return( ret ); +/* + * Merge the flags for all certs in the chain, after calling callback + */ +static int x509_crt_merge_flags_with_cb( + uint32_t *flags, + const mbedtls_x509_crt_verify_chain *ver_chain, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + unsigned i; + uint32_t cur_flags; + const mbedtls_x509_crt_verify_chain_item *cur; - *flags |= parent_flags; + for( i = ver_chain->len; i != 0; --i ) + { + cur = &ver_chain->items[i-1]; + cur_flags = cur->flags; + + if( NULL != f_vrfy ) + if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 ) + return( ret ); + + *flags |= cur_flags; + } return( 0 ); } /* - * Verify the certificate validity + * Verify the certificate validity (default profile, not restartable) */ int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, mbedtls_x509_crt *trust_ca, @@ -2205,41 +2499,13 @@ int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), void *p_vrfy ) { - return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl, - &mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) ); + return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl, + &mbedtls_x509_crt_profile_default, cn, flags, + f_vrfy, p_vrfy, NULL ) ); } - /* - * Verify the certificate validity, with profile - * - * The chain building/verification is spread accross 4 functions: - * - this one - * - x509_crt_verify_child() - * - x509_crt_verify_top() - * - x509_crt_check_parent() - * - * There are five main cases to consider. Let's introduce some notation: - * - E means the end-entity certificate - * - I an intermediate CA - * - R the trusted root CA this chain anchors to - * - T the list of trusted roots (R and possible some others) - * - * The main cases with the calling sequence of the crt_verify_xxx() are: - * 1. E = R (explicitly trusted EE cert) - * verify(E, T) -> verify_top(E, R) - * 2. E -> R (EE signed by trusted root) - * verify(E, T) -> verify_top(E, R) - * 3. E -> I -> R (EE signed by intermediate signed by trusted root) - * verify(E, T) -> verify_child(E, I, T) -> verify_top(I, R) - * (plus variant with multiple intermediates) - * 4. E -> I (EE signed by intermediate that's not trusted) - * verify(E, T) -> verify_child(E, I, T) -> verify_top(I, T) - * (plus variant with multiple intermediates) - * 5. E (EE not trusted) - * verify(E, T) -> verify_top(E, T) - * - * Note: this notation and case numbering is also used in x509_crt_verify_top() + * Verify the certificate validity (user-chosen profile, not restartable) */ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, mbedtls_x509_crt *trust_ca, @@ -2249,15 +2515,37 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), void *p_vrfy ) { - size_t cn_len; + return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl, + profile, cn, flags, f_vrfy, p_vrfy, NULL ) ); +} + +/* + * Verify the certificate validity, with profile, restartable version + * + * This function: + * - checks the requested CN (if any) + * - checks the type and size of the EE cert's key, + * as that isn't done as part of chain building/verification currently + * - builds and verifies the chain + * - then calls the callback and merges the flags + */ +int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ int ret; - int pathlen = 0, selfsigned = 0; - mbedtls_x509_crt *parent; - mbedtls_x509_name *name; - mbedtls_x509_sequence *cur = NULL; mbedtls_pk_type_t pk_type; + mbedtls_x509_crt_verify_chain ver_chain; + uint32_t ee_flags; *flags = 0; + ee_flags = 0; + x509_crt_verify_chain_reset( &ver_chain ); if( profile == NULL ) { @@ -2265,106 +2553,38 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, goto exit; } + /* check name if requested */ if( cn != NULL ) - { - name = &crt->subject; - cn_len = strlen( cn ); - - if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) - { - cur = &crt->subject_alt_names; - - while( cur != NULL ) - { - if( cur->buf.len == cn_len && - x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) - break; - - if( cur->buf.len > 2 && - memcmp( cur->buf.p, "*.", 2 ) == 0 && - x509_check_wildcard( cn, &cur->buf ) == 0 ) - { - break; - } - - cur = cur->next; - } - - if( cur == NULL ) - *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; - } - else - { - while( name != NULL ) - { - if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 ) - { - if( name->val.len == cn_len && - x509_memcasecmp( name->val.p, cn, cn_len ) == 0 ) - break; - - if( name->val.len > 2 && - memcmp( name->val.p, "*.", 2 ) == 0 && - x509_check_wildcard( cn, &name->val ) == 0 ) - break; - } - - name = name->next; - } - - if( name == NULL ) - *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; - } - } + x509_crt_verify_name( crt, cn, &ee_flags ); /* Check the type and size of the key */ pk_type = mbedtls_pk_get_type( &crt->pk ); if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; - if( x509_profile_check_key( profile, pk_type, &crt->pk ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + if( x509_profile_check_key( profile, &crt->pk ) != 0 ) + ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; - /* Look for a parent in trusted CAs */ - for( parent = trust_ca; parent != NULL; parent = parent->next ) - { - if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) - break; - } + /* Check the chain */ + ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, profile, + &ver_chain, rs_ctx ); - if( parent != NULL ) - { - ret = x509_crt_verify_top( crt, parent, ca_crl, profile, - pathlen, selfsigned, flags, f_vrfy, p_vrfy ); - if( ret != 0 ) - goto exit; - } - else - { - /* Look for a parent upwards the chain */ - for( parent = crt->next; parent != NULL; parent = parent->next ) - if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) - break; + if( ret != 0 ) + goto exit; - /* Are we part of the chain or at the top? */ - if( parent != NULL ) - { - ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile, - pathlen, selfsigned, flags, f_vrfy, p_vrfy ); - if( ret != 0 ) - goto exit; - } - else - { - ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile, - pathlen, selfsigned, flags, f_vrfy, p_vrfy ); - if( ret != 0 ) - goto exit; - } - } + /* Merge end-entity flags */ + ver_chain.items[0].flags |= ee_flags; + + /* Build final flags, calling callback on the way if any */ + ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy ); exit: +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) + mbedtls_x509_crt_restart_free( rs_ctx ); +#endif + /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by * the SSL module for authmode optional, but non-zero return from the * callback means a fatal error so it shouldn't be ignored */ @@ -2419,7 +2639,7 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) { name_prv = name_cur; name_cur = name_cur->next; - mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); mbedtls_free( name_prv ); } @@ -2428,7 +2648,7 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) { name_prv = name_cur; name_cur = name_cur->next; - mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); mbedtls_free( name_prv ); } @@ -2437,7 +2657,8 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) { seq_prv = seq_cur; seq_cur = seq_cur->next; - mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); mbedtls_free( seq_prv ); } @@ -2446,13 +2667,14 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) { seq_prv = seq_cur; seq_cur = seq_cur->next; - mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); mbedtls_free( seq_prv ); } if( cert_cur->raw.p != NULL ) { - mbedtls_zeroize( cert_cur->raw.p, cert_cur->raw.len ); + mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len ); mbedtls_free( cert_cur->raw.p ); } @@ -2466,11 +2688,43 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) cert_prv = cert_cur; cert_cur = cert_cur->next; - mbedtls_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); + mbedtls_platform_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); if( cert_prv != crt ) mbedtls_free( cert_prv ); } while( cert_cur != NULL ); } +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Initialize a restart context + */ +void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ) +{ + mbedtls_pk_restart_init( &ctx->pk ); + + ctx->parent = NULL; + ctx->fallback_parent = NULL; + ctx->fallback_signature_is_good = 0; + + ctx->parent_is_trusted = -1; + + ctx->in_progress = x509_crt_rs_none; + ctx->self_cnt = 0; + x509_crt_verify_chain_reset( &ctx->ver_chain ); +} + +/* + * Free the components of a restart context + */ +void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_pk_restart_free( &ctx->pk ); + mbedtls_x509_crt_restart_init( ctx ); +} +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + #endif /* MBEDTLS_X509_CRT_PARSE_C */ diff --git a/app/mbedtls/library/x509_csr.c b/app/mbedtls/library/x509_csr.c index 779098d4e9..c8c08c87b2 100644 --- a/app/mbedtls/library/x509_csr.c +++ b/app/mbedtls/library/x509_csr.c @@ -39,6 +39,7 @@ #include "mbedtls/x509_csr.h" #include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" #include @@ -60,11 +61,6 @@ #include #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * Version ::= INTEGER { v1(0) } */ @@ -283,15 +279,24 @@ int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, siz { mbedtls_pem_init( &pem ); ret = mbedtls_pem_read_buffer( &pem, - "-----BEGIN CERTIFICATE REQUEST-----", - "-----END CERTIFICATE REQUEST-----", - buf, NULL, 0, &use_len ); + "-----BEGIN CERTIFICATE REQUEST-----", + "-----END CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + if( ret == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN NEW CERTIFICATE REQUEST-----", + "-----END NEW CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + } if( ret == 0 ) + { /* * Was PEM encoded, parse the result */ ret = mbedtls_x509_csr_parse_der( csr, pem.buf, pem.buflen ); + } mbedtls_pem_free( &pem ); if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) @@ -316,7 +321,7 @@ int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path ) ret = mbedtls_x509_csr_parse( csr, buf, n ); - mbedtls_zeroize( buf, n ); + mbedtls_platform_zeroize( buf, n ); mbedtls_free( buf ); return( ret ); @@ -398,17 +403,17 @@ void mbedtls_x509_csr_free( mbedtls_x509_csr *csr ) { name_prv = name_cur; name_cur = name_cur->next; - mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); mbedtls_free( name_prv ); } if( csr->raw.p != NULL ) { - mbedtls_zeroize( csr->raw.p, csr->raw.len ); + mbedtls_platform_zeroize( csr->raw.p, csr->raw.len ); mbedtls_free( csr->raw.p ); } - mbedtls_zeroize( csr, sizeof( mbedtls_x509_csr ) ); + mbedtls_platform_zeroize( csr, sizeof( mbedtls_x509_csr ) ); } #endif /* MBEDTLS_X509_CSR_PARSE_C */ diff --git a/app/mbedtls/library/x509write_crt.c b/app/mbedtls/library/x509write_crt.c index 41dfe87b75..61d7ba44a0 100644 --- a/app/mbedtls/library/x509write_crt.c +++ b/app/mbedtls/library/x509write_crt.c @@ -37,6 +37,7 @@ #include "mbedtls/oid.h" #include "mbedtls/asn1write.h" #include "mbedtls/sha1.h" +#include "mbedtls/platform_util.h" #include @@ -44,10 +45,15 @@ #include "mbedtls/pem.h" #endif /* MBEDTLS_PEM_WRITE_C */ -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +/* + * For the currently used signature algorithms the buffer to store any signature + * must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE) + */ +#if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE +#define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN +#else +#define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE +#endif void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ) { @@ -65,7 +71,7 @@ void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ) mbedtls_asn1_free_named_data_list( &ctx->issuer ); mbedtls_asn1_free_named_data_list( &ctx->extensions ); - mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_cert ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_cert ) ); } void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ) @@ -222,26 +228,51 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert * } #endif /* MBEDTLS_SHA1_C */ +static size_t crt_get_unused_bits_for_named_bitstring( unsigned char bitstring, + size_t bit_offset ) +{ + size_t unused_bits; + + /* Count the unused bits removing trailing 0s */ + for( unused_bits = bit_offset; unused_bits < 8; unused_bits++ ) + if( ( ( bitstring >> unused_bits ) & 0x1 ) != 0 ) + break; + + return( unused_bits ); +} + int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, unsigned int key_usage ) { unsigned char buf[4], ku; unsigned char *c; int ret; - - /* We currently only support 7 bits, from 0x80 to 0x02 */ - if( ( key_usage & ~0xfe ) != 0 ) + size_t unused_bits; + const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE | + MBEDTLS_X509_KU_NON_REPUDIATION | + MBEDTLS_X509_KU_KEY_ENCIPHERMENT | + MBEDTLS_X509_KU_DATA_ENCIPHERMENT | + MBEDTLS_X509_KU_KEY_AGREEMENT | + MBEDTLS_X509_KU_KEY_CERT_SIGN | + MBEDTLS_X509_KU_CRL_SIGN; + + /* Check that nothing other than the allowed flags is set */ + if( ( key_usage & ~allowed_bits ) != 0 ) return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); c = buf + 4; - ku = (unsigned char) key_usage; + ku = (unsigned char)key_usage; + unused_bits = crt_get_unused_bits_for_named_bitstring( ku, 1 ); + ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 8 - unused_bits ); - if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 ) + if( ret < 0 ) return( ret ); + else if( ret < 3 || ret > 4 ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), - 1, buf, 4 ); + 1, c, (size_t)ret ); if( ret != 0 ) return( ret ); @@ -253,16 +284,22 @@ int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, { unsigned char buf[4]; unsigned char *c; + size_t unused_bits; int ret; c = buf + 4; - if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + unused_bits = crt_get_unused_bits_for_named_bitstring( ns_cert_type, 0 ); + ret = mbedtls_asn1_write_bitstring( &c, + buf, + &ns_cert_type, + 8 - unused_bits ); + if( ret < 3 || ret > 4 ) return( ret ); ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), - 0, buf, 4 ); + 0, c, (size_t)ret ); if( ret != 0 ) return( ret ); @@ -307,7 +344,7 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t sig_oid_len = 0; unsigned char *c, *c2; unsigned char hash[64]; - unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char sig[SIGNATURE_MAX_SIZE]; unsigned char tmp_buf[2048]; size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len; size_t len = 0; diff --git a/app/mbedtls/library/x509write_csr.c b/app/mbedtls/library/x509write_csr.c index e80053828f..b65a11c6aa 100644 --- a/app/mbedtls/library/x509write_csr.c +++ b/app/mbedtls/library/x509write_csr.c @@ -35,6 +35,7 @@ #include "mbedtls/x509_csr.h" #include "mbedtls/oid.h" #include "mbedtls/asn1write.h" +#include "mbedtls/platform_util.h" #include #include @@ -43,10 +44,15 @@ #include "mbedtls/pem.h" #endif -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} +/* + * For the currently used signature algorithms the buffer to store any signature + * must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE) + */ +#if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE +#define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN +#else +#define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE +#endif void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) { @@ -58,7 +64,7 @@ void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) mbedtls_asn1_free_named_data_list( &ctx->subject ); mbedtls_asn1_free_named_data_list( &ctx->extensions ); - mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_csr ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_csr ) ); } void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ) @@ -85,20 +91,39 @@ int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, 0, val, val_len ); } +static size_t csr_get_unused_bits_for_named_bitstring( unsigned char bitstring, + size_t bit_offset ) +{ + size_t unused_bits; + + /* Count the unused bits removing trailing 0s */ + for( unused_bits = bit_offset; unused_bits < 8; unused_bits++ ) + if( ( ( bitstring >> unused_bits ) & 0x1 ) != 0 ) + break; + + return( unused_bits ); +} + int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ) { unsigned char buf[4]; unsigned char *c; + size_t unused_bits; int ret; c = buf + 4; - if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 ) + unused_bits = csr_get_unused_bits_for_named_bitstring( key_usage, 0 ); + ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 8 - unused_bits ); + + if( ret < 0 ) return( ret ); + else if( ret < 3 || ret > 4 ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), - buf, 4 ); + c, (size_t)ret ); if( ret != 0 ) return( ret ); @@ -110,16 +135,25 @@ int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, { unsigned char buf[4]; unsigned char *c; + size_t unused_bits; int ret; c = buf + 4; - if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + unused_bits = csr_get_unused_bits_for_named_bitstring( ns_cert_type, 0 ); + ret = mbedtls_asn1_write_bitstring( &c, + buf, + &ns_cert_type, + 8 - unused_bits ); + + if( ret < 0 ) + return( ret ); + else if( ret < 3 || ret > 4 ) return( ret ); ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), - buf, 4 ); + c, (size_t)ret ); if( ret != 0 ) return( ret ); @@ -135,7 +169,7 @@ int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, s size_t sig_oid_len = 0; unsigned char *c, *c2; unsigned char hash[64]; - unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char sig[SIGNATURE_MAX_SIZE]; unsigned char tmp_buf[2048]; size_t pub_len = 0, sig_and_oid_len = 0, sig_len; size_t len = 0; diff --git a/app/mbedtls/library/xtea.c b/app/mbedtls/library/xtea.c index fe0a3509f6..a33707bc17 100644 --- a/app/mbedtls/library/xtea.c +++ b/app/mbedtls/library/xtea.c @@ -28,6 +28,7 @@ #if defined(MBEDTLS_XTEA_C) #include "mbedtls/xtea.h" +#include "mbedtls/platform_util.h" #include @@ -42,11 +43,6 @@ #if !defined(MBEDTLS_XTEA_ALT) -/* Implementation that should never be optimized out by the compiler */ -static void mbedtls_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - /* * 32-bit integer manipulation macros (big endian) */ @@ -80,7 +76,7 @@ void mbedtls_xtea_free( mbedtls_xtea_context *ctx ) if( ctx == NULL ) return; - mbedtls_zeroize( ctx, sizeof( mbedtls_xtea_context ) ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_xtea_context ) ); } /* diff --git a/app/mbedtls/platform/mbedtls_mem.c b/app/mbedtls/platform/mbedtls_mem.c deleted file mode 100644 index 9281362f05..0000000000 --- a/app/mbedtls/platform/mbedtls_mem.c +++ /dev/null @@ -1,4 +0,0 @@ -#include - -void *mbedtls_calloc(size_t n, size_t sz) { return calloc(n, sz); } -void mbedtls_free(void *p) { free(p); } diff --git a/app/mbedtls/platform/mbedtls_net.c b/app/mbedtls/platform/mbedtls_net.c index e58053cf7d..03cf22a2d6 100644 --- a/app/mbedtls/platform/mbedtls_net.c +++ b/app/mbedtls/platform/mbedtls_net.c @@ -47,19 +47,6 @@ */ static int net_prepare( void ) { -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - WSADATA wsaData; - - if( wsa_init_done == 0 ) - { - if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) - return( MBEDTLS_ERR_NET_SOCKET_FAILED ); - - wsa_init_done = 1; - } -#else -#endif return( 0 ); } @@ -169,18 +156,6 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char } -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) -/* - * Check if the requested operation would be blocking on a non-blocking socket - * and thus 'failed' with a negative return value. - */ -static int net_would_block( const mbedtls_net_context *ctx ) -{ - ((void) ctx); - return( WSAGetLastError() == WSAEWOULDBLOCK ); -} -#else /* * Check if the requested operation would be blocking on a non-blocking socket * and thus 'failed' with a negative return value. @@ -189,25 +164,8 @@ static int net_would_block( const mbedtls_net_context *ctx ) */ static int net_would_block( const mbedtls_net_context *ctx ) { - /* - * Never return 'WOULD BLOCK' on a non-blocking socket - */ -// if( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK ) -// return( 0 ); - -// switch( errno ) -// { -//#if defined EAGAIN -// case EAGAIN: -//#endif -//#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN -// case EWOULDBLOCK: -//#endif -// return( 1 ); -// } return( 0 ); } -#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ /* * Accept a connection from a remote client @@ -256,44 +214,12 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, */ int mbedtls_net_set_block( mbedtls_net_context *ctx ) { -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - u_long n = 0; - return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); -#else return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) & ~O_NONBLOCK ) ); -#endif } int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) { -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - u_long n = 1; - return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); -#else return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) | O_NONBLOCK ) ); -#endif -} - -/* - * Portable usleep helper - */ -void mbedtls_net_usleep( unsigned long usec ) -{ -//#if defined(_WIN32) -// Sleep( ( usec + 999 ) / 1000 ); -//#else -// struct timeval tv; -// tv.tv_sec = usec / 1000000; -//#if defined(__unix__) || defined(__unix) || \ -// ( defined(__APPLE__) && defined(__MACH__) ) -// tv.tv_usec = (suseconds_t) usec % 1000000; -//#else -// tv.tv_usec = usec % 1000000; -//#endif -// select( 0, NULL, NULL, NULL, &tv ); -//#endif } /* @@ -315,18 +241,6 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) if( net_would_block( ctx ) != 0 ) return( MBEDTLS_ERR_SSL_WANT_READ ); -//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ -// !defined(EFI32) -// if( WSAGetLastError() == WSAECONNRESET ) -// return( MBEDTLS_ERR_NET_CONN_RESET ); -//#else -// if( errno == EPIPE || errno == ECONNRESET ) -// return( MBEDTLS_ERR_NET_CONN_RESET ); -// -// if( errno == EINTR ) -// return( MBEDTLS_ERR_SSL_WANT_READ ); -//#endif - return( MBEDTLS_ERR_NET_RECV_FAILED ); } // os_printf("mbedtls_net_recv get %d\n", ret); @@ -350,32 +264,6 @@ int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, if( fd < 0 ) return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); -// FD_ZERO( &read_fds ); -// FD_SET( fd, &read_fds ); -// -// tv.tv_sec = timeout / 1000; -// tv.tv_usec = ( timeout % 1000 ) * 1000; -// -// ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); -// -// /* Zero fds ready means we timed out */ -// if( ret == 0 ) -// return( MBEDTLS_ERR_SSL_TIMEOUT ); -// -// if( ret < 0 ) -// { -//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ -// !defined(EFI32) -// if( WSAGetLastError() == WSAEINTR ) -// return( MBEDTLS_ERR_SSL_WANT_READ ); -//#else -// if( errno == EINTR ) -// return( MBEDTLS_ERR_SSL_WANT_READ ); -//#endif -// -// return( MBEDTLS_ERR_NET_RECV_FAILED ); -// } - /* This call will not block */ return( mbedtls_net_recv( ctx, buf, len ) ); } @@ -398,20 +286,6 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) { if( net_would_block( ctx ) != 0 ) return( MBEDTLS_ERR_SSL_WANT_WRITE ); - -//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ -// !defined(EFI32) -// if( WSAGetLastError() == WSAECONNRESET ) -// return( MBEDTLS_ERR_NET_CONN_RESET ); -//#else -// if( errno == EPIPE || errno == ECONNRESET ) -// return( MBEDTLS_ERR_NET_CONN_RESET ); -// -// if( errno == EINTR ) -// return( MBEDTLS_ERR_SSL_WANT_WRITE ); -//#endif -// -// return( MBEDTLS_ERR_NET_SEND_FAILED ); } // os_printf("mbedtls_net_send write %d\n", ret); if (ret == 0) diff --git a/docs/modules/crypto.md b/docs/modules/crypto.md index 75bec7e357..db0e0b2bc4 100644 --- a/docs/modules/crypto.md +++ b/docs/modules/crypto.md @@ -10,7 +10,6 @@ The following encryption/decryption algorithms/modes are supported: - `"AES-CBC"` for 128-bit AES in CBC mode The following hash algorithms are supported: -- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`) - MD5 - SHA1 - SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`) diff --git a/docs/modules/tls.md b/docs/modules/tls.md index ebe300b942..1f142daca4 100644 --- a/docs/modules/tls.md +++ b/docs/modules/tls.md @@ -10,7 +10,7 @@ NodeMCU includes the open-source version of [mbed TLS library](https://tls.mbed.org/). -With the NodeMCU default configuration it supports **TLS** 1.1 and 1.2 with +With the NodeMCU default configuration it supports **TLS** 1.2 with most common features supported. Specifically, it provides: - ciphers: AES, Camellia From 52a158716dc7a4db4b9ec66a247f9af8b9ce52a6 Mon Sep 17 00:00:00 2001 From: galjonsfigur <44552519+galjonsfigur@users.noreply.github.com> Date: Fri, 27 Dec 2019 14:20:52 +0100 Subject: [PATCH 21/59] Initial version of software UART C module (#2673) --- app/include/user_modules.h | 1 + app/modules/softuart.c | 412 +++++++++++++++++++++++++++++++++++++ docs/modules/softuart.md | 78 +++++++ mkdocs.yml | 1 + 4 files changed, 492 insertions(+) create mode 100644 app/modules/softuart.c create mode 100644 docs/modules/softuart.md diff --git a/app/include/user_modules.h b/app/include/user_modules.h index 0b28dbe757..7985325497 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -55,6 +55,7 @@ //#define LUA_USE_MODULES_SIGMA_DELTA //#define LUA_USE_MODULES_SJSON //#define LUA_USE_MODULES_SNTP +//#define LUA_USE_MODULES_SOFTUART //#define LUA_USE_MODULES_SOMFY #define LUA_USE_MODULES_SPI //#define LUA_USE_MODULES_SQLITE3 diff --git a/app/modules/softuart.c b/app/modules/softuart.c new file mode 100644 index 0000000000..96db98e91c --- /dev/null +++ b/app/modules/softuart.c @@ -0,0 +1,412 @@ +#include "ets_sys.h" +#include "osapi.h" +#include "gpio.h" +#include "os_type.h" +#include "user_interface.h" +#include "module.h" +#include "lauxlib.h" +#include "task/task.h" +#include "platform.h" +#include +#include + +#define SOFTUART_MAX_RX_BUFF 128 +#define SOFTUART_GPIO_COUNT 13 + +typedef struct { + char receive_buffer[SOFTUART_MAX_RX_BUFF]; + uint8_t length; + uint8_t buffer_overflow; +} softuart_buffer_t; + +typedef struct { + uint8_t pin_rx; + uint8_t pin_tx; + volatile softuart_buffer_t buffer; + uint16_t bit_time; + uint16_t need_len; // Buffer length needed to run callback function + char end_char; // Used to run callback if last char in buffer will be the same + uint8_t armed; +} softuart_t; + +typedef struct { + softuart_t *softuart; +} softuart_userdata; + +// Array of pointers to SoftUART instances +softuart_t * softuart_gpio_instances[SOFTUART_GPIO_COUNT] = {NULL}; +// Array of callback reference to be able to find which callback is used to which rx pin +static int softuart_rx_cb_ref[SOFTUART_GPIO_COUNT]; +// Task for receiving data +static task_handle_t uart_recieve_task = NULL; +// Receiving buffer for callback usage +static char softuart_rx_buffer[SOFTUART_MAX_RX_BUFF]; + +static inline int32_t asm_ccount(void) { + int32_t r; + asm volatile ("rsr %0, ccount" : "=r"(r)); + return r; +} + +static inline uint8_t checkbit(uint8_t data, uint8_t bit) +{ + if ((data & bit) != 0) { + return 1; + } else { + return 0; + } +} + +uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status) +{ + // Disable all interrupts + ets_intr_lock(); + int32_t start_time = asm_ccount(); + uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + uint32_t gpio_bits = gpio_status; + for (uint8_t gpio_bit = 0; gpio_bits != 0; gpio_bit++, gpio_bits >>= 1) { + // Check all pins for interrupts + if (! (gpio_bits & 0x01)) continue; + // We got pin that was interrupted + // Load instance which has rx pin on interrupt pin attached + softuart_t *s = softuart_gpio_instances[pin_num_inv[gpio_bit]]; + if (s == NULL) continue; + if (softuart_rx_cb_ref[pin_num_inv[gpio_bit]] == LUA_NOREF) continue; + if (!s->armed) continue; + // There is SoftUART rx instance on that pin + // Clear interrupt status on that pin + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & (1 << pin_num[s->pin_rx])); + ret_gpio_status &= ~(1 << pin_num[s->pin_rx]); + // Start listening to transmission + // TODO: inverted + if (! (GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx])))) { + //pin is low - therefore we have a start bit + unsigned byte = 0; + // Casting and using signed types to always be able to compute elapsed time even if there is a overflow + uint32_t elapsed_time = (uint32_t)(asm_ccount() - start_time); + + // Wait till start bit is half over so we can sample the next one in the center + if (elapsed_time < s->bit_time / 2) { + uint16_t wait_time = s->bit_time / 2 - elapsed_time; + while ((uint32_t)(asm_ccount() - start_time) < wait_time); + start_time += wait_time; + } + + // Sample bits + // TODO: How many bits? Add other configs to softuart + for (uint8_t i = 0; i < 8; i ++ ) { + while ((uint32_t)(asm_ccount() - start_time) < s->bit_time); + //shift d to the right + byte >>= 1; + + // Read bit + if(GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx]))) { + // If high, set msb of 8bit to 1 + byte |= 0x80; + } + // Recalculate start time for next bit + start_time += s->bit_time; + } + + // Wait for stop bit + // TODO: Add config for stop bits and parity bits + while ((uint32_t)(asm_ccount() - start_time) < s->bit_time); + + // Store byte in buffer + // If buffer full, set the overflow flag and return + uint8 next = s->buffer.length + 1 % SOFTUART_MAX_RX_BUFF; + if (next != 0) { + s->buffer.receive_buffer[s->buffer.length] = byte; // save new byte + s->buffer.length = next; + // Run callback when buffer is filled with enough data or last char is the triggering one + if (((s->need_len != 0) && (s->buffer.length >= s->need_len)) || \ + ((s->need_len == 0) && ((char)byte == s->end_char))) { + s->armed = 0; + task_post_low(uart_recieve_task, (task_param_t)s); // Send the pointer to task handler + } + } else { + //TODO: use this information somehow? + s->buffer.buffer_overflow = 1; + } + } + } + // re-enable all interrupts + ets_intr_unlock(); + return ret_gpio_status; +} + +static void softuart_putchar(softuart_t *s, char data) +{ + // Disable all interrupts + ets_intr_lock(); + int32_t start_time = asm_ccount(); + // Set start bit + GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), 0); + for (uint32_t i = 0; i < 8; i++) { + while ((uint32_t)(asm_ccount() - start_time) < s->bit_time); + + GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), checkbit(data, 1 << i)); + // Recalculate start time for next bit + start_time += s->bit_time; + } + + // Stop bit + while ((uint32_t)(asm_ccount() - start_time) < s->bit_time); + GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), 1); + // Delay after byte, for new sync + os_delay_us(s->bit_time*6 / system_get_cpu_freq()); + // Re-enable all interrupts + ets_intr_unlock(); +} + +static void softuart_init(softuart_t *s) +{ + NODE_DBG("SoftUART initialize gpio\n"); + + if (s->pin_tx != 0xFF){ + // Init tx pin + platform_gpio_mode(s->pin_tx, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP); + platform_gpio_write(s->pin_tx, PLATFORM_GPIO_HIGH); + } + + // Init rx pin + if (s->pin_rx != 0xFF){ + platform_gpio_mode(s->pin_rx, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP); + uint32_t mask = 1 << pin_num[s->pin_rx]; + platform_gpio_register_intr_hook(mask, softuart_intr_handler); + + softuart_gpio_instances[s->pin_rx] = s; + // Enable interrupt for pin on falling edge + platform_gpio_intr_init(s->pin_rx, GPIO_PIN_INTR_NEGEDGE); + } +} + + +static int softuart_setup(lua_State *L) +{ + uint32_t baudrate; + uint8_t tx_gpio_id, rx_gpio_id; + uint8_t stack = 1; + softuart_userdata *suart = NULL; + + NODE_DBG("SoftUART setup called\n"); + + if(lua_isnumber(L, stack)) { + baudrate = (uint32_t)luaL_checkinteger( L, stack); + //230400 Is the max baudrate the author of Arduino-Esp8266-Software-UART tested + if (baudrate <= 0 || baudrate > 230400) { + return luaL_error(L, "Invalid baud rate" ); + } + stack++; + } else { + return luaL_error(L, "Invalid argument type"); + } + + if(lua_isnumber(L, stack)) { + tx_gpio_id = (uint8_t)luaL_checkinteger( L, stack); + if (!platform_gpio_exists(tx_gpio_id) || tx_gpio_id == 0) { + return luaL_error(L, "SoftUART tx GPIO not valid"); + } + stack++; + } else { + tx_gpio_id = 0xFF; + stack++; + } + if (lua_isnumber(L, stack)) { + rx_gpio_id = (uint8_t)luaL_checkinteger( L, stack); + if (!platform_gpio_exists(rx_gpio_id) || rx_gpio_id == 0) { + return luaL_error(L, "SoftUART rx GPIO not valid"); + } + if (softuart_gpio_instances[rx_gpio_id] != NULL) { + return luaL_error( L, "SoftUART rx already configured on the pin."); + } + } else { + rx_gpio_id = 0xFF; + } + + suart = (softuart_userdata*)lua_newuserdata(L, sizeof(softuart_userdata)); + suart->softuart = malloc(sizeof(softuart_t)); + if (!suart->softuart) { + free(suart->softuart); + suart->softuart = NULL; + return luaL_error(L, "Not enough memory"); + } + suart->softuart->pin_rx = rx_gpio_id; + suart->softuart->pin_tx = tx_gpio_id; + suart->softuart->need_len = RX_BUFF_SIZE; + suart->softuart->armed = 0; + //set bit time + suart->softuart->bit_time = system_get_cpu_freq() * 1000000 / baudrate; + + // Set metatable + luaL_getmetatable(L, "softuart.port"); + lua_setmetatable(L, -2); + // Init SoftUART + softuart_init(suart->softuart); + return 1; +} + +static void softuart_rx_callback(task_param_t arg) +{ + softuart_t *softuart = (softuart_t*)arg; //Receive pointer from ISR + lua_State *L = lua_getstate(); + lua_rawgeti(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[softuart->pin_rx]); + // Copy volatile data to static buffer + for (int i = 0; i < softuart->buffer.length; i++) { + softuart_rx_buffer[i] = softuart->buffer.receive_buffer[i]; + } + lua_pushlstring(L, softuart_rx_buffer, softuart->buffer.length); + softuart->buffer.length = 0; + softuart->armed = 1; + lua_call(L, 1, 0); +} + +// Arguments: event name, minimum buffer filled to run callback, callback function +static int softuart_on(lua_State *L) +{ + NODE_DBG("SoftUART on called\n"); + softuart_userdata *suart = NULL; + size_t name_len, arg_len; + uint8_t stack = 1; + + suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port"); + luaL_argcheck(L, suart, stack, "softuart.port expected"); + if (suart == NULL) { + NODE_DBG("Userdata is nil\n"); + return 0; + } + stack++; + + const char *method = luaL_checklstring(L, stack, &name_len); + if (method == NULL) + return luaL_error(L, "Wrong argument type"); + stack++; + + if (lua_type(L, stack) == LUA_TNUMBER) { + suart->softuart->need_len = (uint16_t)luaL_checkinteger( L, stack ); + stack++; + suart->softuart->end_char = 0; + if (suart->softuart->need_len > SOFTUART_MAX_RX_BUFF) { + suart->softuart->need_len = 0; + return luaL_error(L, "Argument bigger than SoftUART buffer"); + } + suart->softuart->armed = 1; + } else if (lua_isstring(L, stack)) { + const char *end = luaL_checklstring(L , stack, &arg_len); + stack++; + if ( arg_len != 1) { + return luaL_error(L, "Wrong end char length"); + } + suart->softuart->end_char = end[0]; + suart->softuart->need_len = 0; + suart->softuart->armed = 1; + } else { + return luaL_error(L, "Wrong argument type"); + } + + + if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION) { + lua_pushvalue(L, stack); // Copy to top of the stack + } else { + lua_pushnil(L); + } + + if (name_len == 4 && strcmp(method, "data") == 0) { + + if(suart->softuart->pin_rx == 0xFF) { + return luaL_error(L, "Rx pin was not declared"); + } + + if (softuart_rx_cb_ref[suart->softuart->pin_rx] != LUA_NOREF) { + luaL_unref(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[suart->softuart->pin_rx]); + softuart_rx_cb_ref[suart->softuart->pin_rx] = LUA_NOREF; + } + if (! lua_isnil(L, -1)) { + softuart_rx_cb_ref[suart->softuart->pin_rx] = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + lua_pop(L, 1); + } + } else { + lua_pop(L, 1); + return luaL_error(L, "Method not supported"); + } + return 0; +} + +static int softuart_write(lua_State *L) +{ + NODE_DBG("SoftUART write called\n"); + softuart_userdata *suart = NULL; + uint8_t stack = 1; + size_t str_len; + suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port"); + luaL_argcheck(L, suart, stack, "softuart.port expected"); + if (suart == NULL) { + NODE_DBG("Userdata is nil\n"); + return 0; + } + stack++; + if(suart->softuart->pin_tx == 0xFF) { + return luaL_error(L, "Tx pin was not declared"); + } + if (lua_type(L, stack) == LUA_TNUMBER) { + // Send byte + uint32_t byte = (uint32_t)luaL_checkinteger( L, stack ); + if (byte > 255) { + return luaL_error(L, "Integer too large for a byte"); + } + softuart_putchar(suart->softuart, (char)byte); + } else if (lua_isstring(L, stack)) { + // Send string + const char *string = luaL_checklstring(L , stack, &str_len); + for (size_t i = 0; i < str_len; i++) { + softuart_putchar(suart->softuart, string[i]); + } + } else { + return luaL_error(L, "Wrong argument type"); + } + return 0; +} + +static int softuart_gcdelete(lua_State *L) +{ + NODE_DBG("SoftUART GC called\n"); + softuart_userdata *suart = NULL; + suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port"); + luaL_argcheck(L, suart, 1, "softuart.port expected"); + if (suart == NULL) { + NODE_DBG("Userdata is nil\n"); + return 0; + } + softuart_gpio_instances[suart->softuart->pin_rx] = NULL; + luaL_unref(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[suart->softuart->pin_rx]); + softuart_rx_cb_ref[suart->softuart->pin_rx] = LUA_NOREF; + free(suart->softuart); + return 0; +} + +// Port function map +LROT_BEGIN(softuart_port) + LROT_FUNCENTRY( on, softuart_on) + LROT_TABENTRY( __index, softuart_port) + LROT_FUNCENTRY( write, softuart_write) + LROT_FUNCENTRY( __gc, softuart_gcdelete) +LROT_END(ads1115, softuart_port, LROT_MASK_GC_INDEX) + +// Module function map +LROT_BEGIN(softuart) + LROT_FUNCENTRY( setup, softuart_setup) + LROT_TABENTRY(__metatable, softuart_port) +LROT_END(softuart, NULL, 0 ) + +static int luaopen_softuart(lua_State *L) +{ + for(int i = 0; i < SOFTUART_GPIO_COUNT; i++) { + softuart_rx_cb_ref[i] = LUA_NOREF; + } + uart_recieve_task = task_get_id((task_callback_t) softuart_rx_callback); + luaL_rometatable(L, "softuart.port", (void *)softuart_port_map); + return 0; +} + +NODEMCU_MODULE(SOFTUART, "softuart", softuart, luaopen_softuart); diff --git a/docs/modules/softuart.md b/docs/modules/softuart.md new file mode 100644 index 0000000000..d976ec3576 --- /dev/null +++ b/docs/modules/softuart.md @@ -0,0 +1,78 @@ +# SoftUART Module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +|2019-12-27 | [pleningerweb](https://github.com/plieningerweb/), [juancgalvez](https://github.com/juancgalvez/), [crasu](https://github.com/crasu/), [galjonsfigur](https://github.com/galjonsfigur/)| [galjonsfigur](https://github.com/galjonsfigur/) | [softuart.c](../../app/modules/softuart.c) | + +The SoftUART module provides access to multiple software-based UART ports. + +ESP8266 has only 1 full hardware UART port that is used to program the chip and communicate with NodeMCU firmware. The second port is transmit-only. More information can be found in [uart module documentation](uart/). This module provides access to more UART ports and can be used to communicate with devices like GSM or GPS modules. The code is based on [esp8266-software-uart](https://github.com/plieningerweb/esp8266-software-uart) and [Arduino-esp8266-Software-UART](https://github.com/juancgalvez/Arduino-esp8266-Software-UART) projects. Currently doesn't support inverted serial data logic or modes other than 8N1. It's important to notice that this is a software implementation of the serial protocol. There could be some interrupts that make the transmition or reception fail due to invalid timing. + +!!! note +SoftUART cannot be used on D0 pin. + +## softuart.setup() + +Creates new SoftUART instance. Note that rx pin cannot be shared between instances but tx pin can. + +#### Syntax +`softuart.setup(baudrate, txPin, rxPin)` + +#### Parameters +- `baudrate`: SoftUART baudrate. Maximum supported is 230400. +- `txPin`: SoftUART tx pin. If set to `nil` `write` method will not be supported. +- `rxPin`: SoftUART rx pin. If set to `nil` `on("data")` method will not be supported. + +#### Returns +`softuart` instance. + +#### Example +```lua +-- Create new software UART with baudrate of 9600, D2 as Tx pin and D3 as Rx pin +s = softuart.setup(9600, 2, 3) +``` + +# SoftUART port + + +## softuart.port:on() +Sets up the callback function to receive data. + +#### Syntax +`softuart.port:on(event, trigger, function(data))` + +#### Parameters +- `event`: Event name. Currently only `data` is supported. +- `trigger`: Can be a character or a number. If character is set, the callback function will only be run when that character gets received. When a number is set, the callback function will only be run when buffer will have as many characters as number. +- `function(data)`: Callback function. the `data` parameter is software UART receiving buffer. + +#### Returns +`nil` + +#### Example +```lua +-- Create new software UART with baudrate of 9600, D2 as Tx pin and D3 as Rx pin +s = softuart.setup(9600, 2, 3) +s:on("data", 10, function(data) + print("Lua handler called!") + print(data) +end) +``` + +## softuart.port:write() +Transmits a byte or sequence of them. + +#### Syntax +`softuart.port:write(data)` + +#### Parameters +- `data`: Can be a number or string. When a number is passed, only one byte will be sent. When a string is passed, whole sequence will be transmitted. + +#### Returns +`nil` + +#### Example +```lua +-- Create new software UART with baudrate of 9600, D2 as Tx pin and D3 as Rx pin +s = softuart.setup(9600, 2, 3) +s:write("Hello!") +``` diff --git a/mkdocs.yml b/mkdocs.yml index 4d704d1751..11be8c881c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -99,6 +99,7 @@ pages: - 'sigma delta': 'modules/sigma-delta.md' - 'sjson': 'modules/sjson.md' - 'sntp': 'modules/sntp.md' + - 'softuart': 'modules/softuart.md' - 'somfy': 'modules/somfy.md' - 'spi': 'modules/spi.md' - 'sqlite3': 'modules/sqlite3.md' From 1652c0c7aed8d50cfe7a880c34ee60e5132b19cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Voborsk=C3=BD?= Date: Sat, 28 Dec 2019 14:10:11 +0100 Subject: [PATCH 22/59] Add DCC decoder module (#2905) --- app/driver/NmraDcc.c | 1161 ++++++++++++++++++++++++++++++++++ app/include/driver/NmraDcc.h | 479 ++++++++++++++ app/include/user_modules.h | 1 + app/modules/dcc.c | 290 +++++++++ docs/modules/dcc.md | 118 ++++ lua_examples/dcc/dcc.lua | 86 +++ mkdocs.yml | 1 + 7 files changed, 2136 insertions(+) create mode 100644 app/driver/NmraDcc.c create mode 100644 app/include/driver/NmraDcc.h create mode 100644 app/modules/dcc.c create mode 100644 docs/modules/dcc.md create mode 100644 lua_examples/dcc/dcc.lua diff --git a/app/driver/NmraDcc.c b/app/driver/NmraDcc.c new file mode 100644 index 0000000000..9fb70cb798 --- /dev/null +++ b/app/driver/NmraDcc.c @@ -0,0 +1,1161 @@ +//------------------------------------------------------------------------ +// +// Model Railroading with Arduino - NmraDcc.cpp +// +// Copyright (c) 2008 - 2017 Alex Shepherd +// +// This source file is subject of the GNU general public license 2, +// that is available at the world-wide-web at +// http://www.gnu.org/licenses/gpl.txt +// +//------------------------------------------------------------------------ +// +// file: NmraDcc.cpp +// author: Alex Shepherd +// webpage: http://mrrwa.org/ +// history: 2008-03-20 Initial Version +// 2011-06-26 Migrated into Arduino library from OpenDCC codebase +// 2014 Added getAddr to NmraDcc Geoff Bunza +// 2015-11-06 Martin Pischky (martin@pischky.de): +// Experimental Version to support 14 speed steps +// and new signature of notifyDccSpeed and notifyDccFunc +// 2015-12-16 Version without use of Timer0 by Franz-Peter Müller +// 2016-07-16 handle glitches on DCC line +// 2016-08-20 added ESP8266 support by Sven (littleyoda) +// 2017-01-19 added STM32F1 support by Franz-Peter +// 2017-11-29 Ken West (kgw4449@gmail.com): +// Minor fixes to pass NMRA Baseline Conformance Tests. +// 2018-12-17 added ESP32 support by Trusty (thierry@lapajaparis.net) +// 2019-02-17 added ESP32 specific changes by Hans Tanner +// +//------------------------------------------------------------------------ +// +// purpose: Provide a simplified interface to decode NMRA DCC packets +// and build DCC Mobile and Stationary Decoders +// +//------------------------------------------------------------------------ + +// NodeMCU Lua port by @voborsky + +// #define NODE_DEBUG + +#include +#include +#include +#include "platform.h" +#include "user_interface.h" +#include "task/task.h" +#include "driver/NmraDcc.h" + +#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + (byte & 0x80 ? '1' : '0'), \ + (byte & 0x40 ? '1' : '0'), \ + (byte & 0x20 ? '1' : '0'), \ + (byte & 0x10 ? '1' : '0'), \ + (byte & 0x08 ? '1' : '0'), \ + (byte & 0x04 ? '1' : '0'), \ + (byte & 0x02 ? '1' : '0'), \ + (byte & 0x01 ? '1' : '0') + + + +//------------------------------------------------------------------------ +// DCC Receive Routine +// +// Howto: uses two interrupts: a rising edge in DCC polarity triggers INTx +// in INTx handler, Timer0 CompareB with a delay of 80us is started. +// On Timer0 CompareB Match the level of DCC is evaluated and +// parsed. +// +// |<-----116us----->| +// +// DCC 1: _________XXXXXXXXX_________XXXXXXXXX_________ +// ^-INTx +// |----87us--->| +// ^Timer-INT: reads zero +// +// DCC 0: _________XXXXXXXXXXXXXXXXXX__________________ +// ^-INTx +// |----------->| +// ^Timer-INT: reads one +// +// new DCC Receive Routine without Timer0 ........................................................ +// +// Howto: uses only one interrupt at the rising or falling edge of the DCC signal +// The time between two edges is measured to determine the bit value +// Synchronising to the edge of the first part of a bit is done after recognizing the start bit +// During synchronizing each part of a bit is detected ( Interruptmode 'change' ) +// +// |<-----116us----->| +// DCC 1: _________XXXXXXXXX_________XXXXXXXXX_________ +// |<--------146us------>| +// ^-INTx ^-INTx +// less than 138us: its a one-Bit +// +// +// |<-----------------232us----------->| +// DCC 0: _________XXXXXXXXXXXXXXXXXX__________________XXXXXXXX__________ +// |<--------146us------->| +// ^-INTx ^-INTx +// greater than 138us: its a zero bit +// +// +// +// +//------------------------------------------------------------------------ + +#define abs(a) ((a) > 0 ? (a) : (0-a)) + + +#define MAX_ONEBITFULL 146 +#define MAX_PRAEAMBEL 146 +#define MAX_ONEBITHALF 82 +#define MIN_ONEBITFULL 82 +#define MIN_ONEBITHALF 35 +#define MAX_BITDIFF 18 + + + +#ifdef NODE_DEBUG + #define PULLUP PLATFORM_GPIO_PULLUP + #define OUTPUT PLATFORM_GPIO_OUTPUT + #define HIGH PLATFORM_GPIO_HIGH + #define LOW PLATFORM_GPIO_LOW + + #define MODE_TP1 platform_gpio_mode( 5, OUTPUT, PULLUP ); // GPIO 14 + #define SET_TP1 platform_gpio_write(5, HIGH); + #define CLR_TP1 platform_gpio_write(5, LOW); + #define MODE_TP2 platform_gpio_mode( 6, OUTPUT, PULLUP ); // GPIO 12 + #define SET_TP2 platform_gpio_write(6, HIGH); + #define CLR_TP2 platform_gpio_write(6, LOW); + #define MODE_TP3 platform_gpio_mode( 7, OUTPUT, PULLUP ); // GPIO 13 + #define SET_TP3 platform_gpio_write(7, HIGH); + #define CLR_TP3 platform_gpio_write(7, LOW); + #define MODE_TP4 platform_gpio_mode( 8, OUTPUT, PULLUP ); // GPIO 15 + #define SET_TP4 platform_gpio_write(8, HIGH); + #define CLR_TP4 platform_gpio_write(8, LOW); +#else + #define MODE_TP1 + #define SET_TP1 + #define CLR_TP1 + #define MODE_TP2 + #define SET_TP2 + #define CLR_TP2 + #define MODE_TP3 + #define SET_TP3 + #define CLR_TP3 + #define MODE_TP4 + #define SET_TP4 + #define CLR_TP4 +#endif + +static uint8_t ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING +static int16_t bitMax, bitMin; + +DCC_MSG Msg ; + +typedef enum +{ + WAIT_PREAMBLE = 0, + WAIT_START_BIT, + WAIT_DATA, + WAIT_END_BIT +} +DccRxWaitState ; + +typedef enum +{ + OPS_INS_RESERVED = 0, + OPS_INS_VERIFY_BYTE, + OPS_INS_BIT_MANIPULATION, + OPS_INS_WRITE_BYTE +} +OpsInstructionType; + +struct DccRx_t +{ + DccRxWaitState State ; + uint8_t BitCount ; + uint8_t TempByte ; + DCC_MSG PacketBuf; + DCC_MSG PacketCopy; +} +DccRx ; + +typedef struct +{ + uint8_t Flags ; + uint8_t OpsModeAddressBaseCV ; + uint8_t inServiceMode ; + long LastServiceModeMillis ; + uint8_t PageRegister ; // Used for Paged Operations in Service Mode Programming + uint8_t DuplicateCount ; + DCC_MSG LastMsg ; + uint8_t IntPin; + uint8_t IntBitmask; + int16_t myDccAddress; // Cached value of DCC Address from CVs + uint8_t inAccDecDCCAddrNextReceivedMode; +#ifdef DCC_DEBUG + uint8_t IntCount; + uint8_t TickCount; +#endif +} +DCC_PROCESSOR_STATE ; + +DCC_PROCESSOR_STATE DccProcState ; + +task_handle_t DataReady_taskid; + +static uint32_t ICACHE_RAM_ATTR InterruptHandler (uint32_t ret_gpio_status) +{ + // This function really is running at interrupt level with everything + // else masked off. It should take as little time as necessary. + + uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + if ((gpio_status & DccProcState.IntBitmask) == 0) { + return ret_gpio_status; + } + + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & DccProcState.IntBitmask); + uint32_t actMicros = system_get_time(); + ret_gpio_status &= ~(DccProcState.IntBitmask); + + // Bit evaluation without Timer 0 ------------------------------ + uint8_t DccBitVal; + static int8_t bit1, bit2 ; + static unsigned long lastMicros = 0; + static uint8_t halfBit; + unsigned long bitMicros; + SET_TP3; + bitMicros = actMicros-lastMicros; + if ( bitMicros < bitMin ) { + // too short - my be false interrupt due to glitch or false protocol -> ignore + CLR_TP3; + return ret_gpio_status; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ + } + DccBitVal = ( bitMicros < bitMax ); + lastMicros = actMicros; + #ifdef NODE_DEBUG + if(DccBitVal) {SET_TP2;} else {CLR_TP2;}; + #endif + #ifdef DCC_DEBUG + DccProcState.TickCount++; + #endif + + switch( DccRx.State ) + { + case WAIT_PREAMBLE: + if( DccBitVal ) + { + SET_TP1; + DccRx.BitCount++; + if( DccRx.BitCount > 10 ) { + DccRx.State = WAIT_START_BIT ; + // While waiting for the start bit, detect halfbit lengths. We will detect the correct + // sync and detect whether we see a false (e.g. motorola) protocol + + gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[DccProcState.IntPin]), GPIO_PIN_INTR_ANYEDGE); + halfBit = 0; + bitMax = MAX_ONEBITHALF; + bitMin = MIN_ONEBITHALF; + CLR_TP1; + } + } else { + SET_TP1; + DccRx.BitCount = 0 ; + CLR_TP1; + } + break; + + case WAIT_START_BIT: + // we are looking for first half "0" bit after preamble + switch ( halfBit ) { + case 0: //SET_TP1; + // check first part + if ( DccBitVal ) { + // is still 1-bit (Preamble) + halfBit=1; + bit1=bitMicros; + } else { + // was "0" half bit, maybe the startbit + SET_TP1; + halfBit = 4; + CLR_TP1; + } + break; + case 1: //SET_TP1; // previous halfbit was '1' + if ( DccBitVal ) { + // its a '1' halfBit -> we are still in the preamble + halfBit = 0; + bit2=bitMicros; + DccRx.BitCount++; + if( abs(bit2-bit1) > MAX_BITDIFF ) { + // the length of the 2 halfbits differ too much -> wrong protokoll + CLR_TP2; + CLR_TP3; + DccRx.State = WAIT_PREAMBLE; + bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; + DccRx.BitCount = 0; + SET_TP4; + gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[DccProcState.IntPin]), ISREdge); + SET_TP3; + CLR_TP4; + } + } else { + // first '0' half detected in second halfBit + // wrong sync or not a DCC protokoll + CLR_TP3; + halfBit = 3; + SET_TP3; + } + break; + case 3: //SET_TP1; // previous halfbit was '0' in second halfbit + if ( DccBitVal ) { + // its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC + DccRx.State = WAIT_PREAMBLE; + bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; + DccRx.BitCount = 0; + } else { + // we got two '0' halfbits -> it's the startbit + // but sync is NOT ok, change IRQ edge. + if ( ISREdge == GPIO_PIN_INTR_POSEDGE ) ISREdge = GPIO_PIN_INTR_NEGEDGE; else ISREdge = GPIO_PIN_INTR_POSEDGE; + DccRx.State = WAIT_DATA ; + bitMax = MAX_ONEBITFULL; + bitMin = MIN_ONEBITFULL; + DccRx.PacketBuf.Size = 0; + DccRx.PacketBuf.PreambleBits = 0; + for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ ) + DccRx.PacketBuf.Data[i] = 0; + + DccRx.PacketBuf.PreambleBits = DccRx.BitCount; + DccRx.BitCount = 0 ; + DccRx.TempByte = 0 ; + } + SET_TP4; + gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[DccProcState.IntPin]), ISREdge); + CLR_TP1; + CLR_TP4; + break; + case 4: SET_TP1; // previous (first) halfbit was 0 + // if this halfbit is 0 too, we got the startbit + if ( DccBitVal ) { + // second halfbit is 1 -> unknown protokoll + DccRx.State = WAIT_PREAMBLE; + bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; + DccRx.BitCount = 0; + } else { + // we got the startbit + DccRx.State = WAIT_DATA ; + bitMax = MAX_ONEBITFULL; + bitMin = MIN_ONEBITFULL; + DccRx.PacketBuf.Size = 0; + DccRx.PacketBuf.PreambleBits = 0; + for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ ) + DccRx.PacketBuf.Data[i] = 0; + + DccRx.PacketBuf.PreambleBits = DccRx.BitCount; + DccRx.BitCount = 0 ; + DccRx.TempByte = 0 ; + } + + CLR_TP1; + SET_TP4; + gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[DccProcState.IntPin]), ISREdge); + CLR_TP4; + break; + + } + break; + + case WAIT_DATA: + DccRx.BitCount++; + DccRx.TempByte = ( DccRx.TempByte << 1 ) ; + if( DccBitVal ) + DccRx.TempByte |= 1 ; + + if( DccRx.BitCount == 8 ) + { + if( DccRx.PacketBuf.Size == MAX_DCC_MESSAGE_LEN ) // Packet is too long - abort + { + DccRx.State = WAIT_PREAMBLE ; + bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; + DccRx.BitCount = 0 ; + } + else + { + DccRx.State = WAIT_END_BIT ; + DccRx.PacketBuf.Data[ DccRx.PacketBuf.Size++ ] = DccRx.TempByte ; + } + } + break; + + case WAIT_END_BIT: + DccRx.BitCount++; + if( DccBitVal ) // End of packet? + { + CLR_TP3; + DccRx.State = WAIT_PREAMBLE ; + bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; + DccRx.PacketCopy = DccRx.PacketBuf ; + uint8_t param; + task_post_high(DataReady_taskid, (os_param_t) ¶m); + SET_TP3; + } + else // Get next Byte + // KGW - Abort immediately if packet is too long. + if( DccRx.PacketBuf.Size == MAX_DCC_MESSAGE_LEN ) // Packet is too long - abort + { + DccRx.State = WAIT_PREAMBLE ; + bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; + DccRx.BitCount = 0 ; + } + else + { + DccRx.State = WAIT_DATA ; + + DccRx.BitCount = 0 ; + DccRx.TempByte = 0 ; + } + } + + CLR_TP1; + CLR_TP3; + return ret_gpio_status; +} + +uint8_t validCV( uint16_t CV, uint8_t Writable ) +{ + if( notifyCVResetFactoryDefault && (CV == CV_MANUFACTURER_ID ) && Writable ) + notifyCVResetFactoryDefault(); + + if( notifyCVValid ) + return notifyCVValid( CV, Writable ) ; + return 0; +} + +uint8_t readCV( unsigned int CV ) +{ + if( notifyCVRead ) + return notifyCVRead( CV ) ; + return 0; +} + +uint8_t writeCV( unsigned int CV, uint8_t Value) +{ + switch( CV ) + { + case CV_29_CONFIG: + // copy addressmode Bit to Flags + DccProcState.Flags = ( DccProcState.Flags & ~FLAGS_CV29_BITS) | (Value & FLAGS_CV29_BITS); + // no break, because myDccAdress must also be reset + case CV_ACCESSORY_DECODER_ADDRESS_LSB: // Also same CV for CV_MULTIFUNCTION_PRIMARY_ADDRESS + case CV_ACCESSORY_DECODER_ADDRESS_MSB: + case CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB: + case CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB: + DccProcState.myDccAddress = -1; // Assume any CV Write Operation might change the Address + } + + if( notifyCVWrite ) + return notifyCVWrite( CV, Value ) ; + return 0; +} + +uint16_t getMyAddr(void) +{ + uint8_t CV29Value ; + + if( DccProcState.myDccAddress != -1 ) // See if we can return the cached value + return( DccProcState.myDccAddress ); + + CV29Value = readCV( CV_29_CONFIG ) ; + + if( CV29Value & CV29_ACCESSORY_DECODER ) // Accessory Decoder? + { + if( CV29Value & CV29_OUTPUT_ADDRESS_MODE ) + DccProcState.myDccAddress = ( readCV( CV_ACCESSORY_DECODER_ADDRESS_MSB ) << 8 ) | readCV( CV_ACCESSORY_DECODER_ADDRESS_LSB ); + else + DccProcState.myDccAddress = ( ( readCV( CV_ACCESSORY_DECODER_ADDRESS_MSB ) & 0b00000111) << 6 ) | ( readCV( CV_ACCESSORY_DECODER_ADDRESS_LSB ) & 0b00111111) ; + } + else // Multi-Function Decoder? + { + if( CV29Value & CV29_EXT_ADDRESSING ) // Two Byte Address? + DccProcState.myDccAddress = ( ( readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB ) - 192 ) << 8 ) | readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB ) ; + + else + DccProcState.myDccAddress = readCV( 1 ) ; + } + + return DccProcState.myDccAddress ; +} + +void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value ) +{ + // is it a Byte Operation + if( Cmd & 0x04 ) + { + // Perform the Write Operation + if( Cmd & 0x08 ) + { + if( validCV( CVAddr, 1 ) ) + { + writeCV( CVAddr, Value ); + } + } + } + // Perform the Bit-Wise Operation + else + { + uint8_t BitMask = (1 << (Value & 0x07) ) ; + uint8_t BitValue = Value & 0x08 ; + uint8_t BitWrite = Value & 0x10 ; + + uint8_t tempValue = readCV( CVAddr ) ; // Read the Current CV Value + + // Perform the Bit Write Operation + if( BitWrite ) + { + if( validCV( CVAddr, 1 ) ) + { + if( BitValue ) + tempValue |= BitMask ; // Turn the Bit On + + else + tempValue &= ~BitMask ; // Turn the Bit Off + + writeCV( CVAddr, tempValue ); + } + } + } +} + +#ifdef NMRA_DCC_PROCESS_MULTIFUNCTION +void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Cmd, uint8_t Data1, uint8_t Data2 ) +{ + uint8_t speed ; + uint16_t CVAddr ; + DCC_DIRECTION dir ; + DCC_SPEED_STEPS speedSteps ; + + uint8_t CmdMasked = Cmd & 0b11100000 ; + + // NODE_DBG("[dcc_processMultiFunctionMessage] Addr: %d, Type: %d, Cmd: %d ("BYTE_TO_BINARY_PATTERN"), Data: %d, %d, CmdMasked="BYTE_TO_BINARY_PATTERN"\n", Addr, AddrType, Cmd, BYTE_TO_BINARY(Cmd), Data1, Data2, BYTE_TO_BINARY(CmdMasked)); + + // If we are an Accessory Decoder + if( DccProcState.Flags & FLAGS_DCC_ACCESSORY_DECODER ) + { + // NODE_DBG("[dcc_processMultiFunctionMessage] DccProcState.Flags & FLAGS_DCC_ACCESSORY_DECODER\n"); + // and this isn't an Ops Mode Write or we are NOT faking the Multifunction Ops mode address in CV 33+34 or + // it's not our fake address, then return + if( ( CmdMasked != 0b11100000 ) || ( DccProcState.OpsModeAddressBaseCV == 0 ) ) + return ; + + uint16_t FakeOpsAddr = readCV( DccProcState.OpsModeAddressBaseCV ) | ( readCV( DccProcState.OpsModeAddressBaseCV + 1 ) << 8 ) ; + uint16_t OpsAddr = Addr & 0x3FFF ; + + if( OpsAddr != FakeOpsAddr ) + return ; + } + + // We are looking for FLAGS_MY_ADDRESS_ONLY but it does not match and it is not a Broadcast Address then return + else if( ( DccProcState.Flags & FLAGS_MY_ADDRESS_ONLY ) && ( Addr != getMyAddr() ) && ( Addr != 0 ) ) + return ; + + NODE_DBG("[dcc_processMultiFunctionMessage] CmdMasked: %x\n", CmdMasked); + switch( CmdMasked ) + { + case 0b00000000: // Decoder Control + switch( Cmd & 0b00001110 ) + { + case 0b00000000: + if( notifyDccReset && ( Cmd & 0b00000001 ) ) // Hard Reset + if( notifyDccReset) + notifyDccReset( 1 ) ; + break ; + + case 0b00000010: // Factory Test + break ; + + case 0b00000110: // Set Decoder Flags + break ; + + case 0b00001010: // Set Advanced Addressing + break ; + + case 0b00001110: // Decoder Acknowledgment + break ; + + default: // Reserved + ; + } + break ; + + case 0b00100000: // Advanced Operations + switch( Cmd & 0b00011111 ) + { + case 0b00011111: + if( notifyDccSpeed ) + { + switch( Data1 & 0b01111111 ) + { + case 0b00000000: // 0=STOP + speed = 1 ; // => 1 + break ; + + case 0b00000001: // 1=EMERGENCY_STOP + speed = 0 ; // => 0 + break ; + + default: // 2..127 + speed = (Data1 & 0b01111111) ; + } + dir = (DCC_DIRECTION) ((Data1 & 0b10000000) >> 7) ; + notifyDccSpeed( Addr, AddrType, speed, dir, SPEED_STEP_128 ) ; + } + } + break; + + case 0b01000000: + case 0b01100000: + //TODO should we cache this info in DCC_PROCESSOR_STATE.Flags ? +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + speedSteps = (readCV( CV_29_CONFIG ) & CV29_F0_LOCATION) ? SPEED_STEP_28 : SPEED_STEP_14 ; +#else + speedSteps = SPEED_STEP_28 ; +#endif + if( notifyDccSpeed ) + { + switch( Cmd & 0b00011111 ) + { + case 0b00000000: // 0 0000 = STOP + case 0b00010000: // 1 0000 = STOP + speed = 1 ; // => 1 + break ; + + case 0b00000001: // 0 0001 = EMERGENCY STOP + case 0b00010001: // 1 0001 = EMERGENCY STOP + speed = 0 ; // => 0 + break ; + + default: +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + if( speedSteps == SPEED_STEP_14 ) + { + speed = (Cmd & 0b00001111) ; // => 2..15 + } + else + { +#endif + speed = (((Cmd & 0b00001111) << 1 ) | ((Cmd & 0b00010000) >> 4)) - 2 ; // => 2..29 +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + } +#endif + } + dir = (DCC_DIRECTION) ((Cmd & 0b00100000) >> 5) ; + notifyDccSpeed( Addr, AddrType, speed, dir, speedSteps ) ; + } + if( notifyDccSpeedRaw ) + notifyDccSpeedRaw(Addr, AddrType, Cmd ); + +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + if( notifyDccFunc && (speedSteps == SPEED_STEP_14) ) + { + // function light is controlled by this package + uint8_t fn0 = (Cmd & 0b00010000) ; + notifyDccFunc( Addr, AddrType, FN_0, fn0 ) ; + } +#endif + break; + + case 0b10000000: // Function Group 0..4 + if( notifyDccFunc ) + { + // function light is controlled by this package (28 or 128 speed steps) + notifyDccFunc( Addr, AddrType, FN_0_4, Cmd & 0b00011111 ) ; + } + break; + + case 0b10100000: // Function Group 5..8 + if( notifyDccFunc) + { + if (Cmd & 0b00010000 ) + notifyDccFunc( Addr, AddrType, FN_5_8, Cmd & 0b00001111 ) ; + else + notifyDccFunc( Addr, AddrType, FN_9_12, Cmd & 0b00001111 ) ; + } + break; + + case 0b11000000: // Feature Expansion Instruction + switch(Cmd & 0b00011111) + { + case 0b00011110: + if( notifyDccFunc ) + notifyDccFunc( Addr, AddrType, FN_13_20, Data1 ) ; + break; + + case 0b00011111: + if( notifyDccFunc ) + notifyDccFunc( Addr, AddrType, FN_21_28, Data1 ) ; + break; + } + break; + + case 0b11100000: // CV Access + CVAddr = ( ( ( Cmd & 0x03 ) << 8 ) | Data1 ) + 1 ; + + processDirectOpsOperation( Cmd, CVAddr, Data2 ) ; + break; + } +} +#endif + +///////////////////////////////////////////////////////////////////////// +#ifdef NMRA_DCC_PROCESS_SERVICEMODE +void processServiceModeOperation( DCC_MSG * pDccMsg ) +{ + uint16_t CVAddr ; + uint8_t Value ; + if( pDccMsg->Size == 3) // 3 Byte Packets are for Address Only, Register and Paged Mode + { + uint8_t RegisterAddr ; + NODE_DBG("[dcc_processServiceModeOperation] 3-BytePkt\n"); + RegisterAddr = pDccMsg->Data[0] & 0x07 ; + Value = pDccMsg->Data[1] ; + + if( RegisterAddr == 5 ) + { + DccProcState.PageRegister = Value ; + } + + else + { + if( RegisterAddr == 4 ) + CVAddr = CV_29_CONFIG ; + + else if( ( RegisterAddr <= 3 ) && ( DccProcState.PageRegister > 0 ) ) + CVAddr = ( ( DccProcState.PageRegister - 1 ) * 4 ) + RegisterAddr + 1 ; + + else + CVAddr = RegisterAddr + 1 ; + + if( pDccMsg->Data[0] & 0x08 ) // Perform the Write Operation + { + if( validCV( CVAddr, 1 ) ) + { + writeCV( CVAddr, Value ); + } + } + } + } + + else if( pDccMsg->Size == 4) // 4 Byte Packets are for Direct Byte & Bit Mode + { + NODE_DBG("[dcc_processServiceModeOperation] BB-Mode\n"); + CVAddr = ( ( ( pDccMsg->Data[0] & 0x03 ) << 8 ) | pDccMsg->Data[1] ) + 1 ; + Value = pDccMsg->Data[2] ; + + processDirectOpsOperation( pDccMsg->Data[0] & 0b00001100, CVAddr, Value ) ; + } +} +#endif + +void resetServiceModeTimer(uint8_t inServiceMode) +{ + if (notifyServiceMode && inServiceMode != DccProcState.inServiceMode) + { + notifyServiceMode(inServiceMode); + } + // Set the Service Mode + DccProcState.inServiceMode = inServiceMode ; + + DccProcState.LastServiceModeMillis = inServiceMode ? system_get_time() : 0 ; + if (notifyServiceMode && inServiceMode != DccProcState.inServiceMode) + { + notifyServiceMode(inServiceMode); + } +} + +void clearDccProcState(uint8_t inServiceMode) +{ + resetServiceModeTimer( inServiceMode ) ; + + // Set the Page Register to it's default of 1 only on the first Reset + DccProcState.PageRegister = 1 ; + + // Clear the LastMsg buffer and DuplicateCount in preparation for possible CV programming + DccProcState.DuplicateCount = 0 ; + memset( &DccProcState.LastMsg, 0, sizeof( DCC_MSG ) ) ; +} + +void execDccProcessor( DCC_MSG * pDccMsg ) +{ + NODE_DBG("[dcc_execDccProcessor]\n"); + + if( ( pDccMsg->Data[0] == 0 ) && ( pDccMsg->Data[1] == 0 ) ) + { + if( notifyDccReset ) + notifyDccReset( 0 ) ; + +#ifdef NMRA_DCC_PROCESS_SERVICEMODE + // If this is the first Reset then perform some one-shot actions as we maybe about to enter service mode + if( DccProcState.inServiceMode ) + resetServiceModeTimer( 1 ) ; + else + clearDccProcState( 1 ); +#endif + } + + else + { +#ifdef NMRA_DCC_PROCESS_SERVICEMODE + if( DccProcState.inServiceMode && ( pDccMsg->Data[0] >= 112 ) && ( pDccMsg->Data[0] < 128 ) ) + { + resetServiceModeTimer( 1 ) ; + + if( memcmp( pDccMsg, &DccProcState.LastMsg, sizeof( DCC_MSG ) ) ) + { + DccProcState.DuplicateCount = 0 ; + memcpy( &DccProcState.LastMsg, pDccMsg, sizeof( DCC_MSG ) ) ; + } + // Wait until you see 2 identicle packets before acting on a Service Mode Packet + else + { + DccProcState.DuplicateCount++ ; + processServiceModeOperation( pDccMsg ) ; + } + } + + else + { + if( DccProcState.inServiceMode ) + clearDccProcState( 0 ); +#endif + + // Idle Packet + if( ( pDccMsg->Data[0] == 0b11111111 ) && ( pDccMsg->Data[1] == 0 ) ) + { + if( notifyDccIdle ) + notifyDccIdle() ; + } + +#ifdef NMRA_DCC_PROCESS_MULTIFUNCTION + // Multi Function Decoders (7-bit address) + else if( pDccMsg->Data[0] < 128 ) + processMultiFunctionMessage( pDccMsg->Data[0], DCC_ADDR_SHORT, pDccMsg->Data[1], pDccMsg->Data[2], pDccMsg->Data[3] ) ; + // Basic Accessory Decoders (9-bit) & Extended Accessory Decoders (11-bit) + else if( pDccMsg->Data[0] < 192 ) +#else + else if( ( pDccMsg->Data[0] >= 128 ) && ( pDccMsg->Data[0] < 192 ) ) +#endif + { + if( DccProcState.Flags & FLAGS_DCC_ACCESSORY_DECODER ) + { + int16_t BoardAddress ; + int16_t OutputAddress ; + uint8_t TurnoutPairIndex ; + +#ifdef NODE_DEBUG + // SerialPrintPacketHex(F( "eDP: AccCmd: "), pDccMsg); +#endif + + BoardAddress = ( ( (~pDccMsg->Data[1]) & 0b01110000 ) << 2 ) | ( pDccMsg->Data[0] & 0b00111111 ) ; + TurnoutPairIndex = (pDccMsg->Data[1] & 0b00000110) >> 1; + NODE_DBG("[dcc_execDccProcessor] eDP: BAddr:%d, Index:%d\n", BoardAddress, TurnoutPairIndex); + + // First check for Legacy Accessory Decoder Configuration Variable Access Instruction + // as it's got a different format to the others + if((pDccMsg->Size == 5) && ((pDccMsg->Data[1] & 0b10001100) == 0b00001100)) + { + NODE_DBG( "eDP: Legacy Accessory Decoder CV Access Command"); + // Check if this command is for our address or the broadcast address + if((BoardAddress != getMyAddr()) && ( BoardAddress < 511 )) + { + NODE_DBG("[dcc_execDccProcessor] eDP: Board Address Not Matched\n"); + return; + } + + uint16_t cvAddress = ((pDccMsg->Data[1] & 0b00000011) << 8) + pDccMsg->Data[2] + 1; + uint8_t cvValue = pDccMsg->Data[3]; + NODE_DBG("[dcc_execDccProcessor] eDP: CV:%d Value:%d\n", cvAddress, cvValue ); + if(validCV( cvAddress, 1 )) + writeCV(cvAddress, cvValue); + return; + } + + + OutputAddress = (((BoardAddress - 1) << 2 ) | TurnoutPairIndex) + 1 ; //decoder output addresses start with 1, packet address range starts with 0 + // ( according to NMRA 9.2.2 ) + NODE_DBG("[dcc_execDccProcessor] eDP: OAddr:%d\n", OutputAddress); + + if( DccProcState.inAccDecDCCAddrNextReceivedMode) + { + if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) + { + NODE_DBG("[dcc_execDccProcessor] eDP: Set OAddr:%d\n", OutputAddress); + //uint16_t storedOutputAddress = OutputAddress + 1; // The value stored in CV1 & 9 for Output Addressing Mode is + 1 + writeCV(CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t)(OutputAddress % 256)); + writeCV(CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t)(OutputAddress / 256)); + + if( notifyDccAccOutputAddrSet ) + notifyDccAccOutputAddrSet(OutputAddress); + } + else + { + NODE_DBG("[dcc_execDccProcessor] eDP: Set BAddr:%d\n", BoardAddress); + writeCV(CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t)(BoardAddress % 64)); + writeCV(CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t)(BoardAddress / 64)); + + if( notifyDccAccBoardAddrSet ) + notifyDccAccBoardAddrSet(BoardAddress); + } + + DccProcState.inAccDecDCCAddrNextReceivedMode = 0; // Reset the mode now that we have set the address + } + + // If we're filtering addresses, does the address match our address or is it a broadcast address? If NOT then return + if( DccProcState.Flags & FLAGS_MY_ADDRESS_ONLY ) + { + if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) { + NODE_DBG("[dcc_execDccProcessor] AddrChk: OAddr:%d, BAddr:%d, myAddr:%d Chk=%d\n", OutputAddress, BoardAddress, getMyAddr(), OutputAddress != getMyAddr() ); + if ( OutputAddress != getMyAddr() && OutputAddress < 2045 ) { + NODE_DBG("[dcc_execDccProcessor] eDP: OAddr:%d, myAddr:%d - no match\n", OutputAddress, getMyAddr() ); + return; + } + } else { + if( ( BoardAddress != getMyAddr() ) && ( BoardAddress < 511 ) ) { + NODE_DBG("[dcc_execDccProcessor] eDP: BAddr:%d, myAddr:%d - no match\n", BoardAddress, getMyAddr() ); + return; + } + } + NODE_DBG("[dcc_execDccProcessor] eDP: Address Matched\n"); + } + + + if((pDccMsg->Size == 4) && ((pDccMsg->Data[1] & 0b10001001) == 1)) // Extended Accessory Decoder Control Packet Format + { + // According to the NMRA Dcc Spec the Signal State should only use the lower 5 Bits, + // however some manufacturers seem to allow/use all 8 bits, so we'll relax that constraint for now + uint8_t state = pDccMsg->Data[2] ; + NODE_DBG("[dcc_execDccProcessor] eDP: OAddr:%d Extended State:%0X\n", OutputAddress, state); + if( notifyDccSigOutputState ) + notifyDccSigOutputState(OutputAddress, state); + } + + else if(pDccMsg->Size == 3) // Basic Accessory Decoder Packet Format + { + uint8_t direction = pDccMsg->Data[1] & 0b00000001; + uint8_t outputPower = (pDccMsg->Data[1] & 0b00001000) >> 3; + + if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) + { + NODE_DBG("[dcc_execDccProcessor] eDP: OAddr:%d Turnout Dir:%d Output Power:%d\n", OutputAddress, direction, outputPower); + if( notifyDccAccTurnoutOutput ) + notifyDccAccTurnoutOutput( OutputAddress, direction, outputPower ); + } + else + { + NODE_DBG("[dcc_execDccProcessor] eDP: Turnout Pair Index:%d Dir:%d Output Power: %d\n", TurnoutPairIndex, direction, outputPower); + if( notifyDccAccTurnoutBoard ) + notifyDccAccTurnoutBoard( BoardAddress, TurnoutPairIndex, direction, outputPower ); + } + } + else if(pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming + { + NODE_DBG("[dcc_execDccProcessor] eDP: OPS Mode CV Programming Command\n"); + // Check for unsupported OPS Mode Addressing mode + if(((pDccMsg->Data[1] & 0b10001001) != 1) && ((pDccMsg->Data[1] & 0b10001111) != 0x80)) + { + NODE_DBG("[dcc_execDccProcessor] eDP: Unsupported OPS Mode CV Addressing Mode\n"); + return; + } + + // Check if this command is for our address or the broadcast address + if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE) + { + NODE_DBG("[dcc_execDccProcessor] eDP: Check Output Address:%d\n", OutputAddress); + if((OutputAddress != getMyAddr()) && ( OutputAddress < 2045 )) + { + NODE_DBG("[dcc_execDccProcessor] eDP: Output Address Not Matched\n"); + return; + } + } + else + { + NODE_DBG("[dcc_execDccProcessor] eDP: Check Board Address:%d\n", BoardAddress); + if((BoardAddress != getMyAddr()) && ( BoardAddress < 511 )) + { + NODE_DBG("[dcc_execDccProcessor] eDP: Board Address Not Matched\n"); + return; + } + } + + uint16_t cvAddress = ((pDccMsg->Data[2] & 0b00000011) << 8) + pDccMsg->Data[3] + 1; + uint8_t cvValue = pDccMsg->Data[4]; + + OpsInstructionType insType = (OpsInstructionType)((pDccMsg->Data[2] & 0b00001100) >> 2) ; + + NODE_DBG("[dcc_execDccProcessor] eDP: OPS Mode Instruction:%d\n", insType); + switch(insType) + { + case OPS_INS_RESERVED: + case OPS_INS_VERIFY_BYTE: + NODE_DBG("[dcc_execDccProcessor] eDP: Unsupported OPS Mode Instruction:%d\n", insType); + break; // We only support Write Byte or Bit Manipulation + + case OPS_INS_WRITE_BYTE: + NODE_DBG("[dcc_execDccProcessor] eDP: CV:%d Value:%d\n", cvAddress, cvValue); + if(validCV( cvAddress, 1 )) + writeCV(cvAddress, cvValue); + break; + + // 111CDBBB + // Where BBB represents the bit position within the CV, + // D contains the value of the bit to be verified or written, + // and C describes whether the operation is a verify bit or a write bit operation. + // C = "1" WRITE BIT + // C = "0" VERIFY BIT + case OPS_INS_BIT_MANIPULATION: + // Make sure its a Write Bit Manipulation + if((cvValue & 0b00010000) && validCV(cvAddress, 1 )) + { + uint8_t currentValue = readCV(cvAddress); + uint8_t newValueMask = 1 << (cvValue & 0b00000111); + if(cvValue & 0b00001000) + writeCV(cvAddress, currentValue | newValueMask); + else + writeCV(cvAddress, currentValue & ~newValueMask); + } + break; + } + } + } + } + +#ifdef NMRA_DCC_PROCESS_MULTIFUNCTION + // Multi Function Decoders (14-bit address) + else if( pDccMsg->Data[0] < 232 ) + { + uint16_t Address ; + Address = ( ( pDccMsg->Data[0] - 192 ) << 8 ) | pDccMsg->Data[1]; + //TODO should we convert Address to 1 .. 10239 ? + processMultiFunctionMessage( Address, DCC_ADDR_LONG, pDccMsg->Data[2], pDccMsg->Data[3], pDccMsg->Data[4] ) ; + } +#endif +#ifdef NMRA_DCC_PROCESS_SERVICEMODE + } +#endif + } +} + +static void process (os_param_t param, uint8_t prio) +{ + // !!!!!! - this will not happen as we call process task only when data is ready + // if( DccProcState.inServiceMode ) + // { + // if( (system_get_time() - DccProcState.LastServiceModeMillis ) > 20L ) + // { + // clearDccProcState( 0 ) ; + // } + // } + // !!!!!! + + // We need to do this check with interrupts disabled + //SET_TP4; + Msg = DccRx.PacketCopy ; + + #ifdef DCC_DBGVAR + countOf.Tel++; + #endif + + uint8_t xorValue = 0 ; + + for(uint8_t i = 0; i < DccRx.PacketCopy.Size; i++) + xorValue ^= DccRx.PacketCopy.Data[i]; + if(xorValue) { + #ifdef DCC_DBGVAR + NODE_DBG("[dcc_process] Cerr\n"); + NODE_DBG("[dcc_process] Data dump:"); + for(uint8_t i = 0; i < DccRx.PacketCopy.Size; i++) + NODE_DBG(" %x", DccRx.PacketCopy.Data[i]); + NODE_DBG("\n"); + countOf.Err++; + #endif + return;// 0 ; + } else { + NODE_DBG("[dcc_process] Size: %d\tPreambleBits: %d\t%d, %d, %d, %d, %d, %d\n", + Msg.Size, Msg.PreambleBits, Msg.Data[0], Msg.Data[1], Msg.Data[2], Msg.Data[3], Msg.Data[4], Msg.Data[5]); + execDccProcessor( &Msg ); + } + + return;// 1 ; +} + +void dcc_setup(uint8_t pin, uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV) +{ + NODE_DBG("[dcc_setup]\n"); + // Clear all the static member variables + memset( &DccRx, 0, sizeof( DccRx) ); + + MODE_TP1; // only for debugging and timing measurement + MODE_TP2; + MODE_TP3; + MODE_TP4; + CLR_TP1; + CLR_TP2; + CLR_TP3; + CLR_TP4; + + bitMax = MAX_ONEBITFULL; + bitMin = MIN_ONEBITFULL; + DccProcState.Flags = Flags ; + DccProcState.OpsModeAddressBaseCV = OpsModeAddressBaseCV ; + DccProcState.myDccAddress = -1; + DccProcState.inAccDecDCCAddrNextReceivedMode = 0; + + ISREdge = GPIO_PIN_INTR_POSEDGE; + + DccProcState.IntPin = pin; + DccProcState.IntBitmask = 1 << pin_num[pin]; + + + platform_gpio_mode(pin, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP); + NODE_DBG("[dcc_setup] platform_gpio_register_intr_hook - pin: %d, mask: %d\n", DccProcState.IntPin, DccProcState.IntBitmask); + platform_gpio_register_intr_hook(DccProcState.IntBitmask, InterruptHandler); + + gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), GPIO_PIN_INTR_POSEDGE); + + // Set the Bits that control Multifunction or Accessory behaviour + // and if the Accessory decoder optionally handles Output Addressing + // we need to peal off the top two bits + writeCV( CV_29_CONFIG, ( readCV( CV_29_CONFIG ) & ~FLAGS_CV29_BITS ) | (Flags & FLAGS_CV29_BITS) ) ; //!!!!! + + uint8_t doAutoFactoryDefault = 0; + if((Flags & FLAGS_AUTO_FACTORY_DEFAULT) && (readCV(CV_VERSION_ID) == 255) && (readCV(CV_MANUFACTURER_ID) == 255)) + doAutoFactoryDefault = 1; + + writeCV( CV_VERSION_ID, VersionId ) ; + writeCV( CV_MANUFACTURER_ID, ManufacturerId ) ; + + clearDccProcState( 0 ); + + if(notifyCVResetFactoryDefault && doAutoFactoryDefault) + notifyCVResetFactoryDefault(); +} + +void dcc_close() +{ + NODE_DBG("[dcc_close]\n"); + platform_gpio_mode(DccProcState.IntPin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); +} + +void dcc_init() +{ + NODE_DBG("[dcc_init]\n"); + DataReady_taskid = task_get_id((task_callback_t) process); +} \ No newline at end of file diff --git a/app/include/driver/NmraDcc.h b/app/include/driver/NmraDcc.h new file mode 100644 index 0000000000..b864b259c9 --- /dev/null +++ b/app/include/driver/NmraDcc.h @@ -0,0 +1,479 @@ +//------------------------------------------------------------------------ +// +// Model Railroading with Arduino - NmraDcc.h +// +// Copyright (c) 2008 - 2018 Alex Shepherd +// +// This source file is subject of the GNU general public license 2, +// that is available at the world-wide-web at +// http://www.gnu.org/licenses/gpl.txt +// +//------------------------------------------------------------------------ +// +// file: NmraDcc.h +// author: Alex Shepherd +// webpage: http://mrrwa.org/ +// history: 2008-03-20 Initial Version +// 2011-06-26 Migrated into Arduino library from OpenDCC codebase +// 2014 Added getAddr to NmraDcc Geoff Bunza +// 2015-11-06 Martin Pischky (martin@pischky.de): +// Experimental Version to support 14 speed steps +// and new signature of notifyDccSpeed and notifyDccFunc +// 2017-11-29 Ken West (kgw4449@gmail.com): +// Added method and callback headers. +// +//------------------------------------------------------------------------ +// +// purpose: Provide a simplified interface to decode NMRA DCC packets +// and build DCC MutliFunction and Stationary Decoders +// +//------------------------------------------------------------------------ + +// NodeMCU Lua port by @voborsky + +// #define NODE_DEBUG +// #define DCC_DEBUG +// #define DCC_DBGVAR + +// Uncomment the following Line to Enable Service Mode CV Programming +#define NMRA_DCC_PROCESS_SERVICEMODE + +// Uncomment the following line to Enable MultiFunction Decoder Operations +#define NMRA_DCC_PROCESS_MULTIFUNCTION + +// #ifndef NMRADCC_IS_IN +// #define NMRADCC_IS_IN + +#define NMRADCC_VERSION 201 // Version 2.0.1 + +#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte + +typedef struct +{ + uint8_t Size ; + uint8_t PreambleBits ; + uint8_t Data[MAX_DCC_MESSAGE_LEN] ; +} DCC_MSG ; + +//-------------------------------------------------------------------------- +// This section contains the NMRA Assigned DCC Manufacturer Id Codes that +// are used in projects +// +// This value is to be used for CV8 +//-------------------------------------------------------------------------- + +#define MAN_ID_JMRI 0x12 +#define MAN_ID_DIY 0x0D +#define MAN_ID_SILICON_RAILWAY 0x21 + +//-------------------------------------------------------------------------- +// This section contains the Product/Version Id Codes for projects +// +// This value is to be used for CV7 +// +// NOTE: Each Product/Version Id Code needs to be UNIQUE for that particular +// the DCC Manufacturer Id Code +//-------------------------------------------------------------------------- + +// Product/Version Id Codes allocated under: MAN_ID_JMRI + +// Product/Version Id Codes allocated under: MAN_ID_DIY + +// Standard CV Addresses +#define CV_ACCESSORY_DECODER_ADDRESS_LSB 1 +#define CV_ACCESSORY_DECODER_ADDRESS_MSB 9 + +#define CV_MULTIFUNCTION_PRIMARY_ADDRESS 1 +#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB 17 +#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB 18 + +#define CV_VERSION_ID 7 +#define CV_MANUFACTURER_ID 8 +#define CV_29_CONFIG 29 + +typedef enum { + CV29_LOCO_DIR = 0b00000001, /** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */ + CV29_F0_LOCATION = 0b00000010, /** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */ + CV29_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */ + CV29_ADV_ACK = 0b00001000, /** bit 3: ACK, Advanced Acknowledge mode enabled if 1, disabled if 0 */ + CV29_SPEED_TABLE_ENABLE = 0b00010000, /** bit 4: STE, Speed Table Enable, "0" = values in CVs 2, 4 and 6, "1" = Custom table selected by CV 25 */ + CV29_EXT_ADDRESSING = 0b00100000, /** bit 5: "0" = one byte addressing, "1" = two byte addressing */ + CV29_OUTPUT_ADDRESS_MODE = 0b01000000, /** bit 6: "0" = Decoder Address Mode "1" = Output Address Mode */ + CV29_ACCESSORY_DECODER = 0b10000000, /** bit 7: "0" = Multi-Function Decoder Mode "1" = Accessory Decoder Mode */ +} CV_29_BITS; + +typedef enum { +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + SPEED_STEP_14 = 15, /**< ESTOP=0, 1 to 15 */ +#endif + SPEED_STEP_28 = 29, /**< ESTOP=0, 1 to 29 */ + SPEED_STEP_128 = 127 /**< ESTOP=0, 1 to 127 */ +} DCC_SPEED_STEPS; + +typedef enum { + DCC_DIR_REV = 0, /** The locomotive to go in the reverse direction */ + DCC_DIR_FWD = 1, /** The locomotive should move in the forward direction */ +} DCC_DIRECTION; + +typedef enum { + DCC_ADDR_SHORT, /** Short address is used. The range is 0 to 127. */ + DCC_ADDR_LONG, /** Long Address is used. The range is 1 to 10239 */ +} DCC_ADDR_TYPE; + +typedef enum +{ + FN_0_4 = 1, + FN_5_8, + FN_9_12, + FN_13_20, + FN_21_28, +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + FN_0 /** function light is controlled by base line package (14 speed steps) */ +#endif +} FN_GROUP; + +#define FN_BIT_00 0x10 +#define FN_BIT_01 0x01 +#define FN_BIT_02 0x02 +#define FN_BIT_03 0x04 +#define FN_BIT_04 0x08 + +#define FN_BIT_05 0x01 +#define FN_BIT_06 0x02 +#define FN_BIT_07 0x04 +#define FN_BIT_08 0x08 + +#define FN_BIT_09 0x01 +#define FN_BIT_10 0x02 +#define FN_BIT_11 0x04 +#define FN_BIT_12 0x08 + +#define FN_BIT_13 0x01 +#define FN_BIT_14 0x02 +#define FN_BIT_15 0x04 +#define FN_BIT_16 0x08 +#define FN_BIT_17 0x10 +#define FN_BIT_18 0x20 +#define FN_BIT_19 0x40 +#define FN_BIT_20 0x80 + +#define FN_BIT_21 0x01 +#define FN_BIT_22 0x02 +#define FN_BIT_23 0x04 +#define FN_BIT_24 0x08 +#define FN_BIT_25 0x10 +#define FN_BIT_26 0x20 +#define FN_BIT_27 0x40 +#define FN_BIT_28 0x80 + +#ifdef DCC_DBGVAR +typedef struct countOf_t { + unsigned long Tel; + unsigned long Err; +}countOf_t ; + +countOf_t countOf; +#endif + +// Flag values to be logically ORed together and passed into the init() method +#define FLAGS_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address +#define FLAGS_AUTO_FACTORY_DEFAULT 0x02 // Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255 +#define FLAGS_SETCV_CALLED 0x10 // only used internally !! +#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6 +#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7 + +// Flag Bits that are cloned from CV29 relating the DCC Accessory Decoder +#define FLAGS_CV29_BITS (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER) + +#define DCC_RESET 1 +#define DCC_IDLE 2 +#define DCC_SPEED 3 +#define DCC_SPEED_RAW 4 +#define DCC_FUNC 5 +#define DCC_TURNOUT 6 +#define DCC_ACCESSORY 7 +#define DCC_RAW 8 +#define DCC_SERVICEMODE 9 + +#define CV_VALID 10 +#define CV_READ 11 +#define CV_WRITE 12 +#define CV_RESET 13 + + +void dcc_setup(uint8_t pin, uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV ); + + +void dcc_close(); + +void dcc_init(); + + +/************************************************************************************ + Call-back functions +************************************************************************************/ + +/*+ + * notifyDccReset(uint8_t hardReset) Callback for a DCC reset command. + * + * Inputs: + * hardReset - 0 normal reset command. + * 1 hard reset command. + * + * Returns: + * None + */ +extern void notifyDccReset(uint8_t hardReset ) __attribute__ ((weak)); + +/*+ + * notifyDccIdle() Callback for a DCC idle command. + * + * Inputs: + * None + * + * Returns: + * None + */ +extern void notifyDccIdle(void) __attribute__ ((weak)); + + +/*+ + * notifyDccSpeed() Callback for a multifunction decoder speed command. + * The received speed and direction are unpacked to separate values. + * + * Inputs: + * Addr - Active decoder address. + * AddrType - DCC_ADDR_SHORT or DCC_ADDR_LONG. + * Speed - Decoder speed. 0 = Emergency stop + * 1 = Regular stop + * 2 to SpeedSteps = Speed step 1 to max. + * Dir - DCC_DIR_REV or DCC_DIR_FWD + * SpeedSteps - Highest speed, SPEED_STEP_14 = 15 + * SPEED_STEP_28 = 29 + * SPEED_STEP_128 = 127 + * + * Returns: + * None + */ +extern void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) __attribute__ ((weak)); + +/*+ + * notifyDccSpeedRaw() Callback for a multifunction decoder speed command. + * The value in Raw is the unpacked speed command. + * + * Inputs: + * Addr - Active decoder address. + * AddrType - DCC_ADDR_SHORT or DCC_ADDR_LONG. + * Raw - Raw decoder speed command. + * + * Returns: + * None + */ +extern void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) __attribute__ ((weak)); + +/*+ + * notifyDccFunc() Callback for a multifunction decoder function command. + * + * Inputs: + * Addr - Active decoder address. + * AddrType - DCC_ADDR_SHORT or DCC_ADDR_LONG. + * FuncGrp - Function group. FN_0 - 14 speed step headlight function. + * Mask FN_BIT_00. + * FN_0_4 - Functions 0 to 4. Mask FN_BIT_00 - FN_BIT_04 + * FN_5_8 - Functions 5 to 8. Mask FN_BIT_05 - FN_BIT_08 + * FN_9_12 - Functions 9 to 12. Mask FN_BIT_09 - FN_BIT_12 + * FN_13_20 - Functions 13 to 20. Mask FN_BIT_13 - FN_BIT_20 + * FN_21_28 - Functions 21 to 28. Mask FN_BIT_21 - FN_BIT_28 + * FuncState - Function state. Bitmask where active functions have a 1 at that bit. + * You must & FuncState with the appropriate + * FN_BIT_nn value to isolate a given bit. + * + * Returns: + * None + */ +extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) __attribute__ ((weak)); + +/*+ + * notifyDccAccTurnoutBoard() Board oriented callback for a turnout accessory decoder. + * Most useful when CV29_OUTPUT_ADDRESS_MODE is not set. + * Decoders of this type have 4 paired turnout outputs per board. + * OutputPower is 1 if the power is on, and 0 otherwise. + * + * Inputs: + * BoardAddr - Per board address. Equivalent to CV 1 LSB & CV 9 MSB. + * OutputPair - Output pair number. It has a range of 0 to 3. + * Equivalent to upper 2 bits of the 3 DDD bits in the accessory packet. + * Direction - Turnout direction. It has a value of 0 or 1. + * It is equivalent to bit 0 of the 3 DDD bits in the accessory packet. + * OutputPower - Output On/Off. Equivalent to packet C bit. It has these values: + * 0 - Output pair is off. + * 1 - Output pair is on. + * + * Returns: + * None + */ + +extern void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak)); +/*+ + * notifyDccAccTurnoutOutput() Output oriented callback for a turnout accessory decoder. + * Most useful when CV29_OUTPUT_ADDRESS_MODE is not set. + * Decoders of this type have 4 paired turnout outputs per board. + * OutputPower is 1 if the power is on, and 0 otherwise. + * + * Inputs: + * Addr - Per output address. There will be 4 Addr addresses + * per board for a standard accessory decoder with 4 output pairs. + * Direction - Turnout direction. It has a value of 0 or 1. + * Equivalent to bit 0 of the 3 DDD bits in the accessory packet. + * OutputPower - Output On/Off. Equivalent to packet C bit. It has these values: + * 0 - Output is off. + * 1 - Output is on. + * + * Returns: + * None + */ +extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak)); + +/*+ + * notifyDccAccBoardAddrSet() Board oriented callback for a turnout accessory decoder. + * This notification is when a new Board Address is set to the + * address of the next DCC Turnout Packet that is received + * + * This is enabled via the setAccDecDCCAddrNextReceived() method above + * + * Inputs: + * BoardAddr - Per board address. Equivalent to CV 1 LSB & CV 9 MSB. + * per board for a standard accessory decoder with 4 output pairs. + * + * Returns: + * None + */ +extern void notifyDccAccBoardAddrSet( uint16_t BoardAddr) __attribute__ ((weak)); + +/*+ + * notifyDccAccOutputAddrSet() Output oriented callback for a turnout accessory decoder. + * This notification is when a new Output Address is set to the + * address of the next DCC Turnout Packet that is received + * + * This is enabled via the setAccDecDCCAddrNextReceived() method above + * + * Inputs: + * Addr - Per output address. There will be 4 Addr addresses + * per board for a standard accessory decoder with 4 output pairs. + * + * Returns: + * None + */ +extern void notifyDccAccOutputAddrSet( uint16_t Addr) __attribute__ ((weak)); + +/*+ + * notifyDccSigOutputState() Callback for a signal aspect accessory decoder. + * Defined in S-9.2.1 as the Extended Accessory Decoder Control Packet. + * + * Inputs: + * Addr - Decoder address. + * State - 6 bit command equivalent to S-9.2.1 00XXXXXX. + * + * Returns: + * None + */ +extern void notifyDccSigOutputState( uint16_t Addr, uint8_t State) __attribute__ ((weak)); + +/*+ + * notifyDccMsg() Raw DCC packet callback. + * Called with raw DCC packet bytes. + * + * Inputs: + * Msg - Pointer to DCC_MSG structure. The values are: + * Msg->Size - Number of Data bytes in the packet. + * Msg->PreambleBits - Number of preamble bits in the packet. + * Msg->Data[] - Array of data bytes in the packet. + * + * Returns: + * None + */ +extern void notifyDccMsg( DCC_MSG * Msg ) __attribute__ ((weak)); + +/*+ + * notifyCVValid() Callback to determine if a given CV is valid. + * This is called when the library needs to determine + * if a CV is valid. Note: If defined, this callback + * MUST determine if a CV is valid and return the + * appropriate value. If this callback is not defined, + * the library will determine validity. + * + * Inputs: + * CV - CV number. + * Writable - 1 for CV writes. 0 for CV reads. + * + * Returns: + * 1 - CV is valid. + * 0 - CV is not valid. + */ +extern uint8_t notifyCVValid( uint16_t CV, uint8_t Writable ) __attribute__ ((weak)); + +/*+ + * notifyCVRead() Callback to read a CV. + * This is called when the library needs to read + * a CV. Note: If defined, this callback + * MUST return the value of the CV. + * If this callback is not defined, + * the library will read the CV from EEPROM. + * + * Inputs: + * CV - CV number. + * + * Returns: + * Value - Value of the CV. + */ +extern uint8_t notifyCVRead( uint16_t CV) __attribute__ ((weak)); + +/*+ + * notifyCVWrite() Callback to write a value to a CV. + * This is called when the library needs to write + * a CV. Note: If defined, this callback + * MUST write the Value to the CV and return the value of the CV. + * If this callback is not defined, + * the library will read the CV from EEPROM. + * + * Inputs: + * CV - CV number. + * Value - Value of the CV. + * + * Returns: + * Value - Value of the CV. + */ +extern uint8_t notifyCVWrite( uint16_t CV, uint8_t Value) __attribute__ ((weak)); + +/*+ + * notifyCVResetFactoryDefault() Called when CVs must be reset. + * This is called when CVs must be reset + * to their factory defaults. This callback + * should write the factory default value of + * relevent CVs using the setCV() method. + * setCV() must not block whens this is called. + * Test with isSetCVReady() prior to calling setCV() + * + * Inputs: + * None + * * + * Returns: + * None + */ +extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak)); + +/*+ + * notifyServiceMode(bool) Called when state of 'inServiceMode' changes + * + * Inputs: + * bool state of inServiceMode + * * + * Returns: + * None + */ +extern void notifyServiceMode(bool) __attribute__ ((weak)); + +// Deprecated, only for backward compatibility with version 1.4.2. +// Don't use in new designs. These functions may be dropped in future versions +// extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State ) __attribute__ ((weak)); +// extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State) __attribute__ ((weak)); diff --git a/app/include/user_modules.h b/app/include/user_modules.h index 7985325497..c04a6bdbbf 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -21,6 +21,7 @@ //#define LUA_USE_MODULES_COLOR_UTILS //#define LUA_USE_MODULES_CRON //#define LUA_USE_MODULES_CRYPTO +//#define LUA_USE_MODULES_DCC #define LUA_USE_MODULES_DHT //#define LUA_USE_MODULES_ENCODER //#define LUA_USE_MODULES_ENDUSER_SETUP // USE_DNS in dhcpserver.h needs to be enabled for this module to work. diff --git a/app/modules/dcc.c b/app/modules/dcc.c new file mode 100644 index 0000000000..c979880f92 --- /dev/null +++ b/app/modules/dcc.c @@ -0,0 +1,290 @@ +// NodeMCU Lua port by @voborsky +// Module for handling NMRA DCC protocol +// #define NODE_DEBUG + +#include "module.h" +#include "lauxlib.h" +#include "platform.h" +#include "driver/NmraDcc.h" + +#ifdef LUA_USE_MODULES_DCC +#if !defined(GPIO_INTERRUPT_ENABLE) || !defined(GPIO_INTERRUPT_HOOK_ENABLE) +#error Must have GPIO_INTERRUPT and GPIO_INTERRUPT_HOOK if using DCC module +#endif +#endif + +#define TYPE "Type" +#define OPERATION "Operation" + +static inline void register_lua_cb(lua_State* L,int* cb_ref){ + int ref=luaL_ref(L, LUA_REGISTRYINDEX); + if( *cb_ref != LUA_NOREF){ + luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref); + } + *cb_ref = ref; +} + +static inline void unregister_lua_cb(lua_State* L, int* cb_ref){ + if(*cb_ref != LUA_NOREF){ + luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref); + *cb_ref = LUA_NOREF; + } +} + +static int notify_cb = LUA_NOREF; +static int CV_cb = LUA_NOREF; + +// DCC commands + +void cbInit(lua_State* L, uint16_t command) { + if(notify_cb == LUA_NOREF) + return; + lua_rawgeti(L, LUA_REGISTRYINDEX, notify_cb); + lua_pushinteger(L, command); + lua_newtable(L); +} + +void cbAddFieldInteger(lua_State* L, uint16_t Value, char *Field) { + lua_pushinteger(L, Value); + lua_setfield(L, -2, Field); +} + +void notifyDccReset(uint8_t hardReset ) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_RESET); + cbAddFieldInteger(L, hardReset, "hardReset"); + lua_call(L, 2, 0); +} + +void notifyDccIdle(void) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_IDLE); + lua_call(L, 2, 0); +} + +void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_SPEED); + cbAddFieldInteger(L, Addr, "Addr"); + cbAddFieldInteger(L, AddrType, "AddrType"); + cbAddFieldInteger(L, Speed, "Speed"); + cbAddFieldInteger(L, Dir, "Dir"); + cbAddFieldInteger(L, SpeedSteps, "SpeedSteps"); + lua_call(L, 2, 0); +} + +void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_SPEED_RAW); + cbAddFieldInteger(L, Addr, "Addr"); + cbAddFieldInteger(L, AddrType, "AddrType"); + cbAddFieldInteger(L, Raw, "Raw"); + lua_call(L, 2, 0); +} + +void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_FUNC); + cbAddFieldInteger(L, Addr, "Addr"); + cbAddFieldInteger(L, AddrType, "AddrType"); + cbAddFieldInteger(L, FuncGrp, "FuncGrp"); + cbAddFieldInteger(L, FuncState, "FuncState"); + lua_call(L, 2, 0); +} + +void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower ) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_TURNOUT); + cbAddFieldInteger(L, BoardAddr, "BoardAddr"); + cbAddFieldInteger(L, OutputPair, "OutputPair"); + cbAddFieldInteger(L, Direction, "Direction"); + cbAddFieldInteger(L, OutputPower, "OutputPower"); + lua_call(L, 2, 0); +} + +void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_TURNOUT); + cbAddFieldInteger(L, Addr, "Addr"); + cbAddFieldInteger(L, Direction, "Direction"); + cbAddFieldInteger(L, OutputPower, "OutputPower"); + lua_call(L, 2, 0); +} + +void notifyDccAccBoardAddrSet( uint16_t BoardAddr) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_ACCESSORY); + cbAddFieldInteger(L, BoardAddr, "BoardAddr"); + lua_call(L, 2, 0); +} + +void notifyDccAccOutputAddrSet( uint16_t Addr) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_ACCESSORY); + cbAddFieldInteger(L, Addr, "Addr"); + lua_call(L, 2, 0); +} + +void notifyDccSigOutputState( uint16_t Addr, uint8_t State) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_ACCESSORY); + cbAddFieldInteger(L, State, "State"); + lua_call(L, 2, 0); +} + +void notifyDccMsg( DCC_MSG * Msg ) { + lua_State* L = lua_getstate(); + cbInit(L, DCC_RAW); + cbAddFieldInteger(L, Msg->Size, "Size"); + cbAddFieldInteger(L, Msg->PreambleBits, "PreambleBits"); + char field[8]; + for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ ) { + ets_sprintf(field, "Data%d", i); + cbAddFieldInteger(L, Msg->Data[i], field); + } + lua_call(L, 2, 0); +} + +void notifyServiceMode(bool InServiceMode){ + lua_State* L = lua_getstate(); + cbInit(L, DCC_SERVICEMODE); + cbAddFieldInteger(L, InServiceMode, "InServiceMode"); + lua_call(L, 2, 0); +} + +// CV handling + +uint8_t notifyCVValid( uint16_t CV, uint8_t Writable ) { + lua_State* L = lua_getstate(); + if(notify_cb == LUA_NOREF) + return 0; + lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb); + lua_pushinteger(L, CV_VALID); + lua_newtable(L); + cbAddFieldInteger(L, CV, "CV"); + cbAddFieldInteger(L, Writable, "Writable"); + lua_call(L, 2, 1); + uint8 result = lua_tointeger(L, -1); + lua_pop(L, 1); + return result; +} + +uint8_t notifyCVRead( uint16_t CV) { + lua_State* L = lua_getstate(); + if(notify_cb == LUA_NOREF) + return 0; + lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb); + lua_pushinteger(L, CV_READ); + lua_newtable(L); + cbAddFieldInteger(L, CV, "CV"); + lua_call(L, 2, 1); + uint8 result = lua_tointeger(L, -1); + lua_pop(L, 1); + return result; +} + +uint8_t notifyCVWrite( uint16_t CV, uint8_t Value) { + lua_State* L = lua_getstate(); + if(notify_cb == LUA_NOREF) + return 0; + lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb); + lua_pushinteger(L, CV_WRITE); + lua_newtable(L); + cbAddFieldInteger(L, CV, "CV"); + cbAddFieldInteger(L, Value, "Value"); + lua_call(L, 2, 0); + return Value; +} + +void notifyCVResetFactoryDefault(void) { + lua_State* L = lua_getstate(); + if(notify_cb == LUA_NOREF) + return; + lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb); + lua_pushinteger(L, CV_RESET); + lua_call(L, 1, 0); +} + +static int dcc_lua_setup(lua_State* L) { + NODE_DBG("[dcc_lua_setup]\n"); + if (!lua_isnumber(L, 6) && !lua_isnumber(L, 7)) { + return luaL_error(L, "wrong arg range"); + } + uint8_t pin = luaL_checkinteger(L, 1); + luaL_argcheck(L, platform_gpio_exists(pin) && pin>0, 1, "Invalid interrupt pin"); + + if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) + { + lua_pushvalue(L, 2); + register_lua_cb(L, ¬ify_cb); + } + else + { + unregister_lua_cb(L, ¬ify_cb); + } + + uint8_t ManufacturerId = luaL_checkinteger(L, 3); + uint8_t VersionId = luaL_checkinteger(L, 4); + uint8_t Flags = luaL_checkinteger(L, 5); + uint8_t OpsModeAddressBaseCV = luaL_checkinteger(L, 6); + + if (lua_type(L, 7) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) + { + lua_pushvalue(L, 7); + register_lua_cb(L, &CV_cb); + } + else + { + unregister_lua_cb(L, &CV_cb); + } + + NODE_DBG("[dcc_lua_setup] Enabling interrupt on PIN %d\n", pin); + dcc_setup(pin, ManufacturerId, VersionId, Flags, OpsModeAddressBaseCV ); + + return 0; +} + +static int dcc_lua_close(lua_State* L) { + dcc_close(); + unregister_lua_cb(L, ¬ify_cb); + return 0; +} + +int luaopen_dcc( lua_State *L ) { + NODE_DBG("[dcc_luaopen]\n"); + dcc_init(); + //DccRx.lua_cb_ref = LUA_NOREF; + return 0; +} + +// Module function map +LROT_BEGIN( dcc ) + LROT_FUNCENTRY( setup, dcc_lua_setup ) + LROT_FUNCENTRY( close, dcc_lua_close ) + + LROT_NUMENTRY( DCC_RESET, DCC_RESET ) + LROT_NUMENTRY( DCC_IDLE, DCC_IDLE ) + LROT_NUMENTRY( DCC_SPEED, DCC_SPEED ) + LROT_NUMENTRY( DCC_SPEED_RAW, DCC_SPEED_RAW ) + LROT_NUMENTRY( DCC_FUNC, DCC_FUNC ) + LROT_NUMENTRY( DCC_TURNOUT, DCC_TURNOUT ) + LROT_NUMENTRY( DCC_ACCESSORY, DCC_ACCESSORY ) + LROT_NUMENTRY( DCC_RAW, DCC_RAW ) + LROT_NUMENTRY( DCC_SERVICEMODE, DCC_SERVICEMODE ) + + LROT_NUMENTRY( CV_VALID, CV_VALID ) + LROT_NUMENTRY( CV_READ, CV_READ ) + LROT_NUMENTRY( CV_WRITE, CV_WRITE ) + LROT_NUMENTRY( CV_RESET, CV_RESET ) + + LROT_NUMENTRY( MAN_ID_JMRI, MAN_ID_JMRI) + LROT_NUMENTRY( MAN_ID_DIY, MAN_ID_DIY) + LROT_NUMENTRY( MAN_ID_SILICON_RAILWAY, MAN_ID_SILICON_RAILWAY) + + LROT_NUMENTRY( FLAGS_MY_ADDRESS_ONLY, FLAGS_MY_ADDRESS_ONLY ) + LROT_NUMENTRY( FLAGS_AUTO_FACTORY_DEFAULT, FLAGS_AUTO_FACTORY_DEFAULT ) + LROT_NUMENTRY( FLAGS_OUTPUT_ADDRESS_MODE, FLAGS_OUTPUT_ADDRESS_MODE ) + LROT_NUMENTRY( FLAGS_DCC_ACCESSORY_DECODER, FLAGS_DCC_ACCESSORY_DECODER ) +LROT_END( dcc, NULL, 0 ) + +NODEMCU_MODULE(DCC, "dcc", dcc, luaopen_dcc); diff --git a/docs/modules/dcc.md b/docs/modules/dcc.md new file mode 100644 index 0000000000..2a55fda20d --- /dev/null +++ b/docs/modules/dcc.md @@ -0,0 +1,118 @@ +# DCC module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2019-12-28 | [vsky279](https://github.com/vsky279) | [vsky279](https://github.com/vsky279) | [dcc.c](../../app/modules/dcc.c)| + +The dcc module implements decoder of the [National Model Railroad Association](https://www.nmra.org/) (NMRA) Digital Command Control (DCC) decoder - see [DCC wiki](https://dccwiki.com/Introduction_to_DCC) for details. + +The hardware needed to decode the DCC signal can be built based on different DCC decoders implementation for Arduino, for inspiration see [https://mrrwa.org/dcc-decoder-interface/](https://mrrwa.org/dcc-decoder-interface/). Basically the signal from the DCC bus is connected via an optocoupler to any GPIO pin. The DCC bus can be also used to power the ESP. + +The module is based on the project NmraDcc [https://github.com/mrrwa/NmraDcc](https://github.com/mrrwa/NmraDcc) by Alex Shepherd. The module is based on the version from May 2005, commit [6d12e6cd3f5f520020d49946652a94c1e3473f6b](https://github.com/mrrwa/NmraDcc/tree/6d12e6cd3f5f520020d49946652a94c1e3473f6b). + +## dcc.setup() + +Initializes the dcc module and links callback functions. + +#### Syntax +`dcc.setup(DCC_command, ManufacturerId, VersionId, Flags, OpsModeAddressBaseCV, CV_callback)` + +#### Parameters +- `DCC_command(cmd, params)` calllback function that is called when a DCC command is decoded. `cmd` parameters is one of the following values. `params` contains a collection of parameters specific to given command. + - `dcc.DCC_RESET` no additional parameters, `params` is `nil`. + - `dcc.DCC_IDLE` no additional parameters, `params` is `nil`. + - `dcc.DCC_SPEED` parameters collection members are `Addr`, `AddrType`, `Speed`,`Dir`, `SpeedSteps`. + - `dcc.DCC_SPEED_RAW` parameters collection members are `Addr`, `AddrType`, `Raw`. + - `dcc.DCC_FUNC` parameters collection members are `Addr`, `AddrType`, `FuncGrp`,`FuncState`. + - `dcc.DCC_TURNOUT` parameters collection members are `BoardAddr`, `OutputPair`, `Direction`,`OutputPower` or `Addr`, `Direction`,`OutputPower`. + - `dcc.DCC_ACCESSORY` parameters collection has one member `BoardAddr` or `Addr` or `State`. + - `dcc.DCC_RAW` parameters collection member are `Size`, `PreambleBits`, `Data1` to `Data6`. + - `dcc.DCC_SERVICEMODE` parameters collection has one member `InServiceMode`. +- `ManufacturerId` Manufacturer ID returned in CV 8. Commonly `dcc.MAN_ID_DIY`. +- `VersionId` Version ID returned in CV 7. +- `Flags` one of or combination (OR operator) of + - `dcc.FLAGS_MY_ADDRESS_ONLY`Only process packets with My Address. + - `dcc.FLAGS_DCC_ACCESSORY_DECODER` Decoder is an accessory decode. + - `dcc.FLAGS_OUTPUT_ADDRESS_MODE` This flag applies to accessory decoders only. Accessory decoders normally have 4 paired outputs and a single address refers to all 4 outputs. Setting this flag causes each address to refer to a single output. + - `dcc.FLAGS_AUTO_FACTORY_DEFAULT` Call DCC command callback with `dcc.CV_RESET` command if CV 7 & 8 == 255. +- `OpsModeAddressBaseCV` Ops Mode base address. Set it to 0? +- `CV_callback(operation, param)` callback function that is called when any manipulation with CV ([Configuarion Variable](https://dccwiki.com/Configuration_Variable)) is requested. + - `dcc.CV_VALID`to determine if a given CV is valid. This callback must determine if a CV is valid and return the appropriate value. `param` collection has members `CV` and `Value`. + - `dcc.CV_READ` to read a CV. This callback must return the value of the CV. `param` collection has one member `CV` determing the CV number to be read. + - `dcc.CV_WRITE` to write a value to a CV. This callback must write the Value to the CV and return the value of the CV. `param` collection has members `CV` and `Value`. + - `dcc.CV_RESET` Called when CVs must be reset to their factory defaults. + +#### Returns +`nil` + +#### Example +`bit` module is used in the example though it is not needed for the dcc module functionality. +```lua +local PIN = 2 -- GPIO4 + +local addr = 0x12a + +CV = {[29]=0, + [1]=bit.band(addr, 0x3f), --CV_ACCESSORY_DECODER_ADDRESS_LSB (6 bits) + [9]=bit.band(bit.rshift(addr,6), 0x7) --CV_ACCESSORY_DECODER_ADDRESS_MSB (3 bits) + } + +local function DCC_command(cmd, params) + if cmd == dcc.DCC_IDLE then + return + elseif cmd == dcc.DCC_TURNOUT then + print("Turnout command") + elseif cmd == dcc.DCC_SPEED then + print("Speed command") + elseif cmd == dcc.DCC_FUNC then + print("Function command") + else + print("Other command", cmd) + end + + for i,j in pairs(params) do + print(i, j) + end + print(("="):rep(80)) +end + +local function CV_callback(operation, param) + local oper = "" + local result + if operation == dcc.CV_WRITE then + oper = "Write" + CV[param.CV]=param.Value + elseif operation == dcc.CV_READ then + oper = "Read" + result = CV[param.CV] + elseif operation == dcc.CV_VALID then + oper = "Valid" + result = 1 + elseif operation == CV_RESET then + oper = "Reset" + CV = {} + end + print(("[CV_callback] %s CV %d%s"):format(oper, param.CV or `nil`, param.Value and "\tValue: "..param.Value or "\tValue: nil")) + return result +end + +dcc.setup(PIN, + DCC_command, + dcc.MAN_ID_DIY, 1, + --bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT, dcc.FLAGS_DCC_ACCESSORY_DECODER, dcc.FLAGS_MY_ADDRESS_ONLY), + bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT), + 0, -- ??? + CV_callback) +``` + +## dcc.close() + +Stops the dcc module. + +#### Syntax +`dcc.close()` + +#### Parameters +`nil` + +#### Returns +`nil` diff --git a/lua_examples/dcc/dcc.lua b/lua_examples/dcc/dcc.lua new file mode 100644 index 0000000000..922b89d388 --- /dev/null +++ b/lua_examples/dcc/dcc.lua @@ -0,0 +1,86 @@ +-- Simple example for responding to NMRA DCC commands +-- author @voborsky +local PIN = 2 -- GPIO4 + +local addr = 0x12a + +CV = {[29]=0, + [1]=bit.band(addr, 0x3f), --CV_ACCESSORY_DECODER_ADDRESS_LSB (6 bits) + [9]=bit.band(bit.rshift(addr,6), 0x7) --CV_ACCESSORY_DECODER_ADDRESS_MSB (3 bits) + } + +local function deepcopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + setmetatable(copy, deepcopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +local cmd_last +local params_last + +local function is_new(cmd, params) + if cmd ~= cmd_last then return true end + for i,j in pairs(params) do + if params_last[i] ~= j then return true end + end + return false +end + +local function DCC_command(cmd, params) + if not is_new(cmd, params) then return end + if cmd == dcc.DCC_IDLE then + return + elseif cmd == dcc.DCC_TURNOUT then + print("Turnout command") + elseif cmd == dcc.DCC_SPEED then + print("Speed command") + elseif cmd == dcc.DCC_FUNC then + print("Function command") + else + print("Other command", cmd) + end + + for i,j in pairs(params) do + print(i, j) + end + print(("="):rep(80)) + cmd_last = cmd + params_last = deepcopy(params) +end + +local function CV_callback(operation, param) + local oper = "" + local result + if operation == dcc.CV_WRITE then + oper = "Write" + CV[param.CV]=param.Value + elseif operation == dcc.CV_READ then + oper = "Read" + result = CV[param.CV] + elseif operation == dcc.CV_VALID then + oper = "Valid" + result = 1 + elseif operation == CV_RESET then + oper = "Reset" + CV = {} + end + print(("[CV_callback] %s CV %d%s"):format(oper, param.CV, param.Value and "\tValue: "..param.Value or "\tValue: nil")) + return result +end + +dcc.setup(PIN, + DCC_command, + dcc.MAN_ID_DIY, 1, + --bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT, dcc.FLAGS_DCC_ACCESSORY_DECODER, dcc.FLAGS_MY_ADDRESS_ONLY), -- Accessories (turnouts) decoder + bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT), -- Cab (train) decoder + 0, -- ??? + CV_callback) diff --git a/mkdocs.yml b/mkdocs.yml index 11be8c881c..16c1685950 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,6 +67,7 @@ pages: - 'color-utils': 'modules/color-utils.md' - 'cron': 'modules/cron.md' - 'crypto': 'modules/crypto.md' + - 'dcc': 'modules/dcc.md' - 'dht': 'modules/dht.md' - 'encoder': 'modules/encoder.md' - 'enduser setup / captive portal / WiFi manager': 'modules/enduser-setup.md' From bcb669a4a0a49e857186093eb79b6f27a3158ad7 Mon Sep 17 00:00:00 2001 From: galjonsfigur <44552519+galjonsfigur@users.noreply.github.com> Date: Tue, 31 Dec 2019 00:53:54 +0100 Subject: [PATCH 23/59] Polish Lua examples (#2846) * Add missing globals from luacheck config * Fix luacheck warnings in all lua files * Re-enable luacheck in Travis * Speed up Travis by using preinstalled LuaRocks * Fix more luacheck warnings in httpserver lua module * Fix DCC module and add appropriate definitions to luacheck config. * Change inline comments from ignoring block to only ignore specific line * Add Luacheck for Windows and enable it for both Windows and Linux * Change luacheck exceptions and fix errors from 1st round of polishing * Add retry and timeout params to wget --- .travis.yml | 4 +- lua_examples/adc_rgb.lua | 64 +++++++------ lua_examples/dcc/dcc.lua | 25 ++--- lua_examples/email/read_email_imap.lua | 55 ++++++----- lua_examples/email/send_email_smtp.lua | 58 ++++++----- lua_examples/irsend.lua | 2 + lua_examples/lfs/HTTP_OTA.lua | 2 +- lua_examples/lfs/_init.lua | 2 +- lua_examples/lfs/dummy_strings.lua | 4 +- lua_examples/lfs/lfs_fragments.lua | 8 +- lua_examples/luaOTA/_doTick.lua | 1 + lua_examples/luaOTA/_provision.lua | 35 +++---- lua_examples/luaOTA/check.lua | 15 ++- lua_examples/luaOTA/default.lua | 3 +- lua_examples/luaOTA/luaOTAserver.lua | 9 +- lua_examples/make_phone_call.lua | 18 ++-- lua_examples/mcp23008/mcp23008_buttons.lua | 20 ++-- lua_examples/mcp23008/mcp23008_leds.lua | 29 +++--- lua_examples/mqtt/mqtt2cloud.lua | 62 ++++++------ lua_examples/mqtt/mqtt_file.lua | 50 +++++----- lua_examples/pcm/play_file.lua | 28 +++--- lua_examples/send_text_message.lua | 18 ++-- lua_examples/sjson-streaming.lua | 23 +++-- lua_examples/somfy.lua | 56 ++++++----- lua_examples/tcp2uart.lua | 32 ++++--- lua_examples/timezone/tz.lua | 5 +- lua_examples/u8g2/graphics_test.lua | 75 ++++++++------- lua_examples/ucglib/GT_box.lua | 1 + lua_examples/ucglib/GT_clip.lua | 1 + lua_examples/ucglib/GT_color_test.lua | 4 +- lua_examples/ucglib/GT_cross.lua | 1 + lua_examples/ucglib/GT_fonts.lua | 1 + lua_examples/ucglib/GT_gradient.lua | 1 + lua_examples/ucglib/GT_graphics_test.lua | 1 + lua_examples/ucglib/GT_pixel_and_lines.lua | 1 + lua_examples/ucglib/GT_text.lua | 1 + lua_examples/ucglib/GT_triangle.lua | 1 + lua_examples/ucglib/GraphicsTest.lua | 62 ++++++------ lua_examples/ucglib/HelloWorld.lua | 24 ++--- lua_examples/ucglib/UcgLogo.lua | 26 ++--- lua_examples/webap_toggle_pin.lua | 12 ++- lua_modules/bh1750/bh1750.lua | 6 +- lua_modules/bh1750/bh1750_Example1.lua | 24 +++-- lua_modules/bh1750/bh1750_Example2.lua | 78 +++++++-------- lua_modules/ds18b20/ds18b20-example.lua | 72 +++++++------- lua_modules/ds18b20/ds18b20-web.lua | 48 +++++----- lua_modules/ds18b20/ds18b20.lua | 29 +++--- lua_modules/ds3231/ds3231-example.lua | 20 ++-- lua_modules/ds3231/ds3231-web.lua | 95 +++++++++---------- lua_modules/ds3231/ds3231.lua | 2 +- lua_modules/email/imap.lua | 24 +++-- lua_modules/fifo/fifosocktest.lua | 72 +++++++------- lua_modules/ftp/ftpserver.lua | 47 ++++----- lua_modules/hdc1000/HDC1000-example.lua | 23 +++-- lua_modules/hdc1000/HDC1000.lua | 4 +- lua_modules/http/http-example.lua | 4 +- lua_modules/http/httpserver.lua | 24 ++--- lua_modules/lm92/lm92.lua | 9 +- lua_modules/mcp23008/mcp23008.lua | 6 +- lua_modules/redis/redis.lua | 2 +- .../yeelink/Example_for_Yeelink_Lib.lua | 6 +- lua_modules/yeelink/yeelink_lib.lua | 34 ++++--- tools/luacheck_config.lua | 46 ++++++++- tools/luacheck_config_helper.lua | 6 ++ tools/travis/run-luacheck-linux.sh | 72 ++++++++++++++ tools/travis/run-luacheck-windows.sh | 13 +++ tools/travis/run-luacheck.sh | 17 ---- 67 files changed, 905 insertions(+), 718 deletions(-) create mode 100755 tools/travis/run-luacheck-linux.sh create mode 100644 tools/travis/run-luacheck-windows.sh delete mode 100644 tools/travis/run-luacheck.sh diff --git a/.travis.yml b/.travis.yml index 7994a09736..6a4f2ae70c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ addons: packages: - python-serial - srecord + - luarocks cache: - directories: - cache @@ -33,4 +34,5 @@ script: - echo "checking:" - find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo - find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 $LUACC -p -# - if [ "$OS" = "linux" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/run-luacheck.sh || true ; fi +- if [ "$OS" = "linux" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/run-luacheck-linux.sh; fi +- if [ "$OS" = "windows" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/run-luacheck-windows.sh; fi diff --git a/lua_examples/adc_rgb.lua b/lua_examples/adc_rgb.lua index 6b094ced91..9da9d805df 100644 --- a/lua_examples/adc_rgb.lua +++ b/lua_examples/adc_rgb.lua @@ -1,43 +1,47 @@ -- --- Light sensor on ADC(0), RGB LED connected to gpio12(6) Green, gpio13(7) Blue & gpio15(8) Red. +-- Light sensor on adc0(A0), RGB LED connected to gpio12(D6) Green, gpio13(D7) Blue & gpio15(D8) Red. -- This works out of the box on the typical ESP8266 evaluation boards with Battery Holder -- -- It uses the input from the sensor to drive a "rainbow" effect on the RGB LED -- Includes a very "pseudoSin" function -- +-- Required C Modules: adc, tmr, pwm -function led(r,Sg,b) - pwm.setduty(8,r) - pwm.setduty(6,g) - pwm.setduty(7,b) +local redLed, greenLed, blueLed = 8, 6, 7 + +local function setRGB(r,g,b) + pwm.setduty(redLed, r) + pwm.setduty(greenLed, g) + pwm.setduty(blueLed, b) end --- this is perhaps the lightest weight sin function in existance --- Given an integer from 0..128, 0..512 appximating 256 + 256 * sin(idx*Pi/256) +-- this is perhaps the lightest weight sin function in existence +-- Given an integer from 0..128, 0..512 approximating 256 + 256 * sin(idx*Pi/256) -- This is first order square approximation of sin, it's accurate around 0 and any multiple of 128 (Pi/2), --- 92% accurate at 64 (Pi/4). -function pseudoSin (idx) - idx = idx % 128 - lookUp = 32 - idx % 64 - val = 256 - (lookUp * lookUp) / 4 - if (idx > 64) then - val = - val; - end - return 256+val +-- 92% accurate at 64 (Pi/4). +local function pseudoSin(idx) + idx = idx % 128 + local lookUp = 32 - idx % 64 + local val = 256 - (lookUp * lookUp) / 4 + if (idx > 64) then + val = - val; + end + return 256+val end -pwm.setup(6,500,512) -pwm.setup(7,500,512) -pwm.setup(8,500,512) -pwm.start(6) -pwm.start(7) -pwm.start(8) +do + pwm.setup(redLed, 500, 512) + pwm.setup(greenLed,500, 512) + pwm.setup(blueLed, 500, 512) + pwm.start(redLed) + pwm.start(greenLed) + pwm.start(blueLed) -tmr.alarm(1,20,1,function() - idx = 3 * adc.read(0) / 2 - r = pseudoSin(idx) - g = pseudoSin(idx + 43) - b = pseudoSin(idx + 85) - led(r,g,b) - idx = (idx + 1) % 128 - end) + tmr.create():alarm(20, tmr.ALARM_AUTO, function() + local idx = 3 * adc.read(0) / 2 + local r = pseudoSin(idx) + local g = pseudoSin(idx + 43) -- ~1/3rd of 128 + local b = pseudoSin(idx + 85) -- ~2/3rd of 128 + setRGB(r,g,b) + end) +end diff --git a/lua_examples/dcc/dcc.lua b/lua_examples/dcc/dcc.lua index 922b89d388..33cf1d1701 100644 --- a/lua_examples/dcc/dcc.lua +++ b/lua_examples/dcc/dcc.lua @@ -4,7 +4,7 @@ local PIN = 2 -- GPIO4 local addr = 0x12a -CV = {[29]=0, +local CV = {[29]=0, [1]=bit.band(addr, 0x3f), --CV_ACCESSORY_DECODER_ADDRESS_LSB (6 bits) [9]=bit.band(bit.rshift(addr,6), 0x7) --CV_ACCESSORY_DECODER_ADDRESS_MSB (3 bits) } @@ -37,18 +37,18 @@ end local function DCC_command(cmd, params) if not is_new(cmd, params) then return end - if cmd == dcc.DCC_IDLE then + if cmd == dcc.DCC_IDLE then return elseif cmd == dcc.DCC_TURNOUT then - print("Turnout command") + print("Turnout command") elseif cmd == dcc.DCC_SPEED then - print("Speed command") + print("Speed command") elseif cmd == dcc.DCC_FUNC then - print("Function command") + print("Function command") else print("Other command", cmd) end - + for i,j in pairs(params) do print(i, j) end @@ -69,18 +69,21 @@ local function CV_callback(operation, param) elseif operation == dcc.CV_VALID then oper = "Valid" result = 1 - elseif operation == CV_RESET then + elseif operation == dcc.CV_RESET then oper = "Reset" CV = {} end - print(("[CV_callback] %s CV %d%s"):format(oper, param.CV, param.Value and "\tValue: "..param.Value or "\tValue: nil")) + print(("[CV_callback] %s CV %d%s") + :format(oper, param.CV, param.Value and "\tValue: "..param.Value or "\tValue: nil")) return result end dcc.setup(PIN, DCC_command, - dcc.MAN_ID_DIY, 1, - --bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT, dcc.FLAGS_DCC_ACCESSORY_DECODER, dcc.FLAGS_MY_ADDRESS_ONLY), -- Accessories (turnouts) decoder - bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT), -- Cab (train) decoder + dcc.MAN_ID_DIY, 1, + -- Accessories (turnouts) decoder: + --bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT, dcc.FLAGS_DCC_ACCESSORY_DECODER, dcc.FLAGS_MY_ADDRESS_ONLY), + -- Cab (train) decoder + bit.bor(dcc.FLAGS_AUTO_FACTORY_DEFAULT), 0, -- ??? CV_callback) diff --git a/lua_examples/email/read_email_imap.lua b/lua_examples/email/read_email_imap.lua index 0729b66fce..97fa7b77b0 100644 --- a/lua_examples/email/read_email_imap.lua +++ b/lua_examples/email/read_email_imap.lua @@ -6,7 +6,7 @@ -- was tested with an AOL and Time Warner cable email accounts (GMail and other services who do -- not support no SSL access will not work). -require("imap") +local imap = require("imap") local IMAP_USERNAME = "email@domain.com" local IMAP_PASSWORD = "password" @@ -25,21 +25,13 @@ local SSID_PASSWORD = "password" local count = 0 -- we will send several IMAP commands/requests, this variable helps keep track of which one to send - --- configure the ESP8266 as a station -wifi.setmode(wifi.STATION) -wifi.sta.config(SSID,SSID_PASSWORD) -wifi.sta.autoconnect(1) - --- create an unencrypted connection -local imap_socket = net.createConnection(net.TCP,0) - +local imap_socket, timer --- -- @name setup -- @description A call back function used to begin reading email -- upon sucessfull connection to the IMAP server -function setup(sck) +local function setup(sck) -- Set the email user name and password, IMAP tag, and if debugging output is needed imap.config(IMAP_USERNAME, IMAP_PASSWORD, @@ -49,19 +41,16 @@ function setup(sck) imap.login(sck) end -imap_socket:on("connection",setup) -- call setup() upon connection -imap_socket:connect(IMAP_PORT,IMAP_SERVER) -- connect to the IMAP server - local subject = "" local from = "" -local message = "" +local body = "" --- -- @name do_next -- @description A call back function for a timer alarm used to check if the previous -- IMAP command reply has been processed. If the IMAP reply has been processed -- this function will call the next IMAP command function necessary to read the email -function do_next() +local function do_next() -- Check if the IMAP reply was processed if(imap.response_processed() == true) then @@ -75,15 +64,18 @@ function do_next() count = count + 1 elseif (count == 1) then -- After examining/selecting the INBOX folder we can begin to retrieve emails. - imap.fetch_header(imap_socket,imap.get_most_recent_num(),"SUBJECT") -- Retrieve the SUBJECT of the first/newest email + -- Retrieve the SUBJECT of the first/newest email + imap.fetch_header(imap_socket,imap.get_most_recent_num(),"SUBJECT") count = count + 1 elseif (count == 2) then subject = imap.get_header() -- store the SUBJECT response in subject - imap.fetch_header(imap_socket,imap.get_most_recent_num(),"FROM") -- Retrieve the FROM of the first/newest email + -- Retrieve the FROM of the first/newest email + imap.fetch_header(imap_socket,imap.get_most_recent_num(),"FROM") count = count + 1 elseif (count == 3) then from = imap.get_header() -- store the FROM response in from - imap.fetch_body_plain_text(imap_socket,imap.get_most_recent_num()) -- Retrieve the BODY of the first/newest email + -- Retrieve the BODY of the first/newest email + imap.fetch_body_plain_text(imap_socket,imap.get_most_recent_num()) count = count + 1 elseif (count == 4) then body = imap.get_body() -- store the BODY response in body @@ -92,9 +84,9 @@ function do_next() else -- display the email contents - -- create patterns to strip away IMAP protocl text from actual message - pattern1 = "(\*.+\}\r\n)" -- to remove "* n command (BODY[n] {n}" - pattern2 = "(%)\r\n.+)" -- to remove ") t1 OK command completed" + -- create patterns to strip away IMAP protocol text from actual message + local pattern1 = "%*.*}\n" -- to remove "* n command (BODY[n] {n}" + local pattern2 = "%)\n.+" -- to remove ") t1 OK command completed" from = string.gsub(from,pattern1,"") from = string.gsub(from,pattern2,"") @@ -108,7 +100,7 @@ function do_next() body = string.gsub(body,pattern2,"") print("Message: " .. body) - tmr.stop(0) -- Stop the timer alarm + timer:stop() -- Stop the timer alarm imap_socket:close() -- close the IMAP socket collectgarbage() -- clean up end @@ -116,5 +108,18 @@ function do_next() end --- A timer alarm is sued to check if an IMAP reply has been processed -tmr.alarm(0,1000,1, do_next) +do + -- configure the ESP8266 as a station + wifi.setmode(wifi.STATION) + wifi.sta.config(SSID,SSID_PASSWORD) + wifi.sta.autoconnect(1) + + -- create an unencrypted connection + imap_socket = net.createConnection(net.TCP,0) + imap_socket:on("connection",setup) -- call setup() upon connection + imap_socket:connect(IMAP_PORT,IMAP_SERVER) -- connect to the IMAP server + + -- A timer alarm is sued to check if an IMAP reply has been processed + timer = tmr.create() + timer:alarm(1000, tmr.ALARM_AUTO, do_next) +end diff --git a/lua_examples/email/send_email_smtp.lua b/lua_examples/email/send_email_smtp.lua index 4ba6585e53..b11e1928a9 100644 --- a/lua_examples/email/send_email_smtp.lua +++ b/lua_examples/email/send_email_smtp.lua @@ -1,16 +1,17 @@ --- -- Working Example: https://www.youtube.com/watch?v=CcRbFIJ8aeU --- @description a basic SMTP email example. You must use an account which can provide unencrypted authenticated access. --- This example was tested with an AOL and Time Warner email accounts. GMail does not offer unecrypted authenticated access. +-- @description a basic SMTP email example. You must use an account which can +-- provide unencrypted authenticated access. +-- This example was tested with an AOL and Time Warner email accounts. +-- GMail does not offer unencrypted authenticated access. -- To obtain your email's SMTP server and port simply Google it e.g. [my email domain] SMTP settings --- For example for timewarner you'll get to this page http://www.timewarnercable.com/en/support/faqs/faqs-internet/e-mailacco/incoming-outgoing-server-addresses.html +-- For example for timewarner you'll get to this page +-- http://www.timewarnercable.com/en/support/faqs/faqs-internet/e-mailacco/incoming-outgoing-server-addresses.html -- To Learn more about SMTP email visit: -- SMTP Commands Reference - http://www.samlogic.net/articles/smtp-commands-reference.htm -- See "SMTP transport example" in this page http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol -- @author Miguel -require("base64") - -- The email and password from the account you want to send emails from local MY_EMAIL = "esp8266@domain.com" local EMAIL_PASSWORD = "123456" @@ -37,18 +38,18 @@ wifi.sta.autoconnect(1) local email_subject = "" local email_body = "" local count = 0 - +local timer local smtp_socket = nil -- will be used as socket to email server -- The display() function will be used to print the SMTP server's response -function display(sck,response) +local function display(sck, response) -- luacheck: no unused print(response) end -- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence. -- I was going to use socket callbacks but the code would not run callbacks after the first 3. -function do_next() +local function do_next() if(count == 0)then count = count+1 local IP_ADDRESS = wifi.sta.getip() @@ -58,10 +59,10 @@ function do_next() smtp_socket:send("AUTH LOGIN\r\n") elseif(count == 2) then count = count + 1 - smtp_socket:send(base64.enc(MY_EMAIL).."\r\n") + smtp_socket:send(encoder.toBase64(MY_EMAIL).."\r\n") elseif(count == 3) then count = count + 1 - smtp_socket:send(base64.enc(EMAIL_PASSWORD).."\r\n") + smtp_socket:send(encoder.toBase64(EMAIL_PASSWORD).."\r\n") elseif(count==4) then count = count+1 smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n") @@ -82,26 +83,27 @@ function do_next() smtp_socket:send(message.."\r\n.\r\n") elseif(count==8) then count = count+1 - tmr.stop(0) + timer:stop() smtp_socket:send("QUIT\r\n") else smtp_socket:close() end end --- The connectted() function is executed when the SMTP socket is connected to the SMTP server. +-- The connected() function is executed when the SMTP socket is connected to the SMTP server. -- This function will create a timer to call the do_next function which will send the SMTP commands -- in sequence, one by one, every 5000 seconds. -- You can change the time to be smaller if that works for you, I used 5000ms just because. -function connected(sck) - tmr.alarm(0,5000,1,do_next) +local function connected() + timer = tmr.create() + timer:alarm(5000, tmr.ALARM_AUTO, do_next) end -- @name send_email -- @description Will initiated a socket connection to the SMTP server and trigger the connected() function -- @param subject The email's subject -- @param body The email's body -function send_email(subject,body) +local function send_email(subject,body) count = 0 email_subject = subject email_body = body @@ -111,19 +113,13 @@ function send_email(subject,body) smtp_socket:connect(SMTP_PORT,SMTP_SERVER) end --- Send an email -send_email( - "ESP8266", -[[Hi, -How are your IoT projects coming along? -Best Wishes, -ESP8266]]) - - - - - - - - - +do + -- Send an email + send_email( + "ESP8266", + [[Hi, + How are your IoT projects coming along? + Best Wishes, + ESP8266]] + ) +end diff --git a/lua_examples/irsend.lua b/lua_examples/irsend.lua index ed1cb98bb1..dd3aec40e1 100644 --- a/lua_examples/irsend.lua +++ b/lua_examples/irsend.lua @@ -10,6 +10,7 @@ local M do -- const + -- luacheck: push no unused local NEC_PULSE_US = 1000000 / 38000 local NEC_HDR_MARK = 9000 local NEC_HDR_SPACE = 4500 @@ -17,6 +18,7 @@ do local NEC_ONE_SPACE = 1600 local NEC_ZERO_SPACE = 560 local NEC_RPT_SPACE = 2250 + -- luacheck: pop -- cache local gpio, bit = gpio, bit local mode, write = gpio.mode, gpio.write diff --git a/lua_examples/lfs/HTTP_OTA.lua b/lua_examples/lfs/HTTP_OTA.lua index 42472de5ae..513771b38e 100644 --- a/lua_examples/lfs/HTTP_OTA.lua +++ b/lua_examples/lfs/HTTP_OTA.lua @@ -10,7 +10,7 @@ local host, dir, image = ... local doRequest, firstRec, subsRec, finalise local n, total, size = 0, 0 -doRequest = function(sk,hostIP) +doRequest = function(socket, hostIP) -- luacheck: no unused if hostIP then local con = net.createConnection(net.TCP,0) con:connect(80,hostIP) diff --git a/lua_examples/lfs/_init.lua b/lua_examples/lfs/_init.lua index 0060811ed2..d3ad4fa563 100644 --- a/lua_examples/lfs/_init.lua +++ b/lua_examples/lfs/_init.lua @@ -46,7 +46,7 @@ local lfs_t = { end end, - __newindex = function(_, name, value) + __newindex = function(_, name, value) -- luacheck: no unused error("LFS is readonly. Invalid write to LFS." .. name, 2) end, diff --git a/lua_examples/lfs/dummy_strings.lua b/lua_examples/lfs/dummy_strings.lua index cee2eaaf54..f644d73424 100644 --- a/lua_examples/lfs/dummy_strings.lua +++ b/lua_examples/lfs/dummy_strings.lua @@ -24,8 +24,10 @@ end This will exclude any strings already in the ROM table, so the output is the list of putative strings that you should consider adding to LFS ROM table. ----------------------------------------------------------------------------------]] +--------------------------------------------------------------------------------- +]]-- +-- luacheck: ignore local preload = "?.lc;?.lua", "/\n;\n?\n!\n-", "@init.lua", "_G", "_LOADED", "_LOADLIB", "__add", "__call", "__concat", "__div", "__eq", "__gc", "__index", "__le", "__len", "__lt", "__mod", "__mode", "__mul", "__newindex", "__pow", diff --git a/lua_examples/lfs/lfs_fragments.lua b/lua_examples/lfs/lfs_fragments.lua index c5e53e06e4..47ccb8342e 100644 --- a/lua_examples/lfs/lfs_fragments.lua +++ b/lua_examples/lfs/lfs_fragments.lua @@ -5,8 +5,8 @@ -- then enter the following commands interactively through the UART: -- do - local _,ma,fa=node.flashindex() - for n,v in pairs{LFS_MAPPED=ma, LFS_BASE=fa, SPIFFS_BASE=sa} do + local sa, ma, fa = node.flashindex() + for n,v in pairs{LFS_MAPPED = ma, LFS_BASE = fa, SPIFFS_BASE = sa} do print(('export %s=""0x%x"'):format(n, v)) end end @@ -60,7 +60,5 @@ local initTimer = tmr.create() initTimer:register(1000, tmr.ALARM_SINGLE, function() local fi=node.flashindex; return pcall(fi and fi'_init') - end - ) + end) initTimer:start() - diff --git a/lua_examples/luaOTA/_doTick.lua b/lua_examples/luaOTA/_doTick.lua index e8a7238f8c..979cb00346 100644 --- a/lua_examples/luaOTA/_doTick.lua +++ b/lua_examples/luaOTA/_doTick.lua @@ -1,3 +1,4 @@ +-- luacheck: globals self if (self.timer) then self.timer:stop() end--SAFETRIM -- function _doTick(self) diff --git a/lua_examples/luaOTA/_provision.lua b/lua_examples/luaOTA/_provision.lua index 3b69fcae38..7eaceb2796 100644 --- a/lua_examples/luaOTA/_provision.lua +++ b/lua_examples/luaOTA/_provision.lua @@ -2,7 +2,7 @@ -- function _provision(self,socket,first_rec) local self, socket, first_rec = ... -local crypto, file, json, node, table = crypto, file, sjson, node, table +local crypto, file, json, node, table = crypto, file, sjson, node, table local stripdebug, gc = node.stripdebug, collectgarbage local buf = {} @@ -13,11 +13,10 @@ local function getbuf() -- upval: buf, table end -- Process a provisioning request record -local function receiveRec(socket, rec) -- upval: self, buf, crypto - -- Note that for 2nd and subsequent responses, we assme that the service has - -- "authenticated" itself, so any protocol errors are fatal and lkely to +local function receiveRec(sck, rec) -- upval: self, buf, crypto + -- Note that for 2nd and subsequent responses, we assume that the service has + -- "authenticated" itself, so any protocol errors are fatal and likely to -- cause a repeating boot, throw any protocol errors are thrown. - local config, file, log = self.config, file, self.log local cmdlen = (rec:find('\n',1, true) or 0) - 1 local cmd,hash = rec:sub(1,cmdlen-6), rec:sub(cmdlen-5,cmdlen) if cmdlen < 16 or @@ -25,7 +24,9 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto return error("Invalid command signature") end - local s; s, cmd = pcall(json.decode, cmd) + local s + s, cmd = pcall(json.decode, cmd) + if not s then error("JSON decode error") end local action,resp = cmd.a, {s = "OK"} local chunk @@ -59,15 +60,15 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto if not msg then gc(); gc() local code, name = string.dump(lcf), cmd.name:sub(1,-5) .. ".lc" - local s = file.open(name, "w+") - if s then + local f = file.open(name, "w+") + if f then for i = 1, #code, 1024 do - s = s and file.write(code:sub(i, ((i+1023)>#code) and i+1023 or #code)) + f = f and file.write(code:sub(i, ((i+1023)>#code) and i+1023 or #code)) end file.close() - if not s then file.remove(name) end + if not f then file.remove(name) end end - if s then + if f then resp.lcsize=#code print("Updated ".. name) else @@ -80,15 +81,15 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto buf = {} elseif action == "dl" then - local s = file.open(cmd.name, "w+") - if s then + local dlFile = file.open(cmd.name, "w+") + if dlFile then for i = 1, #buf do - s = s and file.write(buf[i]) + dlFile = dlFile and file.write(buf[i]) end file.close() end - if s then + if dlFile then print("Updated ".. cmd.name) else file.remove(cmd.name) @@ -109,13 +110,13 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto file.open(self.prefix.."config.json", "w+") file.writeline(json.encode(cmd)) file.close() - socket:close() + sck:close() print("Restarting to load new application") node.restart() -- reboot just schedules a restart return end end - self.socket_send(socket, resp, chunk) + self.socket_send(sck, resp, chunk) gc() end diff --git a/lua_examples/luaOTA/check.lua b/lua_examples/luaOTA/check.lua index 46dcd27310..e869adf388 100644 --- a/lua_examples/luaOTA/check.lua +++ b/lua_examples/luaOTA/check.lua @@ -9,14 +9,13 @@ -------------------------------------------------------------------------------- -- upvals -local crypto, file, json, net, node, table, wifi = - crypto, file, sjson, net, node, table, wifi -local error, pcall = error, pcall +local crypto, json, node, wifi = + crypto, sjson, node, wifi +local error = error local loadfile, gc = loadfile, collectgarbage -local concat, unpack = table.concat, unpack or table.unpack local self = {post = node.task.post, prefix = "luaOTA/", conf = {}} - +-- luacheck: globals DEBUG self.log = (DEBUG == true) and print or function() end self.modname = ... self.timer = tmr.create() @@ -27,15 +26,15 @@ end -------------------------------------------------------------------------------------- -- Utility Functions -setmetatable( self, {__index=function(self, func) --upval: loadfile +setmetatable( self, {__index=function(obj, func) --upval: loadfile -- The only __index calls in in LuaOTA are dynamically loaded functions. -- The convention is that functions starting with "_" are treated as -- call-once / ephemeral; the rest are registered in self - func = self.prefix .. func + func = obj.prefix .. func local f,msg = loadfile( func..".lc") if msg then f, msg = loadfile(func..".lua") end if msg then error (msg,2) end - if func:sub(8,8) ~= "_" then self[func] = f end + if func:sub(8,8) ~= "_" then obj[func] = f end return f end} ) diff --git a/lua_examples/luaOTA/default.lua b/lua_examples/luaOTA/default.lua index bfbaad7901..fa059e98a1 100644 --- a/lua_examples/luaOTA/default.lua +++ b/lua_examples/luaOTA/default.lua @@ -1,5 +1,4 @@ --- -local function enum(t,log) for k,v in pairs(t)do log(k,v) end end +-- luacheck: globals DEBUG return {entry = function(msg) package.loaded["luaOTA.default"]=nil local gc=collectgarbage; gc(); gc() diff --git a/lua_examples/luaOTA/luaOTAserver.lua b/lua_examples/luaOTA/luaOTAserver.lua index b1e07a9fe1..5356e29501 100644 --- a/lua_examples/luaOTA/luaOTAserver.lua +++ b/lua_examples/luaOTA/luaOTAserver.lua @@ -17,6 +17,8 @@ ]] +-- luacheck: std max + local socket = require "socket" local lfs = require "lfs" local md5 = require "md5" @@ -31,7 +33,6 @@ local receive_and_parse -- function(esp) local provision -- function(esp, config, files, inventory, fingerprint) local read_file -- function(fname) local save_file -- function(fname, data) -local compress_lua -- function(lua_file) local hmac -- function(data) -- Function-wide locals (can be upvalues) @@ -164,6 +165,7 @@ receive_and_parse = function(esp) local packed_cmd, sig = line:sub(1,#line-6),line:sub(-6) -- print("reply:", packed_cmd, sig) local status, cmd = pcall(json.decode, packed_cmd) + if not status then error("JSON decode error") end if not hmac or hmac(packed_cmd):sub(-6) == sig then if cmd and cmd.data == "number" then local data = esp:receive(cmd.data) @@ -183,7 +185,7 @@ provision = function(esp, config, inventory, fingerprint) local name, size, mtime, content = f.name, f.size, f.mtime, f.content if not cf[name] or cf[name] ~= mtime then -- Send the file - local func, action, cmd, buf + local action, cmd, buf if f.name:sub(-4) == ".lua" then assert(load(content, f.name)) -- check that the contents can compile if content:find("--SAFETRIM\n",1,true) then @@ -241,12 +243,11 @@ end -- Save contents to the given file ---------------------------------- -save_file = function(fname, data) +save_file = function(fname, data) -- luacheck: ignore local file = io.open(fname, "wb") file:write(data) file:close() end - -------------------------------------------------------------------------------------- main() -- now that all functions have been bound to locals, we can start the show :-) diff --git a/lua_examples/make_phone_call.lua b/lua_examples/make_phone_call.lua index 27058b6bd7..d5501a0e74 100644 --- a/lua_examples/make_phone_call.lua +++ b/lua_examples/make_phone_call.lua @@ -29,10 +29,12 @@ local TWILIO_ACCOUNT_SID = "xxxxxx" local TWILIO_TOKEN = "xxxxxx" local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service - -- Please be sure to understand the security issues of using this relay app and use at your own risk. +-- Please be sure to understand the security issues of using this relay app and use at your own risk. local URI = "/twilio/Calls.json" -function build_post_request(host, uri, data_table) +local wifiTimer = tmr.create() + +local function build_post_request(host, uri, data_table) local data = "" @@ -40,7 +42,7 @@ function build_post_request(host, uri, data_table) data = data .. param.."="..value.."&" end - request = "POST "..uri.." HTTP/1.1\r\n".. + local request = "POST "..uri.." HTTP/1.1\r\n".. "Host: "..host.."\r\n".. "Connection: close\r\n".. "Content-Type: application/x-www-form-urlencoded\r\n".. @@ -53,7 +55,7 @@ function build_post_request(host, uri, data_table) return request end -local function display(sck,response) +local function display(socket, response) -- luacheck: no unused print(response) end @@ -69,7 +71,7 @@ local function make_call(from,to,body) To = to } - socket = net.createConnection(net.TCP,0) + local socket = net.createConnection(net.TCP,0) socket:on("receive",display) socket:connect(80,HOST) @@ -80,13 +82,13 @@ local function make_call(from,to,body) end) end -function check_wifi() +local function check_wifi() local ip = wifi.sta.getip() if(ip==nil) then print("Connecting...") else - tmr.stop(0) + wifiTimer:stop() print("Connected to AP!") print(ip) -- make a call with a voice message "your house is on fire" @@ -95,4 +97,4 @@ function check_wifi() end -tmr.alarm(0,2000,1,check_wifi) +wifiTimer:alarm(2000, tmr.ALARM_AUTO, check_wifi) diff --git a/lua_examples/mcp23008/mcp23008_buttons.lua b/lua_examples/mcp23008/mcp23008_buttons.lua index 1a71c15567..585a4fa696 100644 --- a/lua_examples/mcp23008/mcp23008_buttons.lua +++ b/lua_examples/mcp23008/mcp23008_buttons.lua @@ -14,23 +14,17 @@ -- Website: http://AllAboutEE.com --------------------------------------------------------------------------------------------- -require ("mcp23008") +local mcp23008 = require ("mcp23008") -- ESP-01 GPIO Mapping as per GPIO Table in https://github.com/nodemcu/nodemcu-firmware -gpio0, gpio2 = 3, 4 - --- Setup the MCP23008 -mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW) - -mcp23008.writeIODIR(0xff) -mcp23008.writeGPPU(0xff) +local gpio0, gpio2 = 3, 4 --- -- @name showButtons -- @description Shows the state of each GPIO pin -- @return void --------------------------------------------------------- -function showButtons() +local function showButtons() local gpio = mcp23008.readGPIO() -- read the GPIO/buttons states @@ -51,7 +45,13 @@ function showButtons() print("\r\n") end -tmr.alarm(0,2000,1,showButtons) -- run showButtons() every 2 seconds +do + -- Setup the MCP23008 + mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW) + mcp23008.writeIODIR(0xff) + mcp23008.writeGPPU(0xff) + tmr.create():alarm(2000, tmr.ALARM_AUTO, showButtons) -- run showButtons() every 2 seconds +end diff --git a/lua_examples/mcp23008/mcp23008_leds.lua b/lua_examples/mcp23008/mcp23008_leds.lua index 4f9b6463a0..e1e0633110 100644 --- a/lua_examples/mcp23008/mcp23008_leds.lua +++ b/lua_examples/mcp23008/mcp23008_leds.lua @@ -13,26 +13,17 @@ -- Website: http://AllAboutEE.com --------------------------------------------------------------------------------------------- -require ("mcp23008") +local mcp23008 = require ("mcp23008") -- ESP-01 GPIO Mapping as per GPIO Table in https://github.com/nodemcu/nodemcu-firmware -gpio0, gpio2 = 3, 4 - --- Setup MCP23008 -mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW) - -mcp23008.writeIODIR(0x00) -- make all GPIO pins as outputs -mcp23008.writeGPIO(0x00) -- make all GIPO pins off/low +local gpio0, gpio2 = 3, 4 --- -- @name count() -- @description Reads the value from the GPIO register, increases the read value by 1 -- and writes it back so the LEDs will display a binary count up to 255 or 0xFF in hex. local function count() - - local gpio = 0x00 - - gpio = mcp23008.readGPIO() + local gpio = mcp23008.readGPIO() if(gpio<0xff) then mcp23008.writeGPIO(gpio+1) @@ -41,5 +32,15 @@ local function count() end end --- Run count() every 100ms -tmr.alarm(0,100,1,count) + +do + -- Setup MCP23008 + mcp23008.begin(0x0,gpio2,gpio0,i2c.SLOW) + + mcp23008.writeIODIR(0x00) -- make all GPIO pins as outputs + mcp23008.writeGPIO(0x00) -- make all GIPO pins off/low + + -- Run count() every 100ms + tmr.create():alarm(100, tmr.ALARM_AUTO, count) +end + diff --git a/lua_examples/mqtt/mqtt2cloud.lua b/lua_examples/mqtt/mqtt2cloud.lua index a64e970a6d..753601d30f 100644 --- a/lua_examples/mqtt/mqtt2cloud.lua +++ b/lua_examples/mqtt/mqtt2cloud.lua @@ -1,33 +1,41 @@ -- test with cloudmqtt.com -m_dis={} -function dispatch(m,t,pl) - if pl~=nil and m_dis[t] then - m_dis[t](m,pl) - end +local m_dis = {} + +local function dispatch(m,t,pl) + if pl~=nil and m_dis[t] then + m_dis[t](m,pl) + end end -function topic1func(m,pl) - print("get1: "..pl) + +local function topic1func(_,pl) + print("get1: "..pl) end -function topic2func(m,pl) - print("get2: "..pl) + +local function topic2func(_,pl) + print("get2: "..pl) end -m_dis["/topic1"]=topic1func -m_dis["/topic2"]=topic2func --- Lua: mqtt.Client(clientid, keepalive, user, pass) -m=mqtt.Client("nodemcu1",60,"test","test123") -m:on("connect",function(m) - print("connection "..node.heap()) - m:subscribe("/topic1",0,function(m) print("sub done") end) - m:subscribe("/topic2",0,function(m) print("sub done") end) - m:publish("/topic1","hello",0,0) m:publish("/topic2","world",0,0) - end ) -m:on("offline", function(conn) + +do + m_dis["/topic1"] = topic1func + m_dis["/topic2"] = topic2func + -- Lua: mqtt.Client(clientid, keepalive, user, pass) + local m = mqtt.Client("nodemcu1", 60, "test", "test123") + m:on("connect",function(client) + print("connection "..node.heap()) + client:subscribe("/topic1",0,function() print("sub done") end) + client:subscribe("/topic2",0,function() print("sub done") end) + client:publish("/topic1","hello",0,0) + client:publish("/topic2","world",0,0) + end) + m:on("offline", function() print("disconnect to broker...") print(node.heap()) -end) -m:on("message",dispatch ) --- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) ) -m:connect("m11.cloudmqtt.com",11214,0,1) -tmr.alarm(0,10000,1,function() local pl = "time: "..tmr.time() - m:publish("/topic1",pl,0,0) - end) + end) + m:on("message",dispatch ) + -- Lua: mqtt:connect( host, port, secure, function(client) ) + m:connect("m11.cloudmqtt.com",11214,0) + tmr.create():alarm(10000, tmr.ALARM_AUTO, function() + local pl = "time: "..tmr.time() + m:publish("/topic1",pl,0,0) + end) +end \ No newline at end of file diff --git a/lua_examples/mqtt/mqtt_file.lua b/lua_examples/mqtt/mqtt_file.lua index d528585078..ed5d71d920 100644 --- a/lua_examples/mqtt/mqtt_file.lua +++ b/lua_examples/mqtt/mqtt_file.lua @@ -1,22 +1,23 @@ -- test transfer files over mqtt. -m_dis={} -function dispatch(m,t,pl) - if pl~=nil and m_dis[t] then +local m_dis = {} + +local function dispatch(m, t, pl) + if pl ~= nil and m_dis[t] then m_dis[t](m,pl) end end -function pubfile(m,filename) +local function pubfile(m,filename) file.close() file.open(filename) repeat - local pl=file.read(1024) - if pl then m:publish("/topic2",pl,0,0) end - until not pl - file.close() + local pl = file.read(1024) + if pl then m:publish("/topic2", pl, 0, 0) end + until not pl + file.close() end -- payload(json): {"cmd":xxx,"content":xxx} -function topic1func(m,pl) +local function topic1func(m,pl) print("get1: "..pl) local pack = sjson.decode(pl) if pack.content then @@ -30,21 +31,22 @@ function topic1func(m,pl) end end -m_dis["/topic1"]=topic1func --- Lua: mqtt.Client(clientid, keepalive, user, pass) -m=mqtt.Client() -m:on("connect",function(m) - print("connection "..node.heap()) - m:subscribe("/topic1",0,function(m) print("sub done") end) - end ) -m:on("offline", function(conn) - print("disconnect to broker...") - print(node.heap()) -end) -m:on("message",dispatch ) --- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) ) -m:connect("192.168.18.88",1883,0,1) - +do + m_dis["/topic1"]=topic1func + -- Lua: mqtt.Client(clientid, keepalive, user, pass) + local m = mqtt.Client() + m:on("connect",function(client) + print("connection "..node.heap()) + client:subscribe("/topic1", 0, function() print("sub done") end) + end) + m:on("offline", function() + print("disconnect to broker...") + print(node.heap()) + end) + m:on("message",dispatch ) + -- Lua: mqtt:connect( host, port, secure, function(client) ) + m:connect("192.168.18.88",1883,0) +end -- usage: -- another client(pc) subscribe to /topic2, will receive the test.lua content. -- and publish below message to /topic1 diff --git a/lua_examples/pcm/play_file.lua b/lua_examples/pcm/play_file.lua index d3ceefdc33..3a5f859465 100644 --- a/lua_examples/pcm/play_file.lua +++ b/lua_examples/pcm/play_file.lua @@ -6,7 +6,7 @@ -- **************************************************************************** -function cb_drained(d) +local function cb_drained() print("drained "..node.heap()) file.seek("set", 0) @@ -14,27 +14,29 @@ function cb_drained(d) --d:play(pcm.RATE_8K) end -function cb_stopped(d) +local function cb_stopped() print("playback stopped") file.seek("set", 0) end -function cb_paused(d) +local function cb_paused() print("playback paused") end -file.open("jump_8k.u8", "r") +do + file.open("jump_8k.u8", "r") -drv = pcm.new(pcm.SD, 1) + local drv = pcm.new(pcm.SD, 1) --- fetch data in chunks of FILE_READ_CHUNK (1024) from file -drv:on("data", function(drv) return file.read() end) + -- fetch data in chunks of FILE_READ_CHUNK (1024) from file + drv:on("data", function(driver) return file.read() end) -- luacheck: no unused --- get called back when all samples were read from the file -drv:on("drained", cb_drained) + -- get called back when all samples were read from the file + drv:on("drained", cb_drained) -drv:on("stopped", cb_stopped) -drv:on("paused", cb_paused) + drv:on("stopped", cb_stopped) + drv:on("paused", cb_paused) --- start playback -drv:play(pcm.RATE_8K) + -- start playback + drv:play(pcm.RATE_8K) +end diff --git a/lua_examples/send_text_message.lua b/lua_examples/send_text_message.lua index c454e0ca23..45d8b8d50d 100644 --- a/lua_examples/send_text_message.lua +++ b/lua_examples/send_text_message.lua @@ -29,10 +29,12 @@ local TWILIO_ACCOUNT_SID = "xxxxxx" local TWILIO_TOKEN = "xxxxxx" local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service - -- Please be sure to understand the security issues of using this relay app and use at your own risk. +-- Please be sure to understand the security issues of using this relay app and use at your own risk. local URI = "/twilio/Messages.json" -function build_post_request(host, uri, data_table) +local wifiTimer = tmr.create() + +local function build_post_request(host, uri, data_table) local data = "" @@ -40,7 +42,7 @@ function build_post_request(host, uri, data_table) data = data .. param.."="..value.."&" end - request = "POST "..uri.." HTTP/1.1\r\n".. + local request = "POST "..uri.." HTTP/1.1\r\n".. "Host: "..host.."\r\n".. "Connection: close\r\n".. "Content-Type: application/x-www-form-urlencoded\r\n".. @@ -53,7 +55,7 @@ function build_post_request(host, uri, data_table) return request end -local function display(sck,response) +local function display(socket, response) -- luacheck: no unused print(response) end @@ -69,7 +71,7 @@ local function send_sms(from,to,body) To = to } - socket = net.createConnection(net.TCP,0) + local socket = net.createConnection(net.TCP,0) socket:on("receive",display) socket:connect(80,HOST) @@ -80,13 +82,13 @@ local function send_sms(from,to,body) end) end -function check_wifi() +local function check_wifi() local ip = wifi.sta.getip() if(ip==nil) then print("Connecting...") else - tmr.stop(0) + wifiTimer.stop() print("Connected to AP!") print(ip) -- send a text message with the text "Hello from your esp8266" @@ -95,4 +97,4 @@ function check_wifi() end -tmr.alarm(0,7000,1,check_wifi) +wifiTimer.alarm(7000, tmr.ALARM_AUTO, check_wifi) diff --git a/lua_examples/sjson-streaming.lua b/lua_examples/sjson-streaming.lua index d7981c5f05..c92d2a73ae 100644 --- a/lua_examples/sjson-streaming.lua +++ b/lua_examples/sjson-streaming.lua @@ -1,11 +1,18 @@ -- Test sjson and GitHub API local s = tls.createConnection() -s:on("connection", function(sck, c) - sck:send("GET /repos/nodemcu/nodemcu-firmware/git/trees/master HTTP/1.0\r\nUser-agent: nodemcu/0.1\r\nHost: api.github.com\r\nConnection: close\r\nAccept: application/json\r\n\r\n") +s:on("connection", function(sck) + sck:send( +[[GET /repos/nodemcu/nodemcu-firmware/git/trees/master HTTP/1.0 +User-agent: nodemcu/0.1 +Host: api.github.com +Connection: close +Accept: application/json + +]]) end) -function startswith(String, Start) +local function startswith(String, Start) return string.sub(String, 1, string.len(Start)) == Start end @@ -23,13 +30,13 @@ local decoder = sjson.decoder({ end } }) -local function handledata(s) - decoder:write(s) +local function handledata(sck) + decoder:write(sck) end -- The receive callback is somewhat gnarly as it has to deal with find the end of the header -- and having the newline sequence split across packets -s:on("receive", function(sck, c) +s:on("receive", function(socket, c) -- luacheck: no unused if partial then c = partial .. c partial = nil @@ -45,8 +52,8 @@ s:on("receive", function(sck, c) handledata(c) return end - local s, e = c:find("\r\n") - if s then + local str, e = c:find("\r\n") + if str then -- Throw away line c = c:sub(e + 1) else diff --git a/lua_examples/somfy.lua b/lua_examples/somfy.lua index a67553062d..8f594235e6 100644 --- a/lua_examples/somfy.lua +++ b/lua_examples/somfy.lua @@ -1,17 +1,20 @@ -- Somfy module example (beside somfy module requires also SJSON module) --- The rolling code number is stored in the file somfy.cfg. A cached write of the somfy.cfg file is implemented in order to reduce the number of write to the EEPROM memory. Together with the logic of the file module it should allow long lasting operation. +-- The rolling code number is stored in the file somfy.cfg. +-- A cached write of the somfy.cfg file is implemented in order to reduce +-- the number of write to the EEPROM memory. Together with the logic of the +-- file module it should allow long lasting operation. -config_file = "somfy." +local config_file = "somfy." +local config, config_saved -- somfy.cfg looks like -- {"window1":{"rc":1,"address":123},"window2":{"rc":1,"address":124}} local tmr_cache = tmr.create() local tmr_delay = tmr.create() -pin = 4 -gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP) +local pin = 4 -function deepcopy(orig) +local function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then @@ -26,8 +29,8 @@ function deepcopy(orig) return copy end -function readconfig() - local cfg, ok, ln +local function readconfig() + local ln if file.exists(config_file.."cfg") then print("Reading config from "..config_file.."cfg") file.open(config_file.."cfg", "r+") @@ -47,7 +50,7 @@ function readconfig() config_saved = deepcopy(config) end -function writeconfighard() +local function writeconfighard() print("Saving config") file.remove(config_file.."bak") file.rename(config_file.."cfg", config_file.."bak") @@ -63,8 +66,8 @@ function writeconfighard() config_saved = deepcopy(config) end -function writeconfig() - tmr.stop(tmr_cache) +local function writeconfig() + tmr_cache:stop() local savenow = false local savelater = false @@ -87,12 +90,18 @@ function writeconfig() end if savelater then print("Saving config later") - tmr.alarm(tmr_cache, 65000, tmr.ALARM_SINGLE, writeconfighard) + tmr_cache:alarm(65000, tmr.ALARM_SINGLE, writeconfighard) end end --======================================================================================================-- -function down(remote, cb, par) +local function wait(ms, cb, par) + par = par or {} + print("wait: ".. ms) + if cb then tmr_delay:alarm(ms, tmr.ALARM_SINGLE, function () cb(unpack(par)) end) end +end + +local function down(remote, cb, par) par = par or {} print("down: ".. remote) config[remote].rc=config[remote].rc+1 @@ -100,7 +109,7 @@ function down(remote, cb, par) writeconfig() end -function up(remote, cb, par) +local function up(remote, cb, par) par = par or {} print("up: ".. remote) config[remote].rc=config[remote].rc+1 @@ -108,7 +117,7 @@ function up(remote, cb, par) writeconfig() end -function downStep(remote, cb, par) +local function downStep(remote, cb, par) par = par or {} print("downStep: ".. remote) config[remote].rc=config[remote].rc+1 @@ -116,7 +125,7 @@ function downStep(remote, cb, par) writeconfig() end -function upStep(remote, cb, par) +local function upStep(remote, cb, par) -- luacheck: ignore par = par or {} print("upStep: ".. remote) config[remote].rc=config[remote].rc+1 @@ -124,14 +133,9 @@ function upStep(remote, cb, par) writeconfig() end -function wait(ms, cb, par) - par = par or {} - print("wait: ".. ms) - if cb then tmr.alarm(tmr_delay, ms, tmr.ALARM_SINGLE, function () cb(unpack(par)) end) end -end - - --======================================================================================================-- +gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP) + if not config then readconfig() end if #config == 0 then -- somfy.cfg does not exist config = sjson.decode([[{"window1":{"rc":1,"address":123},"window2":{"rc":1,"address":124}}]]) @@ -141,5 +145,11 @@ down('window1', wait, {60000, up, {'window1', wait, {9000, - downStep, {'window1', downStep, {'window1', downStep, {'window1', downStep, {'window1', downStep, {'window1', downStep, {'window1', downStep, {'window1' + downStep, {'window1', + downStep, {'window1', + downStep, {'window1', + downStep, {'window1', + downStep, {'window1', + downStep, {'window1', + downStep, {'window1' }}}}}}}}}}) diff --git a/lua_examples/tcp2uart.lua b/lua_examples/tcp2uart.lua index 638a2d770e..db38371eff 100644 --- a/lua_examples/tcp2uart.lua +++ b/lua_examples/tcp2uart.lua @@ -1,16 +1,18 @@ -uart.setup(0,9600,8,0,1,0) -sv=net.createServer(net.TCP, 60) -global_c = nil -sv:listen(9999, function(c) - if global_c~=nil then - global_c:close() - end - global_c=c - c:on("receive",function(sck,pl) uart.write(0,pl) end) -end) +do + uart.setup(0, 9600, 8, 0, 1, 0) + local sv = net.createServer(net.TCP, 60) + local global_c = nil + sv:listen(9999, function(c) + if global_c~=nil then + global_c:close() + end + global_c = c + c:on("receive",function(_, pl) uart.write(0, pl) end) + end) -uart.on("data",4, function(data) - if global_c~=nil then - global_c:send(data) - end -end, 0) + uart.on("data", 4, function(data) + if global_c ~= nil then + global_c:send(data) + end + end, 0) +end diff --git a/lua_examples/timezone/tz.lua b/lua_examples/timezone/tz.lua index 8cc6cc5ea7..05d4641de8 100644 --- a/lua_examples/timezone/tz.lua +++ b/lua_examples/timezone/tz.lua @@ -27,7 +27,7 @@ function M.getzones() return result end -function load(t) +local function load(t) local z = file.open(thezone .. ".zone", "r") local hdr = z:read(20) @@ -35,7 +35,8 @@ function load(t) if magic == "TZif" then local lens = z:read(24) - local ttisgmt_count, ttisdstcnt, leapcnt, timecnt, typecnt, charcnt = struct.unpack("> LLLLLL", lens) + local ttisgmt_count, ttisdstcnt, leapcnt, timecnt, typecnt, charcnt -- luacheck: no unused + = struct.unpack("> LLLLLL", lens) local times = z:read(4 * timecnt) local typeindex = z:read(timecnt) diff --git a/lua_examples/u8g2/graphics_test.lua b/lua_examples/u8g2/graphics_test.lua index 7287c0ed0c..4214530666 100644 --- a/lua_examples/u8g2/graphics_test.lua +++ b/lua_examples/u8g2/graphics_test.lua @@ -9,8 +9,13 @@ -- -- *************************************************************************** +-- display object +local disp + +local draw_state, loop_tmr = 0, tmr.create() + -- setup I2c and connect display -function init_i2c_display() +local function init_i2c_display() -- SDA and SCL can be assigned freely to available GPIOs local sda = 5 -- GPIO14 local scl = 6 -- GPIO12 @@ -18,9 +23,8 @@ function init_i2c_display() i2c.setup(0, sda, scl, i2c.SLOW) disp = u8g2.ssd1306_i2c_128x64_noname(0, sla) end - -- setup SPI and connect display -function init_spi_display() +local function init_spi_display() -- luacheck: no unused -- Hardware SPI CLK = GPIO14 -- Hardware SPI MOSI = GPIO13 -- Hardware SPI MISO = GPIO12 (not used) @@ -37,8 +41,7 @@ function init_spi_display() disp = u8g2.ssd1306_128x64_noname(1, cs, dc, res) end - -function u8g2_prepare() +local function u8g2_prepare() disp:setFont(u8g2.font_6x10_tf) disp:setFontRefHeightExtendedText() disp:setDrawColor(1) @@ -47,7 +50,7 @@ function u8g2_prepare() end -function u8g2_box_frame(a) +local function u8g2_box_frame(a) disp:drawStr( 0, 0, "drawBox") disp:drawBox(5,10,20,10) disp:drawBox(10+a,15,30,7) @@ -56,7 +59,7 @@ function u8g2_box_frame(a) disp:drawFrame(10+a,15+30,30,7) end -function u8g2_disc_circle(a) +local function u8g2_disc_circle(a) disp:drawStr( 0, 0, "drawDisc") disp:drawDisc(10,18,9) disp:drawDisc(24+a,16,7) @@ -65,13 +68,13 @@ function u8g2_disc_circle(a) disp:drawCircle(24+a,16+30,7) end -function u8g2_r_frame(a) +local function u8g2_r_frame(a) disp:drawStr( 0, 0, "drawRFrame/Box") disp:drawRFrame(5, 10,40,30, a+1) disp:drawRBox(50, 10,25,40, a+1) end -function u8g2_string(a) +local function u8g2_string(a) disp:setFontDirection(0) disp:drawStr(30+a,31, " 0") disp:setFontDirection(1) @@ -82,7 +85,7 @@ function u8g2_string(a) disp:drawStr(30,31-a, " 270") end -function u8g2_line(a) +local function u8g2_line(a) disp:drawStr( 0, 0, "drawLine") disp:drawLine(7+a, 10, 40, 55) disp:drawLine(7+a*2, 10, 60, 55) @@ -90,7 +93,7 @@ function u8g2_line(a) disp:drawLine(7+a*4, 10, 100, 55) end -function u8g2_triangle(a) +local function u8g2_triangle(a) local offset = a disp:drawStr( 0, 0, "drawTriangle") disp:drawTriangle(14,7, 45,30, 10,40) @@ -99,7 +102,7 @@ function u8g2_triangle(a) disp:drawTriangle(10+offset,40+offset, 45+offset,30+offset, 86+offset,53+offset) end -function u8g2_ascii_1() +local function u8g2_ascii_1() disp:drawStr( 0, 0, "ASCII page 1") for y = 0, 5 do for x = 0, 15 do @@ -108,7 +111,7 @@ function u8g2_ascii_1() end end -function u8g2_ascii_2() +local function u8g2_ascii_2() disp:drawStr( 0, 0, "ASCII page 2") for y = 0, 5 do for x = 0, 15 do @@ -117,7 +120,7 @@ function u8g2_ascii_2() end end -function u8g2_extra_page(a) +local function u8g2_extra_page(a) disp:drawStr( 0, 0, "Unicode") disp:setFont(u8g2.font_unifont_t_symbols) disp:setFontPosTop() @@ -129,9 +132,9 @@ function u8g2_extra_page(a) end end -cross_width = 24 -cross_height = 24 -cross_bits = string.char( +local cross_width = 24 +local cross_height = 24 +local cross_bits = string.char( 0x00, 0x18, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0xC0, 0x00, 0x03, 0x38, 0x3C, 0x1C, 0x06, 0x42, 0x60, 0x01, 0x42, 0x80, @@ -139,24 +142,25 @@ cross_bits = string.char( 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x18, 0x00) -cross_fill_width = 24 -cross_fill_height = 24 -cross_fill_bits = string.char( +-- luacheck: push no unused +local cross_fill_width = 24 +local cross_fill_height = 24 +local cross_fill_bits = string.char( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x64, 0x00, 0x26, 0x84, 0x00, 0x21, 0x08, 0x81, 0x10, 0x08, 0x42, 0x10, 0x10, 0x3C, 0x08, 0x20, 0x00, 0x04, 0x40, 0x00, 0x02, 0x80, 0x00, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x80, 0x00, 0x01, 0x40, 0x00, 0x02, 0x20, 0x00, 0x04, 0x10, 0x3C, 0x08, 0x08, 0x42, 0x10, 0x08, 0x81, 0x10, 0x84, 0x00, 0x21, 0x64, 0x00, 0x26, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) - -cross_block_width = 14 -cross_block_height = 14 -cross_block_bits = string.char( +-- luacheck: pop +local cross_block_width = 14 +local cross_block_height = 14 +local cross_block_bits = string.char( 0xFF, 0x3F, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0xC1, 0x20, 0xC1, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0xFF, 0x3F) -function u8g2_bitmap_overlay(a) +local function u8g2_bitmap_overlay(a) local frame_size = 28 disp:drawStr(0, 0, "Bitmap overlay") @@ -177,7 +181,7 @@ function u8g2_bitmap_overlay(a) end end -function u8g2_bitmap_modes(transparent) +local function u8g2_bitmap_modes(transparent) local frame_size = 24 disp:drawBox(0, frame_size * 0.5, frame_size * 5, frame_size) @@ -201,7 +205,7 @@ function u8g2_bitmap_modes(transparent) end -function draw() +local function draw() u8g2_prepare() local d3 = bit.rshift(draw_state, 3) @@ -235,7 +239,7 @@ function draw() end -function loop() +local function loop() -- picture loop disp:clearBuffer() draw() @@ -251,13 +255,12 @@ function loop() loop_tmr:start() end +do + loop_tmr:register(100, tmr.ALARM_SEMI, loop) -draw_state = 0 -loop_tmr = tmr.create() -loop_tmr:register(100, tmr.ALARM_SEMI, loop) - -init_i2c_display() ---init_spi_display() + init_i2c_display() + --init_spi_display() -print("--- Starting Graphics Test ---") -loop_tmr:start() + print("--- Starting Graphics Test ---") + loop_tmr:start() +end diff --git a/lua_examples/ucglib/GT_box.lua b/lua_examples/ucglib/GT_box.lua index b21323f884..4b68c394d1 100644 --- a/lua_examples/ucglib/GT_box.lua +++ b/lua_examples/ucglib/GT_box.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_clip.lua b/lua_examples/ucglib/GT_clip.lua index bf3d9b4dd8..8348177db7 100644 --- a/lua_examples/ucglib/GT_clip.lua +++ b/lua_examples/ucglib/GT_clip.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_color_test.lua b/lua_examples/ucglib/GT_color_test.lua index 0b619498e9..e8cd84d795 100644 --- a/lua_examples/ucglib/GT_color_test.lua +++ b/lua_examples/ucglib/GT_color_test.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M @@ -7,10 +8,7 @@ function M.run() print("Running component color_test...") - local mx local c, x - mx = disp:getWidth() / 2 - --my = disp:getHeight() / 2 disp:setColor(0, 0, 0, 0) disp:drawBox(0, 0, disp:getWidth(), disp:getHeight()) diff --git a/lua_examples/ucglib/GT_cross.lua b/lua_examples/ucglib/GT_cross.lua index e4cc3e2d2d..502d1d12ba 100644 --- a/lua_examples/ucglib/GT_cross.lua +++ b/lua_examples/ucglib/GT_cross.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_fonts.lua b/lua_examples/ucglib/GT_fonts.lua index 3990f31744..b885806f9c 100644 --- a/lua_examples/ucglib/GT_fonts.lua +++ b/lua_examples/ucglib/GT_fonts.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_gradient.lua b/lua_examples/ucglib/GT_gradient.lua index e432cba6a8..33b6f8abd9 100644 --- a/lua_examples/ucglib/GT_gradient.lua +++ b/lua_examples/ucglib/GT_gradient.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_graphics_test.lua b/lua_examples/ucglib/GT_graphics_test.lua index 4db6800b8c..ba840cf39d 100644 --- a/lua_examples/ucglib/GT_graphics_test.lua +++ b/lua_examples/ucglib/GT_graphics_test.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_pixel_and_lines.lua b/lua_examples/ucglib/GT_pixel_and_lines.lua index 03d65c17f1..5b4b7a25a5 100644 --- a/lua_examples/ucglib/GT_pixel_and_lines.lua +++ b/lua_examples/ucglib/GT_pixel_and_lines.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_text.lua b/lua_examples/ucglib/GT_text.lua index 8a99d8df4b..60aed1b8ed 100644 --- a/lua_examples/ucglib/GT_text.lua +++ b/lua_examples/ucglib/GT_text.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GT_triangle.lua b/lua_examples/ucglib/GT_triangle.lua index d2e8ab88a7..0ed188e9c7 100644 --- a/lua_examples/ucglib/GT_triangle.lua +++ b/lua_examples/ucglib/GT_triangle.lua @@ -1,3 +1,4 @@ +-- luacheck: globals T r disp millis lcg_rnd local M, module = {}, ... _G[module] = M diff --git a/lua_examples/ucglib/GraphicsTest.lua b/lua_examples/ucglib/GraphicsTest.lua index b5bcf153c7..8cc3879fbb 100644 --- a/lua_examples/ucglib/GraphicsTest.lua +++ b/lua_examples/ucglib/GraphicsTest.lua @@ -1,5 +1,23 @@ +-- luacheck: new globals z T r disp lcg_rnd millis +z = 127 -- start value +T = 1000 +r = 0 +disp = nil + +local loop_idx = 0 + +function lcg_rnd() + z = bit.band(65 * z + 17, 255) + return z +end + +function millis() + local usec = tmr.now() + return usec/1000 +end + -- setup SPI and connect display -function init_spi_display() +local function init_spi_display() -- Hardware SPI CLK = GPIO14 -- Hardware SPI MOSI = GPIO13 -- Hardware SPI MISO = GPIO12 (not used) @@ -20,11 +38,8 @@ function init_spi_display() disp = ucg.st7735_18x128x160_hw_spi(bus, cs, dc, res) end - - - -- switch statement http://lua-users.org/wiki/SwitchStatement -function switch(c) +local function switch(c) local swtbl = { casevar = c, caseof = function (self, code) @@ -46,20 +61,7 @@ function switch(c) return swtbl end - -z = 127 -- start value -function lcg_rnd() - z = bit.band(65 * z + 17, 255) - return z -end - - -function millis() - local usec = tmr.now() - return usec/1000 -end - -function set_clip_range() +local function set_clip_range() local x, y, w, h w = bit.band(lcg_rnd(), 31) h = bit.band(lcg_rnd(), 31) @@ -71,7 +73,7 @@ function set_clip_range() disp:setClipRange(x, y, w, h) end -function loop() +local function loop() if (loop_idx == 0) then switch(bit.band(r, 3)) : caseof { @@ -112,18 +114,12 @@ function loop() print("Heap: " .. node.heap()) end +do + init_spi_display() -T = 1000 - -r = 0 -loop_idx = 0 + disp:begin(ucg.FONT_MODE_TRANSPARENT) + disp:setFont(ucg.font_ncenR14_hr) + disp:clearScreen() -init_spi_display() - -disp:begin(ucg.FONT_MODE_TRANSPARENT) -disp:setFont(ucg.font_ncenR14_hr) -disp:clearScreen() - - -tmr.register(0, 3000, tmr.ALARM_AUTO, function() loop() end) -tmr.start(0) + tmr.create():alarm(3000, tmr.ALARM_AUTO, function() loop() end) +end diff --git a/lua_examples/ucglib/HelloWorld.lua b/lua_examples/ucglib/HelloWorld.lua index 6c7c873105..d5b6215ef6 100644 --- a/lua_examples/ucglib/HelloWorld.lua +++ b/lua_examples/ucglib/HelloWorld.lua @@ -1,5 +1,7 @@ +local disp + -- setup SPI and connect display -function init_spi_display() +local function init_spi_display() -- Hardware SPI CLK = GPIO14 -- Hardware SPI MOSI = GPIO13 -- Hardware SPI MISO = GPIO12 (not used) @@ -20,17 +22,17 @@ function init_spi_display() disp = ucg.st7735_18x128x160_hw_spi(bus, cs, dc, res) end +do + init_spi_display() + disp:begin(ucg.FONT_MODE_TRANSPARENT) + disp:clearScreen() -init_spi_display() - -disp:begin(ucg.FONT_MODE_TRANSPARENT) -disp:clearScreen() + disp:setFont(ucg.font_ncenR12_tr); + disp:setColor(255, 255, 255); + disp:setColor(1, 255, 0,0); -disp:setFont(ucg.font_ncenR12_tr); -disp:setColor(255, 255, 255); -disp:setColor(1, 255, 0,0); - -disp:setPrintPos(0, 25) -disp:print("Hello World!") + disp:setPrintPos(0, 25) + disp:print("Hello World!") +end diff --git a/lua_examples/ucglib/UcgLogo.lua b/lua_examples/ucglib/UcgLogo.lua index 760fd0bd2f..644b90a5f7 100644 --- a/lua_examples/ucglib/UcgLogo.lua +++ b/lua_examples/ucglib/UcgLogo.lua @@ -1,5 +1,7 @@ +local disp + -- setup SPI and connect display -function init_spi_display() +local function init_spi_display() -- Hardware SPI CLK = GPIO14 -- Hardware SPI MOSI = GPIO13 -- Hardware SPI MISO = GPIO12 (not used) @@ -21,7 +23,7 @@ function init_spi_display() end -function upper_pin(x, y) +local function upper_pin(x, y) local w = 7 local h = 6 disp:setColor(0, 212, 212, 212) @@ -36,7 +38,7 @@ function upper_pin(x, y) disp:drawGradientLine(x+w, y, h, 1) end -function lower_pin(x, y) +local function lower_pin(x, y) local w = 7 local h = 5 disp:setColor(0, 212, 212, 212) @@ -56,7 +58,7 @@ function lower_pin(x, y) disp:drawPixel(x+w, y+h) end -function ic_body(x, y) +local function ic_body(x, y) local w = 4*14+4 local h = 31 disp:setColor(0, 60, 60, 60) @@ -77,7 +79,7 @@ function ic_body(x, y) disp:drawDisc(x+w-1, y+h/2+1, 7, bit.bor(ucg.DRAW_UPPER_LEFT, ucg.DRAW_LOWER_LEFT)) end -function draw_ucg_logo() +local function draw_ucg_logo() local a, b --ucg_Init(ucg, ucg_sdl_dev_cb, ucg_ext_none, (ucg_com_fnptr)0) @@ -156,12 +158,12 @@ function draw_ucg_logo() --disp:drawString(1, 61, 0, "code.google.com/p/ucglib/") end +do + init_spi_display() -init_spi_display() - -disp:begin(ucg.FONT_MODE_TRANSPARENT) -disp:clearScreen() + disp:begin(ucg.FONT_MODE_TRANSPARENT) + disp:clearScreen() - -disp:setRotate180() -draw_ucg_logo() + disp:setRotate180() + draw_ucg_logo() +end diff --git a/lua_examples/webap_toggle_pin.lua b/lua_examples/webap_toggle_pin.lua index 60de70a6e6..bacb3def23 100644 --- a/lua_examples/webap_toggle_pin.lua +++ b/lua_examples/webap_toggle_pin.lua @@ -1,21 +1,24 @@ +do wifi.setmode(wifi.SOFTAP) wifi.ap.config({ ssid = "test", pwd = "12345678" }) gpio.mode(1, gpio.OUTPUT) -srv = net.createServer(net.TCP) +local srv = net.createServer(net.TCP) srv:listen(80, function(conn) conn:on("receive", function(client, request) local buf = "" - local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP") + local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP") -- luacheck: no unused if (method == nil) then - _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP") + _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP") -- luacheck: no unused end + local _GET = {} if (vars ~= nil) then for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do _GET[k] = v end end - buf = buf .. "

        Hello, this is NodeMCU.

        Turn PIN1 " local _on, _off = "", "" if (_GET.pin == "ON") then _on = " selected=true" @@ -29,3 +32,4 @@ srv:listen(80, function(conn) end) conn:on("sent", function(c) c:close() end) end) +end \ No newline at end of file diff --git a/lua_modules/bh1750/bh1750.lua b/lua_modules/bh1750/bh1750.lua index 5a06611ee3..bbe939dc6b 100644 --- a/lua_modules/bh1750/bh1750.lua +++ b/lua_modules/bh1750/bh1750.lua @@ -33,14 +33,14 @@ local function read_data(ADDR, commands, length) i2c.start(id) i2c.address(id, ADDR,i2c.RECEIVER) tmr.delay(200000) - c = i2c.read(id, length) + local c = i2c.read(id, length) i2c.stop(id) return c end local function read_lux() - dataT = read_data(GY_30_address, CMD, 2) + local dataT = read_data(GY_30_address, CMD, 2) --Make it more faster - UT = dataT:byte(1) * 256 + dataT:byte(2) + local UT = dataT:byte(1) * 256 + dataT:byte(2) l = (UT*1000/12) return(l) end diff --git a/lua_modules/bh1750/bh1750_Example1.lua b/lua_modules/bh1750/bh1750_Example1.lua index 911aa8fccc..a563d5e9f6 100644 --- a/lua_modules/bh1750/bh1750_Example1.lua +++ b/lua_modules/bh1750/bh1750_Example1.lua @@ -6,19 +6,17 @@ -- -- MIT license, http://opensource.org/licenses/MIT -- *************************************************************************** -tmr.alarm(0, 10000, 1, function() +local bh1750 = require("bh1750") - SDA_PIN = 6 -- sda pin, GPIO12 - SCL_PIN = 5 -- scl pin, GPIO14 +local sda = 6 -- sda pin, GPIO12 +local scl = 5 -- scl pin, GPIO14 - bh1750 = require("bh1750") - bh1750.init(SDA_PIN, SCL_PIN) - bh1750.read(OSS) - l = bh1750.getlux() - print("lux: "..(l / 100).."."..(l % 100).." lx") +do + bh1750.init(sda, scl) - -- release module - bh1750 = nil - package.loaded["bh1750"]=nil - -end) + tmr.create():alarm(10000, tmr.ALARM_AUTO, function() + bh1750.read() + local l = bh1750.getlux() + print("lux: "..(l / 100).."."..(l % 100).." lx") + end) +end diff --git a/lua_modules/bh1750/bh1750_Example2.lua b/lua_modules/bh1750/bh1750_Example2.lua index 0fb0b1d891..115ffae361 100644 --- a/lua_modules/bh1750/bh1750_Example2.lua +++ b/lua_modules/bh1750/bh1750_Example2.lua @@ -10,42 +10,42 @@ --Ps 需要改动的地方LW_GATEWAY(乐联的设备标示),USERKEY(乐联userkey) --Ps You nees to rewrite the LW_GATEWAY(Lelian's Device ID),USERKEY(Lelian's userkey) - -tmr.alarm(0, 60000, 1, function() - SDA_PIN = 6 -- sda pin, GPIO12 - SCL_PIN = 5 -- scl pin, GPIO14 - - BH1750 = require("BH1750") - BH1750.init(SDA_PIN, SCL_PIN) - BH1750.read(OSS) - l = BH1750.getlux() - - --定义数据变量格式 Define the veriables formate - PostData = "[{\"Name\":\"T\",\"Value\":\"" ..(l / 100).."."..(l % 100).."\"}]" - --创建一个TCP连接 Create a TCP Connection - socket=net.createConnection(net.TCP, 0) - --域名解析IP地址并赋值 DNS...it - socket:dns("www.lewei50.com", function(conn, ip) - ServerIP = ip - print("Connection IP:" .. ServerIP) - end) - ---开始连接服务器 Connect the sever -socket:connect(80, ServerIP) - socket:on("connection", function(sck) end) - ---HTTP请求头定义 HTTP Head -socket:send("POST /api/V1/gateway/UpdateSensors/LW_GATEWAY HTTP/1.1\r\n" .. - "Host: www.lewei50.com\r\n" .. - "Content-Length: " .. string.len(PostData) .. "\r\n" .. - "userkey: USERKEY\r\n\r\n" .. - PostData .. "\r\n") - ---HTTP响应内容 Print the HTTP response -socket:on("receive", function(sck, response) - print(response) - end) - end) - - - +local bh1750 = require("bh1750") + +local sda = 6 -- sda pin, GPIO12 +local scl = 5 -- scl pin, GPIO14 +local ServerIP + +do + bh1750.init(sda, scl) + + tmr.create():alarm(60000, tmr.ALARM_AUTO, function() + bh1750.read() + local l = bh1750.getlux() + --定义数据变量格式 Define the veriables formate + local PostData = "[{\"Name\":\"T\",\"Value\":\"" ..(l / 100).."."..(l % 100).."\"}]" + --创建一个TCP连接 Create a TCP Connection + local socket = net.createConnection(net.TCP, 0) + --域名解析IP地址并赋值 DNS...it + socket:dns("www.lewei50.com", function(_, ip) + ServerIP = ip + print("Connection IP:" .. ServerIP) + end) + + --开始连接服务器 Connect the sever + socket:connect(80, ServerIP) + socket:on("connection", function() end) + + --HTTP请求头定义 HTTP Head + socket:send("POST /api/V1/gateway/UpdateSensors/LW_GATEWAY HTTP/1.1\r\n" .. + "Host: www.lewei50.com\r\n" .. + "Content-Length: " .. string.len(PostData) .. "\r\n" .. + "userkey: USERKEY\r\n\r\n" .. + PostData .. "\r\n") + + --HTTP响应内容 Print the HTTP response + socket:on("receive", function(sck, response) -- luacheck: no unused + print(response) + end) + end) +end diff --git a/lua_modules/ds18b20/ds18b20-example.lua b/lua_modules/ds18b20/ds18b20-example.lua index 8354695db0..8f9eacb931 100644 --- a/lua_modules/ds18b20/ds18b20-example.lua +++ b/lua_modules/ds18b20/ds18b20-example.lua @@ -1,14 +1,17 @@ -t = require("ds18b20") -pin = 3 -- gpio0 = 3, gpio2 = 4 +local t = require("ds18b20") +local pin = 3 -- gpio0 = 3, gpio2 = 4 -local function readout(temp) +local function readout(temps) if t.sens then - print("Total number of DS18B20 sensors: ".. #t.sens) - for i, s in ipairs(t.sens) do - print(string.format(" sensor #%d address: %s%s", i, ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(s:byte(1,8)), s:byte(9) == 1 and " (parasite)" or "")) + print("Total number of DS18B20 sensors: ".. #t.sens) + for i, s in ipairs(t.sens) do + print(string.format(" sensor #%d address: %s%s", i, + ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(s:byte(1,8)), + s:byte(9) == 1 and " (parasite)" or "")) end end - for addr, temp in pairs(temp) do + + for addr, temp in pairs(temps) do print(string.format("Sensor %s: %s °C", ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(addr:byte(1,8)), temp)) end @@ -17,36 +20,35 @@ local function readout(temp) --package.loaded["ds18b20"]=nil end -t:enable_debug() -file.remove("ds18b20_save.lc") -- remove saved addresses -print("=============================================", node.heap()) -print("first call, no addresses in flash, search is performed") -t:read_temp(readout, pin, t.C) +do + t:enable_debug() + file.remove("ds18b20_save.lc") -- remove saved addresses + print("=============================================", node.heap()) + print("first call, no addresses in flash, search is performed") + t:read_temp(readout, pin, t.C) -tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() + tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() print("=============================================", node.heap()) print("second readout, no new search, found addresses are used") t:read_temp(readout, pin) -tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() - print("=============================================", node.heap()) - print("force search again") - t:read_temp(readout, pin, nil, true) - -tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() - print("=============================================", node.heap()) - print("save search results") - t:read_temp(readout, pin, nil, false, true) - -tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() - print("=============================================", node.heap()) - print("use saved addresses") - t.sens={} - t:read_temp(readout, pin) -end) - -end) - -end) - -end) + tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() + print("=============================================", node.heap()) + print("force search again") + t:read_temp(readout, pin, nil, true) + + tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() + print("=============================================", node.heap()) + print("save search results") + t:read_temp(readout, pin, nil, false, true) + + tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() + print("=============================================", node.heap()) + print("use saved addresses") + t.sens={} + t:read_temp(readout, pin) + end) + end) + end) + end) +end diff --git a/lua_modules/ds18b20/ds18b20-web.lua b/lua_modules/ds18b20/ds18b20-web.lua index 408612f978..bc401d3ea2 100644 --- a/lua_modules/ds18b20/ds18b20-web.lua +++ b/lua_modules/ds18b20/ds18b20-web.lua @@ -1,35 +1,37 @@ -t = require('ds18b20') +local t = require('ds18b20') -port = 80 -pin = 3 -- gpio0 = 3, gpio2 = 4 -gconn = {} -- global variable for connection +local port = 80 +local pin = 3 -- gpio0 = 3, gpio2 = 4 +local gconn = {} -- local variable for connection -function readout(temp) +local function readout(temps) local resp = "HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" .. - "" .. - "" .. - "ESP8266
        " + "" .. + "" .. + "ESP8266
        " - for addr, temp in pairs(temp) do - resp = resp .. string.format("Sensor %s: %s ℃
        ", ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X '):format(addr:byte(1,8)), temp) + for addr, temp in pairs(temps) do + resp = resp .. string.format("Sensor %s: %s ℃
        ", + ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X '):format(addr:byte(1,8)), temp) end resp = resp .. - "Node ChipID: " .. node.chipid() .. "
        " .. - "Node MAC: " .. wifi.sta.getmac() .. "
        " .. - "Node Heap: " .. node.heap() .. "
        " .. - "Timer Ticks: " .. tmr.now() .. "
        " .. - "" + "Node ChipID: " .. node.chipid() .. "
        " .. + "Node MAC: " .. wifi.sta.getmac() .. "
        " .. + "Node Heap: " .. node.heap() .. "
        " .. + "Timer Ticks: " .. tmr.now() .. "
        " .. + "" gconn:send(resp) gconn:on("sent",function(conn) conn:close() end) end -srv=net.createServer(net.TCP) -srv:listen(port, - function(conn) - gconn = conn - -- t:read_temp(readout) -- default pin value is 3 - t:read_temp(readout, pin) - end -) +do + local srv = net.createServer(net.TCP) + srv:listen(port, + function(conn) + gconn = conn + -- t:read_temp(readout) -- default pin value is 3 + t:read_temp(readout, pin) + end) +end diff --git a/lua_modules/ds18b20/ds18b20.lua b/lua_modules/ds18b20/ds18b20.lua index 50d9a34152..a40e27c0f9 100644 --- a/lua_modules/ds18b20/ds18b20.lua +++ b/lua_modules/ds18b20/ds18b20.lua @@ -3,23 +3,25 @@ -- NODEMCU TEAM -- LICENCE: http://opensource.org/licenses/MIT -- @voborsky, @devsaurus, TerryE 26 Mar 2017 ----------------------------------------------------------------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- local modname = ... -- Used modules and functions -local table, string, ow, tmr, print, type, tostring, pcall, ipairs = - table, string, ow, tmr, print, type, tostring, pcall, ipairs +local type, tostring, pcall, ipairs = + type, tostring, pcall, ipairs -- Local functions -local ow_setup, ow_search, ow_select, ow_read, ow_read_bytes, ow_write, ow_crc8, ow_reset, ow_reset_search, ow_skip, ow_depower = - ow.setup, ow.search, ow.select, ow.read, ow.read_bytes, ow.write, ow.crc8, ow.reset, ow.reset_search, ow.skip, ow.depower +local ow_setup, ow_search, ow_select, ow_read, ow_read_bytes, ow_write, ow_crc8, + ow_reset, ow_reset_search, ow_skip, ow_depower = + ow.setup, ow.search, ow.select, ow.read, ow.read_bytes, ow.write, ow.crc8, + ow.reset, ow.reset_search, ow.skip, ow.depower + local node_task_post, node_task_LOW_PRIORITY = node.task.post, node.task.LOW_PRIORITY local string_char, string_dump = string.char, string.dump local now, tmr_create, tmr_ALARM_SINGLE = tmr.now, tmr.create, tmr.ALARM_SINGLE local table_sort, table_concat = table.sort, table.concat local math_floor = math.floor local file_open = file.open - -table, string, tmr, ow = nil, nil, nil, nil +local conversion local DS18B20FAMILY = 0x28 local DS1920FAMILY = 0x10 -- and DS18S20 series @@ -50,8 +52,6 @@ local function to_string(addr, esc) end end -local conversion - local function readout(self) local next = false local sens = self.sens @@ -62,7 +62,7 @@ local function readout(self) local addr = s:sub(1,8) ow_select(pin, addr) -- select the sensor ow_write(pin, READ_SCRATCHPAD, MODE) - data = ow_read_bytes(pin, 9) + local data = ow_read_bytes(pin, 9) local t=(data:byte(1)+data:byte(2)*256) -- t is actually signed so process the sign bit and adjust for fractional bits @@ -116,7 +116,7 @@ local function readout(self) end end -conversion = function (self) +conversion = (function (self) local sens = self.sens local powered_only = true for _, s in ipairs(sens) do powered_only = powered_only and s:byte(9) ~= 1 end @@ -125,7 +125,7 @@ conversion = function (self) ow_reset(pin) ow_skip(pin) -- select the sensor ow_write(pin, CONVERT_T, MODE) -- and start conversion - for i, s in ipairs(sens) do status[i] = 1 end + for i, _ in ipairs(sens) do status[i] = 1 end else for i, s in ipairs(sens) do if status[i] == 0 then @@ -140,12 +140,11 @@ conversion = function (self) end end tmr_create():alarm(750, tmr_ALARM_SINGLE, function() return readout(self) end) -end +end) local function _search(self, lcb, lpin, search, save) self.temp = {} if search then self.sens = {}; status = {} end - local temp = self.temp local sens = self.sens pin = lpin or pin @@ -167,7 +166,7 @@ local function _search(self, lcb, lpin, search, save) -- search the first device addr = ow_search(pin) else - for i, s in ipairs(sens) do status[i] = 0 end + for i, _ in ipairs(sens) do status[i] = 0 end end local function cycle() debugPrint("cycle") diff --git a/lua_modules/ds3231/ds3231-example.lua b/lua_modules/ds3231/ds3231-example.lua index 340bb1be74..81263d0ee0 100644 --- a/lua_modules/ds3231/ds3231-example.lua +++ b/lua_modules/ds3231/ds3231-example.lua @@ -1,15 +1,17 @@ +local ds3231 = require("ds3231") -- ESP-01 GPIO Mapping -gpio0, gpio2 = 3, 4 -i2c.setup(gpio0, gpio2, scl, i2c.SLOW) -- call i2c.setup() only once +local gpio0, gpio2 = 3, 4 -require("ds3231") +do + i2c.setup(0, gpio0, gpio2, i2c.SLOW) -- call i2c.setup() only once -second, minute, hour, day, date, month, year = ds3231.getTime(); + local second, minute, hour, day, date, month, year = ds3231.getTime(); -- luacheck: no unused --- Get current time -print(string.format("Time & Date: %s:%s:%s %s/%s/%s", hour, minute, second, date, month, year)) + -- Get current time + print(string.format("Time & Date: %s:%s:%s %s/%s/%s", hour, minute, second, date, month, year)) --- Don't forget to release it after use -ds3231 = nil -package.loaded["ds3231"]=nil + -- Don't forget to release it after use + ds3231 = nil -- luacheck: no unused + package.loaded["ds3231"] = nil +end \ No newline at end of file diff --git a/lua_modules/ds3231/ds3231-web.lua b/lua_modules/ds3231/ds3231-web.lua index db55854ca9..da08717e02 100644 --- a/lua_modules/ds3231/ds3231-web.lua +++ b/lua_modules/ds3231/ds3231-web.lua @@ -1,54 +1,53 @@ +local ds3231 = require('ds3231') -- ESP-01 GPIO Mapping -gpio0, gpio2 = 3, 4 -i2c.setup(gpio0, gpio2, scl, i2c.SLOW) -- call i2c.setup() only once - -require('ds3231') - -port = 80 - -days = { - [1] = "Sunday", - [2] = "Monday", - [3] = "Tuesday", - [4] = "Wednesday", - [5] = "Thursday", - [6] = "Friday", - [7] = "Saturday" +local gpio0, gpio2 = 3, 4 +local port = 80 +local days = { + [1] = "Sunday", + [2] = "Monday", + [3] = "Tuesday", + [4] = "Wednesday", + [5] = "Thursday", + [6] = "Friday", + [7] = "Saturday" } -months = { - [1] = "January", - [2] = "Febuary", - [3] = "March", - [4] = "April", - [5] = "May", - [6] = "June", - [7] = "July", - [8] = "August", - [9] = "September", - [10] = "October", - [11] = "November", - [12] = "December" +local months = { + [1] = "January", + [2] = "Febuary", + [3] = "March", + [4] = "April", + [5] = "May", + [6] = "June", + [7] = "July", + [8] = "August", + [9] = "September", + [10] = "October", + [11] = "November", + [12] = "December" } -srv=net.createServer(net.TCP) -srv:listen(port, - function(conn) - - second, minute, hour, day, date, month, year = ds3231.getTime() - prettyTime = string.format("%s, %s %s %s %s:%s:%s", days[day], date, months[month], year, hour, minute, second) - - conn:send("HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" .. - "" .. - "" .. - "ESP8266
        " .. - "Time and Date: " .. prettyTime .. "
        " .. - "Node ChipID : " .. node.chipid() .. "
        " .. - "Node MAC : " .. wifi.sta.getmac() .. "
        " .. - "Node Heap : " .. node.heap() .. "
        " .. - "Timer Ticks : " .. tmr.now() .. "
        " .. - "") - conn:on("sent",function(conn) conn:close() end) - end -) +do + i2c.setup(0, gpio0, gpio2, i2c.SLOW) -- call i2c.setup() only once + + local srv = net.createServer(net.TCP) + srv:listen(port, function(conn) + local second, minute, hour, day, date, month, year = ds3231.getTime() + local prettyTime = string.format("%s, %s %s %s %s:%s:%s", + days[day], date, months[month], year, hour, minute, second) + + conn:send("HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" .. + "" .. + "" .. + "ESP8266
        " .. + "Time and Date: " .. prettyTime .. "
        " .. + "Node ChipID : " .. node.chipid() .. "
        " .. + "Node MAC : " .. wifi.sta.getmac() .. "
        " .. + "Node Heap : " .. node.heap() .. "
        " .. + "Timer Ticks : " .. tmr.now() .. "
        " .. + "") + + conn:on("sent",function(sck) sck:close() end) + end) +end diff --git a/lua_modules/ds3231/ds3231.lua b/lua_modules/ds3231/ds3231.lua index e7f848b7ce..b0c2f7cbcd 100644 --- a/lua_modules/ds3231/ds3231.lua +++ b/lua_modules/ds3231/ds3231.lua @@ -114,7 +114,7 @@ function M.reloadAlarms () i2c.write(id, 0x0F) i2c.write(id, d) i2c.stop(id) - print('[LOG] Alarm '..almId..' reloaded') + print('[LOG] Alarms reloaded') end -- Enable alarmId bit. Let it to be triggered diff --git a/lua_modules/email/imap.lua b/lua_modules/email/imap.lua index b3c2a95cbc..8f7cf4adc3 100644 --- a/lua_modules/email/imap.lua +++ b/lua_modules/email/imap.lua @@ -22,8 +22,6 @@ _G[moduleName] = M local USERNAME = "" local PASSWORD = "" -local SERVER = "" -local PORT = "" local TAG = "" local DEBUG = false @@ -45,10 +43,10 @@ end --- -- @name display -- @description A generic IMAP response processing function. --- Can disply the IMAP response if DEBUG is set to true. --- Sets the reponse processed variable to true when the string "complete" +-- Can display the IMAP response if DEBUG is set to true. +-- Sets the response processed variable to true when the string "complete" -- is found in the IMAP reply/response -local function display(socket, response) +local function display(socket, response) -- luacheck: no unused -- If debuggins is enabled print the IMAP response if(DEBUG) then @@ -67,7 +65,7 @@ end --- -- @name config -- @description Initiates the IMAP settings -function M.config(username,password,tag,debug) +function M.config(username, password, tag, debug) USERNAME = username PASSWORD = password TAG = tag @@ -96,13 +94,13 @@ end -- @description Gets the most recent email number from the EXAMINE command. -- i.e. if EXAMINE returns "* 4 EXISTS" this means that there are 4 emails, -- so the latest/newest will be identified by the number 4 -local function set_most_recent_num(socket,response) +local function set_most_recent_num(socket, response) -- luacheck: no unused if(DEBUG) then print(response) end - local _, _, num = string.find(response,"([0-9]+) EXISTS(\.)") -- the _ and _ keep the index of the string found + local _, _, num = string.find(response,"([0-9]+) EXISTS") -- the _ and _ keep the index of the string found -- but we don't care about that. if(num~=nil) then @@ -117,7 +115,7 @@ end --- -- @name examine -- @description IMAP examines the given mailbox/folder. Sends the IMAP EXAMINE command -function M.examine(socket,mailbox) +function M.examine(socket, mailbox) response_processed = false socket:send(TAG .. " EXAMINE " .. mailbox .. "\r\n") @@ -135,7 +133,7 @@ end -- @name set_header -- @description Records the IMAP header field response in a variable -- so that it may be read later -local function set_header(socket,response) +local function set_header(socket, response) -- luacheck: no unused if(DEBUG) then print(response) end @@ -152,7 +150,7 @@ end -- @param socket The IMAP socket to use -- @param msg_number The email number to read e.g. 1 will read fetch the latest/newest email -- @param field A header field such as SUBJECT, FROM, or DATE -function M.fetch_header(socket,msg_number,field) +function M.fetch_header(socket, msg_number, field) header = "" -- we are getting a new header so clear this variable response_processed = false socket:send(TAG .. " FETCH " .. msg_number .. " BODY[HEADER.FIELDS (" .. field .. ")]\r\n") @@ -171,7 +169,7 @@ end -- @name set_body -- @description Records the IMAP body response in a variable -- so that it may be read later -local function set_body(socket,response) +local function set_body(_, response) if(DEBUG) then print(response) @@ -188,7 +186,7 @@ end -- @description Sends the IMAP command to fetch a plain text version of the email's body -- @param socket The IMAP socket to use -- @param msg_number The email number to obtain e.g. 1 will obtain the latest email -function M.fetch_body_plain_text(socket,msg_number) +function M.fetch_body_plain_text(socket, msg_number) response_processed = false body = "" -- clear the body variable since we'll be fetching a new email socket:send(TAG .. " FETCH " .. msg_number .. " BODY[1]\r\n") diff --git a/lua_modules/fifo/fifosocktest.lua b/lua_modules/fifo/fifosocktest.lua index b2424c46a6..4ac9f2196d 100644 --- a/lua_modules/fifo/fifosocktest.lua +++ b/lua_modules/fifo/fifosocktest.lua @@ -11,7 +11,7 @@ local vprint = (verbose > 0) and print or function() end -- Mock up enough of the nodemcu tmr structure, but pretend that nothing -- happens between ticks. This won't exercise the optimistic corking logic, -- but that's probably fine. --- +-- luacheck: push ignore tmr = {} tmr.ALARM_SINGLE = 0 function tmr.create() @@ -19,6 +19,7 @@ function tmr.create() function r:alarm(_i, _t, cb) vprint("TMR") cb() end return r end +-- luacheck: pop -- -- Mock up enough of the nodemcu net.socket type; have it log all the sends @@ -28,7 +29,7 @@ local outs = {} local fakesock = { cb = nil, on = function(this, _, cb) this.cb = cb end, - send = function(this, s) vprint("SEND", (verbose > 1) and s) table.insert(outs, s) end, + send = function(this, s) vprint("SEND", (verbose > 1) and s) table.insert(outs, s) end -- luacheck: no unused } local function sent() vprint("SENT") fakesock.cb() end @@ -68,25 +69,25 @@ sent() ; fchecke() -- Hit default FSMALLLIM while building up fsendc("abracadabra lots small") -for i = 1, 32 do fsend("a") end +for i = 1, 32 do fsend("a") end -- luacheck: no unused nocoal() -for i = 1, 4 do fsend("a") end +for i = 1, 4 do fsend("a") end -- luacheck: no unused sent() ; fcheck(string.rep("a", 32)) sent() ; fcheck(string.rep("a", 4)) sent() ; fchecke() -- Hit string length while building up fsendc("abracadabra overlong") -for i = 1, 10 do fsend(string.rep("a",32)) end +for i = 1, 10 do fsend(string.rep("a",32)) end -- luacheck: no unused sent() ; fcheck(string.rep("a", 320)) sent() ; fchecke() -- Hit neither before sending a big string fsendc("abracadabra mid long") -for i = 1, 6 do fsend(string.rep("a",32)) end +for i = 1, 6 do fsend(string.rep("a",32)) end -- luacheck: no unused fsend(string.rep("b", 256)) nocoal() -for i = 1, 6 do fsend(string.rep("c",32)) end +for i = 1, 6 do fsend(string.rep("c",32)) end -- luacheck: no unused sent() ; fcheck(string.rep("a", 192) .. string.rep("b", 256)) sent() ; fcheck(string.rep("c", 192)) sent() ; fchecke() @@ -109,33 +110,36 @@ sent() ; fcheck(string.rep("c",512)) sent() ; fchecke() -- test a lazy generator -local ix = 0 -local function gen() vprint("GEN", ix); ix = ix + 1; return ("a" .. ix), ix < 3 and gen end -fsend(gen) -fsend("b") -fcheck("a1") -sent() ; fcheck("a2") -sent() ; fcheck("a3") -sent() ; fcheck("b") -sent() ; fchecke() - +do + local ix = 0 + local function gen() vprint("GEN", ix); ix = ix + 1; return ("a" .. ix), ix < 3 and gen end + fsend(gen) + fsend("b") + fcheck("a1") + sent() ; fcheck("a2") + sent() ; fcheck("a3") + sent() ; fcheck("b") + sent() ; fchecke() +end -- test a completion-like callback that does send text -local ix = 0 -local function gen() vprint("GEN"); ix = 1; return "efgh", nil end -fsend("abcd"); fsend(gen); fsend("ijkl") -assert (ix == 0) - fcheck("abcd"); assert (ix == 0) -sent() ; fcheck("efgh"); assert (ix == 1); ix = 0 -sent() ; fcheck("ijkl"); assert (ix == 0) -sent() ; fchecke() - +do + local ix = 0 + local function gen() vprint("GEN"); ix = 1; return "efgh", nil end + fsend("abcd"); fsend(gen); fsend("ijkl") + assert (ix == 0) + fcheck("abcd"); assert (ix == 0) + sent() ; fcheck("efgh"); assert (ix == 1); ix = 0 + sent() ; fcheck("ijkl"); assert (ix == 0) + sent() ; fchecke() +end -- and one that doesn't -local ix = 0 -local function gen() vprint("GEN"); ix = 1; return nil, nil end -fsend("abcd"); fsend(gen); fsend("ijkl") -assert (ix == 0) - fcheck("abcd"); assert (ix == 0) -sent() ; fcheck("ijkl"); assert (ix == 1); ix = 0 -sent() ; fchecke() ; assert (ix == 0) - +do + local ix = 0 + local function gen() vprint("GEN"); ix = 1; return nil, nil end + fsend("abcd"); fsend(gen); fsend("ijkl") + assert (ix == 0) + fcheck("abcd"); assert (ix == 0) + sent() ; fcheck("ijkl"); assert (ix == 1); ix = 0 + sent() ; fchecke() ; assert (ix == 0) +end print("All tests OK") diff --git a/lua_modules/ftp/ftpserver.lua b/lua_modules/ftp/ftpserver.lua index b488221ab1..6a2d65de05 100644 --- a/lua_modules/ftp/ftpserver.lua +++ b/lua_modules/ftp/ftpserver.lua @@ -19,8 +19,8 @@ Note that FTP also exposes a number of really private properties (which could be stores in local / upvals) as FTP properties for debug purposes. ]] -local file,net,wifi,node,string,table,tmr,pairs,print,pcall, tostring = - file,net,wifi,node,string,table,tmr,pairs,print,pcall, tostring +local file, net, wifi, node, table, tmr, pairs, print, pcall, tostring = + file, net, wifi, node, table, tmr, pairs, print, pcall, tostring local post = node.task.post local FTP, cnt = {client = {}}, 0 @@ -90,18 +90,18 @@ function FTP.createServer(user, pass, dbgFlag) -- upval: FTP (, debug, tostring -- debug("Sending: %s", rec) return CNX.cmdSocket:send(rec.."\r\n", cb) end, --- send() - close = function(sock) -- upval: client, CNX (,debug, pcall, type) + close = function(socket) -- upval: client, CNX (,debug, pcall, type) -- debug("Closing CNX.socket=%s, sock=%s", tostring(CNX.socket), tostring(sock)) for _,s in ipairs{'cmdSocket', 'dataServer', 'dataSocket'} do local sck; sck,CNX[s] = CNX[s], nil -- debug("closing CNX.%s=%s", s, tostring(sck)) if type(sck)=='userdata' then pcall(sck.close, sck) end end - client[sock] = nil + client[socket] = nil end -- CNX.close() } - local function validateUser(sock, data) -- upval: CNX, FTP (, debug, processCommand) + local function validateUser(socket, data) -- upval: CNX, FTP (, debug, processCommand) -- validate the logon and if then switch to processing commands -- debug("Authorising: %s", data) @@ -118,8 +118,8 @@ function FTP.createServer(user, pass, dbgFlag) -- upval: FTP (, debug, tostring elseif CNX.validUser and cmd == 'PASS' then if arg == FTP.pass then CNX.cwd = '/' - sock:on("receive", function(sock,data) - processCommand(CNX,sock,data) + socket:on("receive", function(socketObj, dataObj) + processCommand(CNX,socketObj, dataObj) end) -- logged on so switch to command mode msg = "230 Login successful. Username & password correct; proceed." else @@ -134,8 +134,8 @@ function FTP.createServer(user, pass, dbgFlag) -- upval: FTP (, debug, tostring return CNX.send(msg) end - local port,ip = sock:getpeer() - -- debug("Connection accepted: (userdata) %s client %s:%u", tostring(sock), ip, port) + local port,ip = sock:getpeer() -- luacheck: no unused + --debug("Connection accepted: (userdata) %s client %s:%u", tostring(sock), ip, port) sock:on("receive", validateUser) sock:on("disconnection", CNX.close) FTP.client[sock]=CNX @@ -177,8 +177,8 @@ end -- FTP.close() -- -- Find strings are used do this lookup and minimise long if chains. ------------------------------------------------------------------------------ -processCommand = function(cxt, sock, data) -- upvals: (, debug, processBareCmds, processSimpleCmds, processDataCmds) - +-- upvals: (, debug, processBareCmds, processSimpleCmds, processDataCmds) +processCommand = function(cxt, socket, data) -- luacheck: no unused debug("Command: %s", data) data = data:gsub('[\r\n]+$', '') -- chomp trailing CRLF local cmd, arg = data:match('([a-zA-Z]+) *(.*)') @@ -331,7 +331,7 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin pattern = arg:gsub('*','[^/%%.]*') end - for k,v in pairs(fileSize) do + for k, _ in pairs(fileSize) do if k:match(pattern) then nameList[#nameList+1] = k else @@ -341,8 +341,8 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin table.sort(nameList) function cxt.getData() -- upval: cmd, fileSize, nameList (, table) - local list, user, v = {}, FTP.user - for i = 1,10 do + local list, user = {}, FTP.user + for i = 1,10 do -- luacheck: no unused if #nameList == 0 then break end local f = table.remove(nameList, 1) list[#list+1] = (cmd == "LIST") and @@ -395,9 +395,9 @@ end -- processDataCmds(cmd, arg, send) -- ---------------- Open a new data server and port --------------------------- dataServer = function(cxt, n) -- upval: (pcall, net, ftpDataOpen, debug, tostring) - local dataServer = cxt.dataServer - if dataServer then -- close any existing listener - pcall(dataServer.close, dataServer) + local dataSrv = cxt.dataServer + if dataSrv then -- close any existing listener + pcall(dataSrv.close, dataSrv) end if n then -- Open a new listener if needed. Note that this is only used to establish @@ -425,10 +425,11 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall) cxt.dataServer = nil local function cleardown(skt,type) -- upval: cxt (, debug, tostring, post, pcall) + -- luacheck: push no unused type = type==1 and "disconnection" or "reconnection" local which = cxt.setData and "setData" or (cxt.getData and cxt.getData or "neither") - -- debug("Cleardown entered from %s with %s", type, which) - + --debug("Cleardown entered from %s with %s", type, which) + -- luacheck: pop if cxt.setData then cxt.fileClose() cxt.setData = nil @@ -446,8 +447,9 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall) local on_hold = false dataSocket:on("receive", function(skt, rec) --upval: cxt, on_hold (, debug, tstring, post, node, pcall) - local which = cxt.setData and "setData" or (cxt.getData and cxt.getData or "neither") - -- debug("Received %u data bytes with %s", #rec, which) + + local which = cxt.setData and "setData" or (cxt.getData and cxt.getData or "neither")-- luacheck: no unused + --debug("Received %u data bytes with %s", #rec, which) if not cxt.setData then return end @@ -476,7 +478,8 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall) function cxt.sender(skt) -- upval: cxt (, debug) debug ("entering sender") if not cxt.getData then return end - local rec, skt = cxt.getData(), cxt.dataSocket + skt = skt or cxt.dataSocket + local rec = cxt.getData() if rec and #rec > 0 then -- debug("Sending %u data bytes", #rec) skt:send(rec) diff --git a/lua_modules/hdc1000/HDC1000-example.lua b/lua_modules/hdc1000/HDC1000-example.lua index d4c08c7633..c2e10c0486 100644 --- a/lua_modules/hdc1000/HDC1000-example.lua +++ b/lua_modules/hdc1000/HDC1000-example.lua @@ -1,14 +1,17 @@ -HDC1000 = require("HDC1000") +local HDC1000 = require("HDC1000") -sda = 1 -scl = 2 -drdyn = false +local sda, scl = 1, 2 +local drdyn = false -i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once -HDC1000.setup(drdyn) -HDC1000.config() -- default values are used if called with no arguments. prototype is config(address, resolution, heater) +do + i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once + HDC1000.setup(drdyn) + -- prototype is config(address, resolution, heater) + HDC1000.config() -- default values are used if called with no arguments. -print(string.format("Temperature: %.2f °C\nHumidity: %.2f %%", HDC1000.getTemp(), HDC1000.getHumi())) + print(string.format("Temperature: %.2f °C\nHumidity: %.2f %%", HDC1000.getTemp(), HDC1000.getHumi())) -HDC1000 = nil -package.loaded["HDC1000"]=nil + -- Don't forget to release it after use + HDC1000 = nil -- luacheck: no unused + package.loaded["HDC1000"] = nil +end \ No newline at end of file diff --git a/lua_modules/hdc1000/HDC1000.lua b/lua_modules/hdc1000/HDC1000.lua index 8067afe9b7..40b0180c60 100644 --- a/lua_modules/hdc1000/HDC1000.lua +++ b/lua_modules/hdc1000/HDC1000.lua @@ -40,9 +40,9 @@ local HDC1000_TEMP_HUMI_14BIT = 0x00 local function read16() i2c.start(id) i2c.address(id, HDC1000_ADDR, i2c.RECEIVER) - data_temp = i2c.read(0, 2) + local data_temp = i2c.read(0, 2) i2c.stop(id) - data = bit.lshift(string.byte(data_temp, 1, 1), 8) + string.byte(data_temp, 2, 2) + local data = bit.lshift(string.byte(data_temp, 1, 1), 8) + string.byte(data_temp, 2, 2) return data end diff --git a/lua_modules/http/http-example.lua b/lua_modules/http/http-example.lua index ea03a46e5d..9a8509955b 100644 --- a/lua_modules/http/http-example.lua +++ b/lua_modules/http/http-example.lua @@ -8,7 +8,7 @@ require("httpserver").createServer(80, function(req, res) -- analyse method and url print("+R", req.method, req.url, node.heap()) -- setup handler of headers, if any - req.onheader = function(self, name, value) + req.onheader = function(self, name, value) -- luacheck: ignore print("+H", name, value) -- E.g. look for "content-type" header, -- setup body parser to particular format @@ -21,7 +21,7 @@ require("httpserver").createServer(80, function(req, res) -- end end -- setup handler of body, if any - req.ondata = function(self, chunk) + req.ondata = function(self, chunk) -- luacheck: ignore print("+B", chunk and #chunk, node.heap()) if not chunk then -- reply diff --git a/lua_modules/http/httpserver.lua b/lua_modules/http/httpserver.lua index 50717e1e96..bce4dfb899 100644 --- a/lua_modules/http/httpserver.lua +++ b/lua_modules/http/httpserver.lua @@ -48,7 +48,7 @@ do csend("\r\n") end end - local send_header = function(self, name, value) + local send_header = function(self, name, value) -- luacheck: ignore -- NB: quite a naive implementation csend(name) csend(": ") @@ -88,13 +88,13 @@ do local req, res local buf = "" local method, url - local ondisconnect = function(conn) - conn.on("sent", nil) + local ondisconnect = function(connection) + connection.on("sent", nil) collectgarbage("collect") end -- header parser local cnt_len = 0 - local onheader = function(conn, k, v) + local onheader = function(connection, k, v) -- luacheck: ignore -- TODO: look for Content-Type: header -- to help parse body -- parse content length to know body length @@ -111,19 +111,19 @@ do end -- body data handler local body_len = 0 - local ondata = function(conn, chunk) + local ondata = function(connection, chunk) -- luacheck: ignore -- feed request data to request handler if not req or not req.ondata then return end req:ondata(chunk) -- NB: once length of seen chunks equals Content-Length: - -- ondata(conn) is called + -- ondata(conn) is called body_len = body_len + #chunk -- print("-B", #chunk, body_len, cnt_len, node.heap()) if body_len >= cnt_len then req:ondata() end end - local onreceive = function(conn, chunk) + local onreceive = function(connection, chunk) -- merge chunks in buffer if buf then buf = buf .. chunk @@ -139,12 +139,12 @@ do buf = buf:sub(e + 2) -- method, url? if not method then - local i + local i, _ -- luacheck: ignore -- NB: just version 1.1 assumed _, i, method, url = line:find("^([A-Z]+) (.-) HTTP/1.1$") if method then -- make request and response objects - req = make_req(conn, method, url) + req = make_req(connection, method, url) res = make_res(csend, cfini) end -- spawn request handler @@ -156,17 +156,17 @@ do -- header seems ok? if k then k = k:lower() - onheader(conn, k, v) + onheader(connection, k, v) end -- headers end else -- NB: we feed the rest of the buffer as starting chunk of body - ondata(conn, buf) + ondata(connection, buf) -- buffer no longer needed buf = nil -- NB: we explicitly reassign receive handler so that -- next received chunks go directly to body handler - conn:on("receive", ondata) + connection:on("receive", ondata) -- parser done break end diff --git a/lua_modules/lm92/lm92.lua b/lua_modules/lm92/lm92.lua index b8f331b80d..802373e50e 100644 --- a/lua_modules/lm92/lm92.lua +++ b/lua_modules/lm92/lm92.lua @@ -24,7 +24,6 @@ local address = 0 local function read_reg(reg_addr, len) local ret={} local c - local x i2c.start(id) i2c.address(id, address ,i2c.TRANSMITTER) i2c.write(id,reg_addr) @@ -32,9 +31,9 @@ local function read_reg(reg_addr, len) i2c.start(id) i2c.address(id, address,i2c.RECEIVER) c=i2c.read(id,len) - for x=1,len,1 do - tc=string.byte(c,x) - table.insert(ret,tc) + for x = 1, len, 1 do + local tc = string.byte(c, x) + table.insert(ret, tc) end i2c.stop(id) return ret @@ -64,7 +63,7 @@ function M.setup(a) if (a ~= nil) and (a >= 0x48) and (a <= 0x4b ) then address = a i2c.start(id) - res = i2c.address(id, address, i2c.TRANSMITTER) --verify that the address is valid + local res = i2c.address(id, address, i2c.TRANSMITTER) --verify that the address is valid i2c.stop(id) if (res == false) then print("device not found") diff --git a/lua_modules/mcp23008/mcp23008.lua b/lua_modules/mcp23008/mcp23008.lua index dc5e4122d7..3e2bf9a3be 100644 --- a/lua_modules/mcp23008/mcp23008.lua +++ b/lua_modules/mcp23008/mcp23008.lua @@ -17,6 +17,7 @@ _G[moduleName] = M local MCP23008_ADDRESS = 0x20 -- Registers' address as defined in the MCP23008's datashseet +-- luacheck: push no unused local MCP23008_IODIR = 0x00 local MCP23008_IPOL = 0x01 local MCP23008_GPINTEN = 0x02 @@ -28,7 +29,7 @@ local MCP23008_INTF = 0x07 local MCP23008_INTCAP = 0x08 local MCP23008_GPIO = 0x09 local MCP23008_OLAT = 0x0A - +-- luacheck: pop -- Default value for i2c communication local id = 0 @@ -75,8 +76,7 @@ local function read(registerAddress) i2c.start(id) -- Read the data form the register i2c.address(id,MCP23008_ADDRESS,i2c.RECEIVER) -- send the MCP's address and read bit - local data = 0x00 - data = i2c.read(id,1) -- we expect only one byte of data + local data = i2c.read(id,1) -- we expect only one byte of data i2c.stop(id) return string.byte(data) -- i2c.read returns a string so we convert to it's int value diff --git a/lua_modules/redis/redis.lua b/lua_modules/redis/redis.lua index cc4bf64db6..94005e09b3 100644 --- a/lua_modules/redis/redis.lua +++ b/lua_modules/redis/redis.lua @@ -55,7 +55,7 @@ do -- FIXME: this suddenly occurs. timeout? --print("-FD") end) - _fd:on("receive", function(fd, s) + _fd:on("receive", function(fd, s) --luacheck: no unused --print("IN", s) -- TODO: subscription to all channels -- lookup message pattern to determine channel and payload diff --git a/lua_modules/yeelink/Example_for_Yeelink_Lib.lua b/lua_modules/yeelink/Example_for_Yeelink_Lib.lua index 129bc47878..c000046bd1 100644 --- a/lua_modules/yeelink/Example_for_Yeelink_Lib.lua +++ b/lua_modules/yeelink/Example_for_Yeelink_Lib.lua @@ -10,13 +10,13 @@ wifi.setmode(wifi.STATION) --Step1: Connect to Wifi wifi.sta.config("SSID","Password") -dht = require("dht_lib") --Step2: "Require" the libs -yeelink = require("yeelink_lib") +local dht = require("dht_lib") --Step2: "Require" the libs +local yeelink = require("yeelink_lib") yeelink.init(23333,23333,"You api-key",function() --Step3: Register the callback function print("Yeelink Init OK...") - tmr.alarm(1,60000,1,function() --Step4: Have fun~ (Update your data) + tmr.create():alarm(60000, tmr.ALARM_AUTO, function() --Step4: Have fun~ (Update your data) dht.read(4) yeelink.update(dht.getTemperature()) diff --git a/lua_modules/yeelink/yeelink_lib.lua b/lua_modules/yeelink/yeelink_lib.lua index 004bbe0e44..70c6c4a415 100644 --- a/lua_modules/yeelink/yeelink_lib.lua +++ b/lua_modules/yeelink/yeelink_lib.lua @@ -22,7 +22,7 @@ local apikey = "" --================================ local debug = true --<<<<<<<<<<<<< Don't forget to "false" it before using --================================ -local sk=net.createConnection(net.TCP, 0) +local sk = net.createConnection(net.TCP, 0) local datapoint = 0 @@ -31,10 +31,11 @@ local datapoint = 0 if wifi.sta.getip() == nil then print("Please Connect WIFI First") - tmr.alarm(1,1000,1,function () + local wifiTimer = tmr.create() + wifiTimer:alarm(1000, tmr.ALARM_AUTO,function () if wifi.sta.getip() ~= nil then - tmr.stop(1) - sk:dns("api.yeelink.net",function(conn,ip) + wifiTimer:stop() + sk:dns("api.yeelink.net",function(_,ip) dns=ip print("DNS YEELINK OK... IP: "..dns) end) @@ -42,12 +43,9 @@ if wifi.sta.getip() == nil then end) end -sk:dns("api.yeelink.net",function(conn,ip) - -dns=ip - -print("DNS YEELINK OK... IP: "..dns) - +sk:dns("api.yeelink.net",function(conn, ip) -- luacheck: no unused + dns = ip + print("DNS YEELINK OK... IP: "..dns) end) --========Set the init function=========== @@ -61,12 +59,12 @@ function M.init(_device, _sensor, _apikey) sensor = tostring(_sensor) apikey = _apikey if dns == "0.0.0.0" then - tmr.alarm(2,5000,1,function () - if dns == "0.0.0.0" then - print("Waiting for DNS...") - end - end) - return false + tmr.create():alarm(5000,tmr.ALARM_AUTO,function () + if dns == "0.0.0.0" then + print("Waiting for DNS...") + end + end) + return false else return dns end @@ -96,7 +94,7 @@ function M.update(_datapoint) datapoint = tostring(_datapoint) - sk:on("connection", function(conn) + sk:on("connection", function() print("connect OK...") @@ -116,7 +114,7 @@ function M.update(_datapoint) end) - sk:on("receive", function(sck, content) + sk:on("receive", function(conn, content) -- luacheck: no unused if debug then print("\r\n"..content.."\r\n") diff --git a/tools/luacheck_config.lua b/tools/luacheck_config.lua index 34a8b6eb59..85147ec788 100644 --- a/tools/luacheck_config.lua +++ b/tools/luacheck_config.lua @@ -173,6 +173,32 @@ stds.nodemcu_libs = { toHex = empty } }, + dcc = { + fields = { + CV_READ = empty, + CV_RESET = empty, + CV_VALID = empty, + CV_WRITE = empty, + DCC_ACCESSORY = empty, + DCC_FUNC = empty, + DCC_IDLE = empty, + DCC_RAW = empty, + DCC_RESET = empty, + DCC_SERVICEMODE = empty, + DCC_SPEED = empty, + DCC_SPEED_RAW = empty, + DCC_TURNOUT = empty, + FLAGS_AUTO_FACTORY_DEFAULT = empty, + FLAGS_DCC_ACCESSORY_DECODER = empty, + FLAGS_MY_ADDRESS_ONLY = empty, + FLAGS_OUTPUT_ADDRESS_MODE = empty, + MAN_ID_DIY = empty, + MAN_ID_JMRI = empty, + MAN_ID_SILICON_RAILWAY = empty, + close = empty, + setup = empty + } + }, dht = { fields = { ERROR_CHECKSUM = empty, @@ -200,12 +226,17 @@ stds.nodemcu_libs = { }, file = { fields = { + chdir = empty, close = empty, exists = empty, flush = empty, + format = empty, + fscfg = empty, fsinfo = empty, getcontents = empty, list = empty, + mount = empty, + n = empty, on = empty, open = empty, putcontents = empty, @@ -393,7 +424,10 @@ stds.nodemcu_libs = { }, task = { fields = { - post = empty + post = empty, + LOW_PRIORITY = empty, + MEDIUM_PRIORITY = empty, + HIGH_PRIORITY = empty } } } @@ -576,6 +610,13 @@ stds.nodemcu_libs = { transaction = empty } }, + struct = { + fields = { + pack = empty, + size = empty, + unpack = empty + } + }, switec = { fields = { close = empty, @@ -876,7 +917,8 @@ stds.nodemcu_libs = { }, pack = empty, unpack = empty, - size = empty + size = empty, + package = {fields = {seeall = read_write}} } } diff --git a/tools/luacheck_config_helper.lua b/tools/luacheck_config_helper.lua index f7b5bb2e62..58bce3fab1 100755 --- a/tools/luacheck_config_helper.lua +++ b/tools/luacheck_config_helper.lua @@ -114,6 +114,12 @@ local function printTables(fileName) if not findBegin then findBegin, _, field = string.find(line, "LROT_TABENTRY%(%s?(%g+),") end + if not findBegin then + findBegin, _, field = string.find(line, "LROT_FUNCENTRY_S%(%s?(%g+),") + end + if not findBegin then + findBegin, _, field = string.find(line, "LROT_FUNCENTRY_F%(%s?(%g+),") + end if findBegin then if not string.find(field, "__") then diff --git a/tools/travis/run-luacheck-linux.sh b/tools/travis/run-luacheck-linux.sh new file mode 100755 index 0000000000..929f92e4d2 --- /dev/null +++ b/tools/travis/run-luacheck-linux.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +set -e + +exists() { + if command -v "$1" >/dev/null 2>&1 + then + return 0 + else + return 1 + fi +} + +usage() { +echo " +usage: bash tools/travis/run-luacheck.sh [-s] + +Avarible options are: +-s: Standalone mode: Lua, LuaRocks and luacheck +will be installed in nodemcu-firmare/cache folder. + +By default script will use luarocks installed in host system. +" +} + +install_tools() { + if ! exists luarocks; then + echo "LuaRocks not found!" + exit 1 + fi + + eval "`luarocks path --bin`" #Set PATH for luacheck + #In Travis Path it's not changed by LuaRocks for some unknown reason + if [ "${TRAVIS}" = "true" ]; then + export PATH=$PATH:/home/travis/.luarocks/bin + fi + + if ! exists luacheck; then + echo "Installing luacheck" + luarocks install --local luacheck || exit + fi + +} + +install_tools_standalone() { + if ! [ -x cache/localua/bin/luarocks ]; then + echo "Installing Lua 5.3 and LuaRocks" + bash tools/travis/localua.sh cache/localua || exit + fi + + if ! [ -x cache/localua/bin/luacheck ]; then + echo "Installing luacheck" + cache/localua/bin/luarocks install luacheck || exit + fi +} + +if [[ $1 == "" ]]; then + install_tools + else + while getopts "s" opt + do + case $opt in + (s) install_tools_standalone ;; + (*) usage; exit 1 ;; + esac + done +fi + +echo "Static analysys of" +find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo + +(find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 luacheck --config tools/luacheck_config.lua) || exit diff --git a/tools/travis/run-luacheck-windows.sh b/tools/travis/run-luacheck-windows.sh new file mode 100644 index 0000000000..682510de66 --- /dev/null +++ b/tools/travis/run-luacheck-windows.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +#Download luacheck binary if nessesary +if ! [ -x "cache/luacheck.exe" ]; then + wget --tries=5 --timeout=10 --waitretry=10 --read-timeout=10 --retry-connrefused -O cache/luacheck.exe https://github.com/mpeterv/luacheck/releases/download/0.23.0/luacheck.exe +fi + +echo "Static analysys of" +find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo + +(find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 cache/luacheck.exe --config tools/luacheck_config.lua) || exit diff --git a/tools/travis/run-luacheck.sh b/tools/travis/run-luacheck.sh deleted file mode 100644 index d97241f715..0000000000 --- a/tools/travis/run-luacheck.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -echo "Installing Lua 5.3, LuaRocks and Luacheck" -( - cd "$TRAVIS_BUILD_DIR" || exit - bash tools/travis/localua.sh cache/localua || exit - cache/localua/bin/luarocks install luacheck || exit -) - -( - echo "Static analysys of:" - find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo -) - -(find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 cache/localua/bin/luacheck --config tools/luacheck_config.lua) || exit From 7ed3d0007b972e0632006bf36af0490434212741 Mon Sep 17 00:00:00 2001 From: "M.K" Date: Wed, 1 Jan 2020 23:31:04 +0100 Subject: [PATCH 24/59] Minor typo and wording fixes (#2991) --- app/include/user_config.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/include/user_config.h b/app/include/user_config.h index 0f988d6db2..dbb3447e4e 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -59,7 +59,7 @@ // NodeMCU supports two file systems: SPIFFS and FATFS, the first is available -// on all ESP8266 modules. The latter requires extra H/W so is less common. +// on all ESP8266 modules. The latter requires extra H/W so it is less common. // If you use SPIFFS then there are a number of options which impact the // RAM overhead and performance of the file system. @@ -87,7 +87,7 @@ // The HTTPS stack requires client SSL to be enabled. The SSL buffer size is // used only for espconn-layer secure connections, and is ignored otherwise. -// Some HTTPS applications require a larger buffer size to work. See +// Some HTTPS applications require a larger buffer size to work. See // https://github.com/nodemcu/nodemcu-firmware/issues/1457 for details. // The SHA2 and MD2 libraries are also optionally used by the crypto functions. // The SHA1 and MD5 function are implemented in the ROM BIOS. The MD2 and SHA2 @@ -101,8 +101,8 @@ // GPIO_INTERRUPT_ENABLE needs to be defined if your application uses the // gpio.trig() or related GPIO interrupt service routine code. Likewise the -// GPIO interrupt hook is requited for a few modules such as rotary. If you -// don't require this functionality, then commenting out these options out +// GPIO interrupt hook is required for a few modules such as rotary. If you +// don't require this functionality, then commenting out these options // will remove any associated runtime overhead. #define GPIO_INTERRUPT_ENABLE @@ -170,7 +170,7 @@ #define I2C_MASTER_OLD_VERSION -// The following sections are only relevent for those developers who are +// The following sections are only relevant for those developers who are // developing modules or core Lua changes and configure how extra diagnostics // are enabled in the firmware. These should only be configured if you are // building your own custom firmware and have full access to the firmware From 8c08e7648d5a0e98e3e293e36ec7e73b31958874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Voborsk=C3=BD?= Date: Thu, 2 Jan 2020 21:38:22 +0100 Subject: [PATCH 25/59] Add CRC check (#2992) Also clean-up a nasty `ow` module example. --- docs/modules/ow.md | 60 +++++++++++++++------------------ lua_modules/ds18b20/ds18b20.lua | 30 ++++++++++------- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/docs/modules/ow.md b/docs/modules/ow.md index 0c13c21e31..e09819cba3 100644 --- a/docs/modules/ow.md +++ b/docs/modules/ow.md @@ -145,48 +145,42 @@ Issues a 1-Wire rom select command. Make sure you do the `ow.reset(pin)` first. #### Example ```lua -- 18b20 Example -pin = 9 +-- 18b20 Example +pin = 3 ow.setup(pin) -count = 0 -repeat - count = count + 1 - addr = ow.reset_search(pin) - addr = ow.search(pin) - tmr.wdclr() -until (addr ~= nil) or (count > 100) +addr = ow.reset_search(pin) +addr = ow.search(pin) + if addr == nil then - print("No more addresses.") + print("No device detected.") else print(addr:byte(1,8)) - crc = ow.crc8(string.sub(addr,1,7)) + local crc = ow.crc8(string.sub(addr,1,7)) if crc == addr:byte(8) then if (addr:byte(1) == 0x10) or (addr:byte(1) == 0x28) then print("Device is a DS18S20 family device.") - repeat + tmr.create():alarm(1000, tmr.ALARM_AUTO, function() ow.reset(pin) ow.select(pin, addr) - ow.write(pin, 0x44, 1) - tmr.delay(1000000) - present = ow.reset(pin) - ow.select(pin, addr) - ow.write(pin,0xBE,1) - print("P="..present) - data = nil - data = string.char(ow.read(pin)) - for i = 1, 8 do - data = data .. string.char(ow.read(pin)) - end - print(data:byte(1,9)) - crc = ow.crc8(string.sub(data,1,8)) - print("CRC="..crc) - if crc == data:byte(9) then - t = (data:byte(1) + data:byte(2) * 256) * 625 - t1 = t / 10000 - t2 = t % 10000 - print("Temperature="..t1.."."..t2.."Centigrade") - end - tmr.wdclr() - until false + ow.write(pin, 0x44, 1) -- convert T command + tmr.create():alarm(750, tmr.ALARM_SINGLE, function() + ow.reset(pin) + ow.select(pin, addr) + ow.write(pin,0xBE,1) -- read scratchpad command + local data = ow.read_bytes(pin, 9) + print(data:byte(1,9)) + local crc = ow.crc8(string.sub(data,1,8)) + print("CRC="..crc) + if crc == data:byte(9) then + local t = (data:byte(1) + data:byte(2) * 256) * 625 + local sgn = t<0 and -1 or 1 + local tA = sgn*t + local t1 = math.floor(tA / 10000) + local t2 = tA % 10000 + print("Temperature="..(sgn<0 and "-" or "")..t1.."."..t2.." Centigrade") + end + end) + end) else print("Device family is not recognized.") end diff --git a/lua_modules/ds18b20/ds18b20.lua b/lua_modules/ds18b20/ds18b20.lua index a40e27c0f9..dcc4b065d4 100644 --- a/lua_modules/ds18b20/ds18b20.lua +++ b/lua_modules/ds18b20/ds18b20.lua @@ -69,6 +69,7 @@ local function readout(self) -- the DS18B20 family has 4 fractional bits and the DS18S20s, 1 fractional bit t = ((t <= 32767) and t or t - 65536) * ((addr:byte(1) == DS18B20FAMILY) and 625 or 5000) + local crc, b9 = ow_crc8(string.sub(data,1,8)), data:byte(9) if 1/2 == 0 then -- integer version @@ -83,22 +84,22 @@ local function readout(self) local tL=(tA%10000)/1000 + ((tA%1000)/100 >= 5 and 1 or 0) if tH and (t~=850000) then - temp[addr]=(sgn<0 and "-" or "")..tH.."."..tL - debugPrint(to_string(addr),(sgn<0 and "-" or "")..tH.."."..tL) + debugPrint(to_string(addr),(sgn<0 and "-" or "")..tH.."."..tL, crc, b9) + if crc==b9 then temp[addr]=(sgn<0 and "-" or "")..tH.."."..tL end status[i] = 2 end -- end integer version else -- float version - if t and (math_floor(t/10000)~=85) then - t = t / 10000 + t = t / 10000 + if math_floor(t)~=85 then if unit == 'F' then t = t * 18/10 + 32 elseif unit == 'K' then t = t + 27315/100 end - self.temp[addr]=t - debugPrint(to_string(addr), t) + debugPrint(to_string(addr), t, crc, b9) + if crc==b9 then temp[addr]=t end status[i] = 2 end -- end float version @@ -123,19 +124,22 @@ conversion = (function (self) if powered_only then debugPrint("starting conversion: all sensors") ow_reset(pin) - ow_skip(pin) -- select the sensor + ow_skip(pin) -- skip ROM selection, talk to all sensors ow_write(pin, CONVERT_T, MODE) -- and start conversion for i, _ in ipairs(sens) do status[i] = 1 end else + local started = false for i, s in ipairs(sens) do if status[i] == 0 then - local addr, parasite = s:sub(1,8), s:byte(9) - debugPrint("starting conversion:", to_string(addr), parasite == 1 and "parasite" or " ") + local addr, parasite = s:sub(1,8), s:byte(9) == 1 + if parasite and started then break end -- do not start concurrent conversion of powered and parasite + debugPrint("starting conversion:", to_string(addr), parasite and "parasite" or "") ow_reset(pin) ow_select(pin, addr) -- select the sensor ow_write(pin, CONVERT_T, MODE) -- and start conversion status[i] = 1 - if parasite == 1 then break end -- parasite sensor blocks bus during conversion + if parasite then break end -- parasite sensor blocks bus during conversion + started = true end end end @@ -169,7 +173,6 @@ local function _search(self, lcb, lpin, search, save) for i, _ in ipairs(sens) do status[i] = 0 end end local function cycle() - debugPrint("cycle") if addr then local crc=ow_crc8(addr:sub(1,7)) if (crc==addr:byte(8)) and ((addr:byte(1)==DS1920FAMILY) or (addr:byte(1)==DS18B20FAMILY)) then @@ -177,8 +180,9 @@ local function _search(self, lcb, lpin, search, save) ow_select(pin, addr) ow_write(pin, READ_POWERSUPPLY, MODE) local parasite = (ow_read(pin)==0 and 1 or 0) - sens[#sens+1]= addr..string_char(parasite) -- {addr=addr, parasite=parasite, status=0} - debugPrint("contact: ", to_string(addr), parasite == 1 and "parasite" or " ") + sens[#sens+1]= addr..string_char(parasite) + status[#sens] = 0 + debugPrint("contact: ", to_string(addr), parasite == 1 and "parasite" or "") end addr = ow_search(pin) node_task_post(node_task_LOW_PRIORITY, cycle) From 5278944a69779d53f98546994a7ce77683196689 Mon Sep 17 00:00:00 2001 From: galjonsfigur <44552519+galjonsfigur@users.noreply.github.com> Date: Fri, 3 Jan 2020 12:12:29 +0100 Subject: [PATCH 26/59] Fix compile warning and set correct order in module LROT (#2996) --- app/modules/softuart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/modules/softuart.c b/app/modules/softuart.c index 96db98e91c..02eaa9b6e7 100644 --- a/app/modules/softuart.c +++ b/app/modules/softuart.c @@ -38,7 +38,7 @@ softuart_t * softuart_gpio_instances[SOFTUART_GPIO_COUNT] = {NULL}; // Array of callback reference to be able to find which callback is used to which rx pin static int softuart_rx_cb_ref[SOFTUART_GPIO_COUNT]; // Task for receiving data -static task_handle_t uart_recieve_task = NULL; +static task_handle_t uart_recieve_task = 0; // Receiving buffer for callback usage static char softuart_rx_buffer[SOFTUART_MAX_RX_BUFF]; @@ -388,8 +388,8 @@ static int softuart_gcdelete(lua_State *L) // Port function map LROT_BEGIN(softuart_port) LROT_FUNCENTRY( on, softuart_on) - LROT_TABENTRY( __index, softuart_port) LROT_FUNCENTRY( write, softuart_write) + LROT_TABENTRY( __index, softuart_port) LROT_FUNCENTRY( __gc, softuart_gcdelete) LROT_END(ads1115, softuart_port, LROT_MASK_GC_INDEX) From 1c83f027e2e4972c66a5dd2db71d87ab3ae80a15 Mon Sep 17 00:00:00 2001 From: Nikolay Fiykov Date: Sat, 4 Jan 2020 22:48:08 +0200 Subject: [PATCH 27/59] Expose CPU CCOUNT register as tmr function (#2906) --- app/modules/tmr.c | 8 ++++++++ app/platform/platform.h | 3 +++ docs/modules/tmr.md | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/app/modules/tmr.c b/app/modules/tmr.c index 10c09db3e2..5c68900193 100644 --- a/app/modules/tmr.c +++ b/app/modules/tmr.c @@ -142,6 +142,13 @@ static int tmr_now(lua_State* L){ return 1; } +// Lua: tmr.ccount() , returns CCOUNT register +static int tmr_ccount( lua_State* L ) +{ + lua_pushinteger(L, CCOUNT_REG); + return 1; +} + static tmr_t tmr_get( lua_State *L, int stack ) { tmr_t t = (tmr_t)luaL_checkudata(L, stack, "tmr.timer"); if (t == NULL) @@ -392,6 +399,7 @@ LROT_BEGIN(tmr) LROT_FUNCENTRY( wdclr, tmr_wdclr ) LROT_FUNCENTRY( softwd, tmr_softwd ) LROT_FUNCENTRY( time, tmr_time ) + LROT_FUNCENTRY( ccount, tmr_ccount ) #ifdef TIMER_SUSPEND_ENABLE LROT_FUNCENTRY( suspend_all, tmr_suspend_all ) LROT_FUNCENTRY( resume_all, tmr_resume_all ) diff --git a/app/platform/platform.h b/app/platform/platform.h index 68c6811f5f..36aee52695 100644 --- a/app/platform/platform.h +++ b/app/platform/platform.h @@ -372,4 +372,7 @@ platform_task_handle_t platform_task_get_id(platform_task_callback_t t); bool platform_post(uint8 prio, platform_task_handle_t h, platform_task_param_t par); +// Get current value of CCOUNt register +#define CCOUNT_REG ({ int32_t r; asm volatile("rsr %0, ccount" : "=r"(r)); r;}) + #endif diff --git a/docs/modules/tmr.md b/docs/modules/tmr.md index cfe4135aaa..5ac52f33d4 100644 --- a/docs/modules/tmr.md +++ b/docs/modules/tmr.md @@ -145,6 +145,42 @@ none #### Returns `nil` +## tmr.ccount() + +Get value of CPU CCOUNT register which contains CPU ticks. The register is 32-bit and rolls over. + +Converting the register's CPU ticks to us is done by dividing it to 80 or 160 (CPU80/CPU160) i.e. `tmr.ccount() / node.getcpufreq()`. + +Register arithmetic works without need to account for roll over, unlike `tmr.now()`. Because of same reason when CCOUNT is having its 32nd bit set, it appears in Lua as negative number. + +#### Syntax +`tmr.ccount()` + +#### Returns +The current value of CCOUNT register. + +#### Example +```lua +function timeIt(fnc, cnt) + local function loopIt(f2) + local t0 = tmr.ccount() + for i=1,cnt do + f2() + end + local t1 = tmr.ccount() + return math.ceil((t1-t0)/cnt) + end + assert(type(fnc) == "function", "function to test missing") + cnt = cnt or 1000 + local emptyTime = loopIt(function()end) + local deltaCPUTicks = math.abs(loopIt(fnc) - emptyTime) + local deltaUS = math.ceil(deltaCPUTicks/node.getcpufreq()) + return deltaCPUTicks, deltaUS +end + +print( timeIt(function() tmr.ccount() end) ) +``` + ## Timer Object Methods ### tobj:alarm() From 49f25bd8955f88df518451b28fb8dfb24963f8ce Mon Sep 17 00:00:00 2001 From: "M.K" Date: Sat, 1 Feb 2020 22:12:14 +0100 Subject: [PATCH 28/59] Clarify LFS build info is its size (#3022) --- app/modules/node.c | 2 +- tools/update_buildinfo.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/modules/node.c b/app/modules/node.c index 6714a6b874..6746517401 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -163,7 +163,7 @@ static int node_info( lua_State* L ) int table_index = lua_gettop(L); lua_pushboolean(L, BUILDINFO_SSL); lua_setfield(L, table_index, "ssl"); - lua_pushnumber(L, BUILDINFO_LFS); + lua_pushnumber(L, BUILDINFO_LFS_SIZE); lua_setfield(L, table_index, "lfs_size"); lua_pushstring(L, BUILDINFO_MODULES); lua_setfield(L, table_index, "modules"); diff --git a/tools/update_buildinfo.sh b/tools/update_buildinfo.sh index 66370a90d3..7caa09e5d5 100755 --- a/tools/update_buildinfo.sh +++ b/tools/update_buildinfo.sh @@ -22,9 +22,9 @@ cat > $TEMPFILE << EndOfMessage #define BUILDINFO_TO_STR(x) BUILDINFO_STR_HELPER(x) #ifdef LUA_FLASH_STORE -#define BUILDINFO_LFS LUA_FLASH_STORE +#define BUILDINFO_LFS_SIZE LUA_FLASH_STORE #else -#define BUILDINFO_LFS 0 +#define BUILDINFO_LFS_SIZE 0 #endif #ifdef CLIENT_SSL_ENABLE @@ -57,7 +57,7 @@ cat > $TEMPFILE << EndOfMessage "\trelease DTS: " BUILDINFO_RELEASE_DTS "\n" \\ "\tSSL: " BUILDINFO_SSL_STR "\n" \\ "\tbuild type: " BUILDINFO_BUILD_TYPE "\n" \\ - "\tLFS: " BUILDINFO_TO_STR(BUILDINFO_LFS) "\n" \\ + "\tLFS: " BUILDINFO_TO_STR(BUILDINFO_LFS_SIZE) " bytes total capacity\n" \\ "\tmodules: " BUILDINFO_MODULES "\n" EndOfMessage From 76e9f1a8c70e4a0a0bcd4902c866d813409eb05b Mon Sep 17 00:00:00 2001 From: Gregor Hartmann Date: Sat, 1 Feb 2020 22:24:12 +0100 Subject: [PATCH 29/59] Document tls.cert.auth (#3010) --- app/modules/tls.c | 7 +++-- docs/modules/tls.md | 74 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/app/modules/tls.c b/app/modules/tls.c index b9a63f6202..72cc0d95a5 100644 --- a/app/modules/tls.c +++ b/app/modules/tls.c @@ -525,7 +525,8 @@ static const char *fill_page_with_pem(lua_State *L, const unsigned char *flash_m return NULL; } -// Lua: tls.cert.auth(true / false | PEM data [, PEM data] ) +// Lua: tls.cert.auth(PEM data [, PEM data] ) +// Lua: tls.cert.auth(true / false) static int tls_cert_auth(lua_State *L) { int enable; @@ -565,7 +566,8 @@ static int tls_cert_auth(lua_State *L) return 1; } -// Lua: tls.cert.verify(true / false | PEM data [, PEM data] ) +// Lua: tls.cert.verify(PEM data [, PEM data] ) +// Lua: tls.cert.verify(true / false) static int tls_cert_verify(lua_State *L) { int enable; @@ -579,7 +581,6 @@ static int tls_cert_verify(lua_State *L) if (lua_type(L, 1) == LUA_TSTRING) { const char *types[2] = { "CERTIFICATE", NULL }; const char *names[1] = { "certificate" }; - const char *error = fill_page_with_pem(L, &tls_server_cert_area[0], flash_offset, types, names); if (error) { return luaL_error(L, error); diff --git a/docs/modules/tls.md b/docs/modules/tls.md index 1f142daca4..a6333c28c3 100644 --- a/docs/modules/tls.md +++ b/docs/modules/tls.md @@ -33,7 +33,7 @@ most common features supported. Specifically, it provides: the TLS specification, which requires a 16KiB recieve buffer and, therefore, 32KiB of heap within mbedTLS, even in the steady-state. While it is possible to slightly raise the buffer sizes with custom - nodeMCU builds, connecting to endpoints out of your control will remain + NodeMCU builds, connecting to endpoints out of your control will remain a precarious position, and so we strongly suggest that TLS connections be made only to endpoints under your control, whose TLS configurations can ensure that their ServerHello messages are small. A reasonable @@ -157,7 +157,8 @@ none ## tls.socket:hold() -Throttle data reception by placing a request to block the TCP receive function. This request is not effective immediately, Espressif recommends to call it while reserving 5*1460 bytes of memory. +Throttle data reception by placing a request to block the TCP receive function. +This request is not effective immediately, Espressif recommends to call it while reserving 5*1460 bytes of memory. #### Syntax `hold()` @@ -220,7 +221,10 @@ Sends data to remote peer. #### Note -Multiple consecutive `send()` calls aren't guaranteed to work (and often don't) as network requests are treated as separate tasks by the SDK. Instead, subscribe to the "sent" event on the socket and send additional data (or close) in that callback. See [#730](https://github.com/nodemcu/nodemcu-firmware/issues/730#issuecomment-154241161) for details. +Multiple consecutive `send()` calls aren't guaranteed to work (and often don't) as +network requests are treated as separate tasks by the SDK. +Instead, subscribe to the "sent" event on the socket and send additional data (or close) in that callback. +See [#730](https://github.com/nodemcu/nodemcu-firmware/issues/730#issuecomment-154241161) for details. #### See also [`tls.socket:on()`](#tlssocketon) @@ -252,16 +256,16 @@ none ## tls.cert.verify() -Controls the vertificate verification process when the Nodemcu makes a secure connection. +Controls the certificate verification process when the NodeMCU makes a secure connection. #### Syntax `tls.cert.verify(enable)` -`tls.cert.verify(pemdata)` +`tls.cert.verify(pemdata[, pemdata])` #### Parameters - `enable` A boolean which indicates whether verification should be enabled or not. The default at boot is `false`. -- `pemdata` A string containing the CA certificate to use for verification. +- `pemdata` A string containing the CA certificate to use for verification. There can be several of these. #### Returns `true` if it worked. @@ -318,9 +322,65 @@ at `server-ca.crt` in the root of the nodemcu-firmware build tree. The build scr firmware image. The alternative approach is easier for development, and that is to supply the PEM data as a string value to `tls.cert.verify`. This -will store the certificate into the flash chip and turn on verification for that certificate. Subsequent boots of the nodemcu can then +will store the certificate into the flash chip and turn on verification for that certificate. Subsequent boots of the ESP can then use `tls.cert.verify(true)` and use the stored certificate. +## tls.cert.auth() + +Controls the client key and certificate used when the ESP creates a TLS connection (for example, +through `tls.createConnection` or `https` or `MQTT` connections with `secure = true`). + +#### Syntax +`tls.cert.auth(enable)` + +`tls.cert.auth(pemdata[, pemdata])` + +#### Parameters +- `enable` A boolean, specifying whether subsequent TLS connections will present a client certificate. The default at boot is `false`. +- `pemdata` Two strings, the first containing the PEM-encoded client's certificate and the second containing the PEM-encoded client's private key. + +#### Returns +`true` if it worked. + +Can throw a number of errors if invalid data is supplied. + +#### Example +Open an MQTT client. +``` +tls.cert.auth(true) +tls.cert.verify(true) + +m = mqtt.Client('basicPubSub', 1500, "admin", "admin", 1) +``` +For further discussion see https://github.com/nodemcu/nodemcu-firmware/issues/2576 + +Load a certificate into the flash chip. + +``` +tls.cert.auth([[ +-----BEGIN CERTIFICATE----- +CLIENT CERTIFICATE String (PEM file) +-----END CERTIFICATE----- +]] +, +[[ +-----BEGIN RSA PRIVATE KEY----- +CLIENT PRIVATE KEY String (PEM file) +-----END RSA PRIVATE KEY----- +]]) +``` + +#### Notes +The certificate needed for proofing is stored in the flash chip. The `tls.cert.auth` call with `true` +enables proofing against the value stored in the flash. + +The certificate can not be defined at firmware build time but it can be loaded into the flash chip at initial boot of the firmware. +It can be supplied by passing the PEM data as a string value to `tls.cert.auth`. This +will store the certificate into the flash chip and turn on proofing with that certificate. +Subsequent boots of the ESP can then use `tls.cert.auth(true)` and use the stored certificate. + + + # tls.setDebug function mbedTLS can be compiled with debug support. If so, the tls.setDebug From 9fb8a2f2c743cbe2badcf5f544f5fb44eecbe844 Mon Sep 17 00:00:00 2001 From: sergio Date: Sun, 9 Feb 2020 18:58:58 +0300 Subject: [PATCH 30/59] Add flag to disable start-up banner (#3026) --- app/include/user_config.h | 20 ++++++++++++++++++++ app/lua/lua.c | 2 ++ 2 files changed, 22 insertions(+) diff --git a/app/include/user_config.h b/app/include/user_config.h index dbb3447e4e..eb68edd5e1 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -22,6 +22,26 @@ //#define BIT_RATE_AUTOBAUD +// At start-up firmware details like: +// +// NodeMCU 3.0.1.0 +// branch: +// commit: +// release: +// release DTS: +// SSL: false +// build type: integer +// LFS: 0x0 +// modules: file,gpio,net,node,rtctime,sntp,tmr,uart,wifi +// build 2020-01-27 17:39 powered by Lua 5.1.4 on SDK 3.0.2(824dc80) +// +// will be printed to serial console. While it's mandatory for bug reports +// and good for development, it may be unwanted for non-interactive serial +// devices. + +//#define DISABLE_STARTUP_BANNER + + // Three separate build variants are now supported. The main difference is in the // processing of numeric data types. If LUA_NUMBER_INTEGRAL is defined, then // all numeric calculations are done in integer, with divide being an integer diff --git a/app/lua/lua.c b/app/lua/lua.c index 80afc690b2..bf01c625fa 100644 --- a/app/lua/lua.c +++ b/app/lua/lua.c @@ -245,7 +245,9 @@ static int pmain (lua_State *L) { input_setup(LUA_MAXINPUT, get_prompt(L, 1)); lua_input_string(" \n", 2); /* queue CR to issue first prompt */ +#if !defined(DISABLE_STARTUP_BANNER) print_version(L); +#endif /* and last of all, kick off application initialisation */ if (init[0] == '@') From df839084775b10d9f0f7e1ab551d4b8cba7a6d45 Mon Sep 17 00:00:00 2001 From: Gregor Hartmann Date: Tue, 18 Feb 2020 12:41:31 +0100 Subject: [PATCH 31/59] Documentation fixes for pipe (#3041) --- docs/modules/pipe.md | 20 ++++++++++---------- mkdocs.yml | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/modules/pipe.md b/docs/modules/pipe.md index 439276007a..1be4fa4fe4 100644 --- a/docs/modules/pipe.md +++ b/docs/modules/pipe.md @@ -3,7 +3,7 @@ | :----- | :-------------------- | :---------- | :------ | | 2019-07-18 | [Terry Ellison](https://github.com/TerryE) | [Terry Ellison](https://github.com/TerryE) | [pipe.c](../../app/modules/pipe.c)| -The pipe module provides RAM-efficient a means of passing character stream of records from one Lua +The pipe module provides a RAM-efficient means of passing character stream of records from one Lua task to another. ## pipe.create() @@ -14,7 +14,7 @@ Create a pipe. `pobj = pipe.create([CB_function],[task_priority])` #### Parameters -- `CB_function` optional reader callback which is called through the `ǹode.task.post()` when the pipe is written to. If the CB returns a boolean, then the reposting action is forced: it is reposted if true and not if false. If the return is nil or omitted then the deault is to repost if a pipe write has occured since the last call. +- `CB_function` optional reader callback which is called through the `node.task.post()` when the pipe is written to. If the CB returns a boolean, then the reposting action is forced: it is reposted if true and not if false. If the return is nil or omitted then the deault is to repost if a pipe write has occured since the last call. - `task_priority` See `ǹode.task.post()` #### Returns @@ -24,7 +24,7 @@ A pipe resource. Read a record from a pipe object. -Note that the recommended method of reading from a pipe is to user a reader function as described below. +Note that the recommended method of reading from a pipe is to use a reader function as described below. #### Syntax `pobj:read([size/end_char])` @@ -32,7 +32,7 @@ Note that the recommended method of reading from a pipe is to user a reader func #### Parameters - `size/end_char` - If numeric then a string of `size` length will be returned from the pipe. - - If a string then this is a single character delimiter, followed by an optional "+" flag. The delimiter is used as an end-of-record to split the character stream into separate records. If the flag "+" is specified then the delimiter is also returned at the end of the record, otherwise it is discarded. + - If a string then this is a single character delimiter, followed by an optional "+" flag. The delimiter is used as an end-of-record to split the character stream into separate records. If the flag "+" is specified then the delimiter is also returned at the end of the record, otherwise it is discarded. - If omitted, then this defaults to `"\n+"` Note that if the last record in the pipe is missing a delimiter or is too short, then it is still returned, emptying the pipe. @@ -51,13 +51,13 @@ line = pobj:read(50) Returns a Lua **iterator** function for a pipe object. This is as described in the [Lua Language: For Statement](http://www.lua.org/manual/5.1/manual.html#2.4.5). \(Note that the `state` and `object` variables mentioned in 2.5.4 are optional and default to `nil`, so this -conforms to to the`for` iterator syntax and works in a for because it maintains the state and `pobj` +conforms to the`for` iterator syntax and works in a for because it maintains the state and `pobj` internally as upvalues. An emptied pipe takes up minimal RAM resources (an empty Lua array), and just like any other array -this is reclaimed if all variables referencing it go out of scope or are over-written). Note +this is reclaimed if all variables referencing it go out of scope or are over-written. Note that any reader iterators that you have created also refer to the pipe as an upval, so you will -need to descard these to desope the pipe array. +need to discard these to descope the pipe array. #### Syntax `myFunc = pobj:reader([size/end_char])` @@ -98,10 +98,10 @@ end ## pobj:unread() -Write a string to a head of pipe object. This can be used to back-out a previous read. +Write a string to the head of a pipe object. This can be used to back-out a previous read. #### Syntax -`pobj:write(s)` +`pobj:unread(s)` #### Parameters `s` Any input string. Note that with all Lua strings, these may contain all character values including "\0". @@ -113,7 +113,7 @@ Nothing ```Lua a=p:read() -p:unread() -- restores pipe to state before the read +p:unread(a) -- restores pipe to state before the read ``` ## pobj:write() diff --git a/mkdocs.yml b/mkdocs.yml index 16c1685950..6e07270242 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -39,6 +39,7 @@ pages: - Lua Flash Store (LFS): 'lfs.md' - Lua Modules: - 'bh1750': 'lua-modules/bh1750.md' + - 'cohelper': 'lua-modules/cohelper.md' - 'ds18b20': 'lua-modules/ds18b20.md' - 'ds3231': 'lua-modules/ds3231.md' - 'fifo' : 'lua-modules/fifo.md' @@ -88,6 +89,7 @@ pages: - 'ow (1-Wire)': 'modules/ow.md' - 'pcm' : 'modules/pcm.md' - 'perf': 'modules/perf.md' + - 'pipe': 'modules/pipe.md' - 'pwm' : 'modules/pwm.md' - 'pwm2' : 'modules/pwm2.md' - 'rc' : 'modules/rc.md' From ec8622fd87e4f005bccce958ddc36d02221b8611 Mon Sep 17 00:00:00 2001 From: galjonsfigur <44552519+galjonsfigur@users.noreply.github.com> Date: Tue, 18 Feb 2020 12:42:44 +0100 Subject: [PATCH 32/59] Fix timing of softuart module RX (#3029) --- app/modules/softuart.c | 73 +++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/app/modules/softuart.c b/app/modules/softuart.c index 02eaa9b6e7..442700f5d2 100644 --- a/app/modules/softuart.c +++ b/app/modules/softuart.c @@ -13,9 +13,12 @@ #define SOFTUART_MAX_RX_BUFF 128 #define SOFTUART_GPIO_COUNT 13 +//TODO: Overflow flag as callback function + docs typedef struct { char receive_buffer[SOFTUART_MAX_RX_BUFF]; - uint8_t length; + uint8_t buffer_first; + uint8_t buffer_last; + uint8_t bytes_count; uint8_t buffer_overflow; } softuart_buffer_t; @@ -108,26 +111,36 @@ uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status) start_time += s->bit_time; } - // Wait for stop bit - // TODO: Add config for stop bits and parity bits - while ((uint32_t)(asm_ccount() - start_time) < s->bit_time); - // Store byte in buffer // If buffer full, set the overflow flag and return - uint8 next = s->buffer.length + 1 % SOFTUART_MAX_RX_BUFF; - if (next != 0) { - s->buffer.receive_buffer[s->buffer.length] = byte; // save new byte - s->buffer.length = next; - // Run callback when buffer is filled with enough data or last char is the triggering one - if (((s->need_len != 0) && (s->buffer.length >= s->need_len)) || \ - ((s->need_len == 0) && ((char)byte == s->end_char))) { + if (s->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) { + s->buffer.buffer_overflow = 1; + } else if (s->buffer.bytes_count < SOFTUART_MAX_RX_BUFF) { + s->buffer.receive_buffer[s->buffer.buffer_last] = byte; + s->buffer.buffer_last++; + s->buffer.bytes_count++; + + // Check for callback conditions + if (((s->need_len != 0) && (s->buffer.bytes_count >= s->need_len)) || \ + ((s->need_len == 0) && ((char)byte == s->end_char))) { + // Send the pointer to task handler s->armed = 0; - task_post_low(uart_recieve_task, (task_param_t)s); // Send the pointer to task handler - } - } else { - //TODO: use this information somehow? + task_post_low(uart_recieve_task, (task_param_t)s); + } + } + // Check for overflow after appending new byte + if (s->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) { s->buffer.buffer_overflow = 1; } + // Roll over buffer index if necessary + if (s->buffer.buffer_last == SOFTUART_MAX_RX_BUFF) { + s->buffer.buffer_last = 0; + } + + // Wait for stop bit + // TODO: Add config for stop bits and parity bits + while ((uint32_t)(asm_ccount() - start_time) < s->bit_time); + } } // re-enable all interrupts @@ -163,8 +176,8 @@ static void softuart_init(softuart_t *s) { NODE_DBG("SoftUART initialize gpio\n"); + // Init tx pin if (s->pin_tx != 0xFF){ - // Init tx pin platform_gpio_mode(s->pin_tx, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP); platform_gpio_write(s->pin_tx, PLATFORM_GPIO_HIGH); } @@ -235,7 +248,14 @@ static int softuart_setup(lua_State *L) suart->softuart->pin_tx = tx_gpio_id; suart->softuart->need_len = RX_BUFF_SIZE; suart->softuart->armed = 0; - //set bit time + + // Set buffer + suart->softuart->buffer.buffer_first = 0; + suart->softuart->buffer.buffer_last = 0; + suart->softuart->buffer.bytes_count = 0; + suart->softuart->buffer.buffer_overflow = 0; + + // Set bit time suart->softuart->bit_time = system_get_cpu_freq() * 1000000 / baudrate; // Set metatable @@ -251,12 +271,21 @@ static void softuart_rx_callback(task_param_t arg) softuart_t *softuart = (softuart_t*)arg; //Receive pointer from ISR lua_State *L = lua_getstate(); lua_rawgeti(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[softuart->pin_rx]); + // Clear overflow flag if needed + if(softuart->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) { + softuart->buffer.buffer_overflow = 0; + } // Copy volatile data to static buffer - for (int i = 0; i < softuart->buffer.length; i++) { - softuart_rx_buffer[i] = softuart->buffer.receive_buffer[i]; + uint8_t buffer_lenght = softuart->buffer.bytes_count; + for (int i = 0; i < buffer_lenght; i++) { + softuart_rx_buffer[i] = softuart->buffer.receive_buffer[softuart->buffer.buffer_first]; + softuart->buffer.buffer_first++; + softuart->buffer.bytes_count--; + if (softuart->buffer.buffer_first == SOFTUART_MAX_RX_BUFF) { + softuart->buffer.buffer_first = 0; + } } - lua_pushlstring(L, softuart_rx_buffer, softuart->buffer.length); - softuart->buffer.length = 0; + lua_pushlstring(L, softuart_rx_buffer, buffer_lenght); softuart->armed = 1; lua_call(L, 1, 0); } From 1851a734294381ed493993b7247e1f333b890bc4 Mon Sep 17 00:00:00 2001 From: Gregor Hartmann Date: Fri, 21 Feb 2020 13:20:39 +0100 Subject: [PATCH 33/59] Update sqlite3.md (#3042) --- docs/modules/sqlite3.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/modules/sqlite3.md b/docs/modules/sqlite3.md index a98b3b7f40..1779e4a08c 100644 --- a/docs/modules/sqlite3.md +++ b/docs/modules/sqlite3.md @@ -3,6 +3,17 @@ | :----- | :-------------------- | :---------- | :------ | | 2017-06-20 | [Luiz Felipe Silva](https://github.com/luizfeliperj) | [Luiz Felipe Silva](https://github.com/luizfeliperj) | [sqlite3.c](../../app/modules/sqlite3.c)| +!!! attention + ###This module is currently not available. + + Even if you enable it in configuration it will not be available. + + In brief this is due to a lack of proof of usability. The memory constraints on the ESP8266 are just too tight. + + The module is not removed yet as it might be revived to run on the ESP32 after the two branches for ESP8266 and ESP32 have been unified. + + Please see [#2913](https://github.com/nodemcu/nodemcu-firmware/issues/2913) for more information. + This module is based on [LuaSQLite3](http://lua.sqlite.org/index.cgi/index) module developed by Tiago Dionizio and Doug Currie with contributions from Thomas Lauer, Michael Roth, and Wolfgang Oertl. This module depens on [SQLite3](http://www.sqlite.org/) library developed by Dwayne Richard Hipp. From 31d47149af67342e37a7f469a4a2fd47f451019f Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Sun, 23 Feb 2020 09:44:40 -0800 Subject: [PATCH 34/59] net: rename net.if.info to net.ifinfo (#3033) Reserved words are always reserved in Lua, so let's not have people typing net["if"]... --- app/modules/net.c | 10 ++----- docs/modules/net.md | 72 ++++++++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/app/modules/net.c b/app/modules/net.c index d8678ec9c8..4565f53d35 100644 --- a/app/modules/net.c +++ b/app/modules/net.c @@ -1008,12 +1008,12 @@ field_from_ipaddr(lua_State *L, const char * field_name, ip_addr_t* addr) { lua_setfield(L, -2, field_name); } -static int net_if_info( lua_State* L ) { +static int net_ifinfo( lua_State* L ) { int ifidx = luaL_optint(L, 1, 0); struct netif * nif = eagle_lwip_getif(ifidx); if (nif == NULL) { - return luaL_error( L, "unknown network interface index %d", ifidx); + return 0; } lua_createtable(L, 0, @@ -1088,18 +1088,14 @@ LROT_BEGIN(net_dns) LROT_FUNCENTRY( resolve, net_dns_static ) LROT_END( net_dns, net_dns, 0 ) -LROT_BEGIN(net_if) - LROT_FUNCENTRY( info, net_if_info ) -LROT_END(net_if, net_if, 0) - LROT_BEGIN(net) LROT_FUNCENTRY( createServer, net_createServer ) LROT_FUNCENTRY( createConnection, net_createConnection ) LROT_FUNCENTRY( createUDPSocket, net_createUDPSocket ) + LROT_FUNCENTRY( ifinfo, net_ifinfo ) LROT_FUNCENTRY( multicastJoin, net_multicastJoin ) LROT_FUNCENTRY( multicastLeave, net_multicastLeave ) LROT_TABENTRY( dns, net_dns ) - LROT_TABENTRY( if, net_if ) #ifdef TLS_MODULE_PRESENT LROT_TABENTRY( cert, tls_cert ) #endif diff --git a/docs/modules/net.md b/docs/modules/net.md index 7f6b70e4ff..d15cec4276 100644 --- a/docs/modules/net.md +++ b/docs/modules/net.md @@ -83,6 +83,41 @@ none #### See also [`net.createConnection()`](#netcreateconnection) +## net.ifinfo() + +Return information about a network interface, specified by index. + +#### Syntax +`net.ifinfo(if_index)` + +#### Parameters +- `if_index` the interface index; on ESP8266, `0` is the wifi client (STA) and `1` + is the wifi AP. + +#### Returns +`nil` if the given `if_index` does not correspond to an interface. Otherwise, +a table containing ... + +* `ip`, `netmask`, and `gateway` configured for this interface, as dotted quad strings + or `nil` if none is set. + +* if DHCP was used to configure the interface, then `dhcp` will be a table containing... + + * `server_ip` -- the DHCP server itself, as a dotted quad + + * `client_ip` -- the IP address suggested for the client; likely, this equals `ip` + above, unless the configuration has been overridden. + + * `ntp_server` -- the NTP server suggested by the DHCP server. + +DNS servers are not tracked per-interface in LwIP and, as such, are not +reported here; use [`net.dns:getdnsserver()`](#netdnsgetdnsserver). + +#### Example + +`print(net.ifinfo(0).dhcp.ntp_server)` will show the NTP server suggested by +the DHCP server. + ## net.multicastJoin() Join multicast group. @@ -618,43 +653,6 @@ Sets the IP of the DNS server used to resolve hostnames. Default: resolver1.open #### See also [`net.dns:getdnsserver()`](#netdnsgetdnsserver) -# net.if Module - -## net.if.info() - -Return information about a network interface, specified by index. - -#### Syntax -`net.if.info(if_index)` - -#### Parameters -- `if_index` the interface index; on ESP8266, `0` is the wifi client (STA) and `1` - is the wifi AP. - -#### Returns -`nil` if the given `if_index` does not correspond to an interface. Otherwise, -a table containing ... - -* `ip`, `netmask`, and `gateway` configured for this interface, as dotted quad strings - or `nil` if none is set. - -* if DHCP was used to configure the interface, then `dhcp` will be a table containing... - - * `server_ip` -- the DHCP server itself, as a dotted quad - - * `client_ip` -- the IP address suggested for the client; likely, this equals `ip` - above, unless the configuration has been overridden. - - * `ntp_server` -- the NTP server suggested by the DHCP server. - -DNS servers are not tracked per-interface in LwIP and, as such, are not -reported here; use [`net.dns:getdnsserver()`](#netdnsgetdnsserver). - -#### Example - -`print(net.if.info(0).dhcp.ntp_server)` will show the NTP server suggested by -the DHCP server. - # net.cert Module This part gone to the [TLS](tls.md) module, link kept for backward compatibility. From 1577988d14c55eb59147f64d0d4f2fcf746c0f27 Mon Sep 17 00:00:00 2001 From: Edvinas Date: Sun, 23 Feb 2020 19:46:35 +0200 Subject: [PATCH 35/59] Bugfix conn metatable method call (#3012) Here `conn` is net.socket instance, so it should be called as one. Otherwise request is very likely to end up with crash and PANIC. nwf edited in light of bcb669a4a0a49e857186093eb79b6f27a3158ad7 --- lua_modules/http/httpserver.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua_modules/http/httpserver.lua b/lua_modules/http/httpserver.lua index bce4dfb899..7a5f07be8d 100644 --- a/lua_modules/http/httpserver.lua +++ b/lua_modules/http/httpserver.lua @@ -89,7 +89,7 @@ do local buf = "" local method, url local ondisconnect = function(connection) - connection.on("sent", nil) + connection:on("sent", nil) collectgarbage("collect") end -- header parser From c116d9d25f5d15e2b1d0d52ff4c8ebdfd18f75c3 Mon Sep 17 00:00:00 2001 From: Alexandru Antochi Date: Fri, 6 Mar 2020 21:24:25 +0000 Subject: [PATCH 36/59] Add Lua module for Gossip protocol (#3013) --- docs/lua-modules/gossip.md | 191 +++++++++++++++++++ lua_examples/gossip_example.lua | 73 ++++++++ lua_modules/gossip/README.md | 3 + lua_modules/gossip/gossip.lua | 274 +++++++++++++++++++++++++++ lua_modules/gossip/gossip_tests.lua | 277 ++++++++++++++++++++++++++++ mkdocs.yml | 1 + 6 files changed, 819 insertions(+) create mode 100644 docs/lua-modules/gossip.md create mode 100644 lua_examples/gossip_example.lua create mode 100644 lua_modules/gossip/README.md create mode 100644 lua_modules/gossip/gossip.lua create mode 100644 lua_modules/gossip/gossip_tests.lua diff --git a/docs/lua-modules/gossip.md b/docs/lua-modules/gossip.md new file mode 100644 index 0000000000..e49e9ea1a3 --- /dev/null +++ b/docs/lua-modules/gossip.md @@ -0,0 +1,191 @@ +# ESPGossip + +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2020-01-20 | [alexandruantochi](https://github.com/alexandruantochi) | [alexandruantochi](https://github.com/alexandruantochi) | [gossip.lua](../../lua_modules/gossip/gossip.lua) | + + +This module is based on the gossip protocol and it can be used to disseminate information through the network to other nodes. The time it takes for the information to reach all nodes is logN. For every round number n, 2^n nodes will receive the information. + +### Require +```lua +gossip = require('gossip') +``` + +### Release +```lua +gossip.inboundSocket:close() +gossip = nil +``` + +## Usage +```lua +config = { + seedList = { '192.168.0.1', '192.168.0.15' }, + debug = true, + debugOutput = print +} +gossip = require ("gossip") +gossip.setConfig(config) +gossip.start() +``` + +## Strategy + +Each controller will randomly pick an IP from it's seed list. It will send a `SYN` request to that IP and set receiving node's `state` to an intermediary state between `Up` and `Suspect`. The node that receives the `SYN` request will compute a diff on the received networkState vs own networkState. It will then send that diff as an `ACK` request. If there is no data to send, it will only send an `ACK`. When the `ACK` is received, the sender's state will revert to `Up` and the receiving node will update it's own networkState using the diff (based on the `ACK` reply). + +Gossip will establish if the information received from another node has fresher data by first comparing the `revision`, then the `heartbeat` and lastly the `state`. States that are closer to `DOWN` have priority as an offline node does not update it's heartbeat. + +Any other parameter can be sent along with the mandatory `revision`, `heartbeat` and `state` thus allowing the user to spread information around the network. Every time a node receives 'fresh' data, the `gossip.updateCallback` will be called with that data as the first parameter. + +Currently there is no implemented deletion for nodes that are down except for the fact that their status is signaled as `REMOVE`. + +## Example use-case + +There are multiple modules on the network that measure temperature. We want to know the maximum and minimum temperature at a given time and have every node display it. + +The brute force solution would be to query each node from a single point and save the `min` and `max` values, then go back to each node and present them with the computed `min` and `max`. This requires n*2 rounds, where n is the number of nodes. It also opens the algorithm to a single point of failure (the node that is in charge of gathering the data). + +Using gossip, one can have the node send it's latest value through `SYN` or `pushGossip()` and use the `callbackUpdate` function to compare the values from other nodes to it's own. Based on that, the node will display the values it knows about by gossiping with others. The data will be transmitted in ~log(n) rounds, where n is the number of nodes. + +## Terms + +`revision` : generation of the node; if a node restarts, the revision will be increased by one. The revision data is stored as a file to provide persistency + +`heartBeat` : the node uptime in seconds (`tmr.time()`). This is used to help the other nodes figure out if the information about that particular node is newer. + +`networkState` : the list with the state of the network composed of the `ip` as a key and `revision`, `heartBeat` and `state` as values packed in a table. + +`state` : all nodes start with a state set to `UP` and when a node sends a `SYN` request, it will mark the destination node in an intermediary state until it receives an `ACK` or a `SYN` from it. If a node receives any message, it will mark that senders IP as `UP` as this provides proof that the node is online. + + +## setConfig() + +#### Syntax +```lua +gossip.setConfig(config) +``` + +Sets the configuration for gossip. The available options are: + +`seedList` : the list of seeds gossip will start with; this will be updated as new nodes are discovered. Note that it's enough for all nodes to start with the same IP in the seedList, as once they have one seed in common, the data will propagate + +`roundInterval`: interval in milliseconds at which gossip will pick a random node from the seed list and send a `SYN` request + +`comPort` : port for the listening UDP socket + +`debug` : flag that will provide debugging messages + +`debugOutput` : if debug is set to `true`, then this method will be used as a callback with the debug message as the first parameter + +```lua +config = { + seedList = {'192.168.0.54','192.168.0.55'}, + roundInterval = 10000, + comPort = 5000, + debug = true, + debugOutput = function(message) print('Gossip says: '..message); end +} +``` + +If any of them is not provided, the values will default: + +`seedList` : nil + +`roundInterval`: 10000 (10 seconds) + +`comPort` : 5000 + +`debug` : false + +`debugOutput` : print + +## start() + +#### Syntax +```lua +gossip.start() +``` + +Starts gossip, sets the `started` flag to true and initiates the `revision`. The revision (generation) main purpose is like a persistent heartbeat, as the heartbeat (measured by uptime in seconds) will obviously revert to 0. + +## callbackFunction + +#### Syntax +```lua +gossip.callbackFunction = function(data) + processData(data) +end + +-- stop the callback +gossip.callbackFunction = nil +``` + +If declared, this function will get called every time there is a `SYN` with new data. + +## pushGossip() + +#### Syntax + +```lua +gossip.pushGossip(data, [ip]) + +-- remove data +gossip.pushGossip(nil, [ip]) +``` + +Send a `SYN` request outside of the normal gossip round. The IP is optional and if none given, it will pick a random node. + +``` +!!! note +. By calling `pushGossip(nil)` you effectively remove the `data` table from the node's network state and notify other nodes of this. +``` +## setRevManually() + +#### Syntax + +```lua +gossip.setRevFileValue(number) +``` + +The only scenario when rev should be set manually is when a new node is added to the network and has the same IP. Having a smaller revision than the previous node with the same IP would make gossip think the data it received is old, thus ignoring it. + +``` +!!! note + +The revision file value will only be read when gossip starts and it will be incremented by one. +``` + +## getNetworkState() + +#### Syntax + +```lua +networkState = gossip.getNetworkState() +print(networkState) +``` + +The network state can be directly accessed as a Lua table : `gossip.networkState` or it can be received as a JSON with this method. + +#### Returns + +JSON formatted string regarding the network state. + +Example: + +```JSON +{ + "192.168.0.53": { + "state": 3, + "revision": 25, + "heartbeat": 2500, + "extra" : "this is some extra info from node 53" + }, + "192.168.0.75": { + "state": 0, + "revision": 4, + "heartbeat": 6500 + } +} +``` + diff --git a/lua_examples/gossip_example.lua b/lua_examples/gossip_example.lua new file mode 100644 index 0000000000..3e9d975e50 --- /dev/null +++ b/lua_examples/gossip_example.lua @@ -0,0 +1,73 @@ +-- need a wifi connection +-- enter your wifi credentials +local credentials = {SSID = "SSID", PASS = "PASS"}; + +-- push a message onto the network +-- this can also be done by changing gossip.networkState[gossip.ip].data = {temperature = 78}; +local function sendAlarmingData() + Gossip.pushGossip({temperature = 78}); + print('Pushed alarming data'); +end + +local function removeAlarmingData() + Gossip.pushGossip(nil); + print('Removed alarming data from the network.'); +end + +-- callback function for when gossip receives an update +local function treatAlarmingData(updateData) + for k in pairs(updateData) do + if updateData[k].data then + if updateData[k].data.temperature and updateData[k].data.temperature > 30 then + print('Warning, the temp is above 30 degrees at ' .. k); + end + end + end +end + +local function Startup() + -- initialize all nodes with the seed except for the seed itself + -- eventually they will all know about each other + + -- enter at least one ip that will be a start seed + local startingSeed = '192.168.0.73'; + + -- luacheck: push allow defined + Gossip = require('gossip'); + -- luacheck: pop + local config = {debug = true, seedList = {}}; + + if wifi.sta.getip() ~= startingSeed then + table.insert(config.seedList, startingSeed); + end + + Gossip.setConfig(config); + + -- add the update callback + Gossip.updateCallback = treatAlarmingData; + + -- start gossiping + Gossip.start(); + + -- send some alarming data timer + if wifi.sta.getip() == startingSeed then + tmr.create():alarm(50000, tmr.ALARM_SINGLE, sendAlarmingData); + tmr.create():alarm(50000*3, tmr.ALARM_SINGLE, removeAlarmingData); + end +end + +local function startExample() + wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, + function() print('Diconnected') end); + print("Connecting to WiFi access point..."); + + if wifi.sta.getip() == nil then + wifi.setmode(wifi.STATION); + wifi.sta.config({ssid = credentials.SSID, pwd = credentials.PASS}); + end + print('Ip: ' .. wifi.sta.getip() .. '. Starting in 5s ..'); + tmr.create():alarm(5000, tmr.ALARM_SINGLE, Startup); +end + +startExample(); + diff --git a/lua_modules/gossip/README.md b/lua_modules/gossip/README.md new file mode 100644 index 0000000000..fc8e7fe8e7 --- /dev/null +++ b/lua_modules/gossip/README.md @@ -0,0 +1,3 @@ +# Gossip module + +Documentation for this Lua module is available in the [gossip.md](../../docs/lua-modules/gossip.md) file and in the [Official NodeMCU Documentation](https://nodemcu.readthedocs.io/) in `Lua Modules` section. diff --git a/lua_modules/gossip/gossip.lua b/lua_modules/gossip/gossip.lua new file mode 100644 index 0000000000..f4709d9aab --- /dev/null +++ b/lua_modules/gossip/gossip.lua @@ -0,0 +1,274 @@ +-- Gossip protocol implementation +-- https://github.com/alexandruantochi/ +local gossip = {}; +local constants = {}; +local utils = {}; +local network = {}; +local state = {}; + +-- Utils + +utils.contains = function(list, element) + for k in pairs(list) do if list[k] == element then return true; end end + return false; +end + +utils.debug = function(message) + if gossip.config.debug then + if gossip.config.debugOutput then + gossip.config.debugOutput(message); + else + print(message); + end + end +end + +utils.getNetworkState = function() return sjson.encode(gossip.networkState); end + +utils.isNodeDataValid = function(nodeData) + return (nodeData and nodeData.revision and nodeData.heartbeat and + nodeData.state) ~= nil; +end + +utils.compare = function(first, second) + if first > second then return -1; end + if first < second then return 1; end + return 0; +end + +utils.compareNodeData = function(first, second) + local firstDataValid = utils.isNodeDataValid(first); + local secondDataValid = utils.isNodeDataValid(second); + if firstDataValid and secondDataValid then + for index in ipairs(constants.comparisonFields) do + local comparisonField = constants.comparisonFields[index]; + local comparisonResult = utils.compare(first[comparisonField], + second[comparisonField]); + if comparisonResult ~= 0 then return comparisonResult; end + end + elseif firstDataValid then + return -1; + elseif secondDataValid then + return 1; + end + return 0; +end + +-- computes data1 - data2 based on node compare function +utils.getMinus = function(data1, data2) + local diff = {}; + for ip, nodeData1 in pairs(data1) do + if utils.compareNodeData(nodeData1, data2[ip]) == -1 then + diff[ip] = nodeData1; + end + end + return diff; +end + +utils.setConfig = function(userConfig) + for k, v in pairs(userConfig) do + if gossip.config[k] ~= nil and type(gossip.config[k]) == type(v) then + gossip.config[k] = v; + end + end +end + +-- State + +state.setRev = function() + local revision = 0; + if file.exists(constants.revFileName) then + revision = file.getcontents(constants.revFileName) + 1; + end + file.putcontents(constants.revFileName, revision); + utils.debug('Revision set to ' .. revision); + return revision; +end + +state.setRevFileValue = function(revNumber) + if revNumber then + file.putcontents(constants.revFileName, revNumber); + utils.debug('Revision overriden to ' .. revNumber); + else + utils.debug('Please provide a revision number.'); + end +end + +state.start = function() + if gossip.started then + utils.debug('Gossip already started.'); + return; + end + gossip.ip = wifi.sta.getip(); + if not gossip.ip then + utils.debug('Node not connected to network. Gossip will not start.'); + return; + end + + gossip.networkState[gossip.ip] = {}; + local localState = gossip.networkState[gossip.ip]; + localState.revision = state.setRev(); + localState.heartbeat = tmr.time(); + localState.state = constants.nodeState.UP; + + gossip.inboundSocket = net.createUDPSocket(); + gossip.inboundSocket:listen(gossip.config.comPort); + gossip.inboundSocket:on('receive', network.receiveData); + + gossip.started = true; + + gossip.timer = tmr.create(); + gossip.timer:register(gossip.config.roundInterval, tmr.ALARM_AUTO, + network.sendSyn); + gossip.timer:start(); + + utils.debug('Gossip started.'); +end + +state.tickNodeState = function(ip) + if gossip.networkState[ip] then + local nodeState = gossip.networkState[ip].state; + if nodeState < constants.nodeState.REMOVE then + nodeState = nodeState + constants.nodeState.TICK; + gossip.networkState[ip].state = nodeState; + end + end +end + +-- Network + +network.pushGossip = function(data, ip) + gossip.networkState[gossip.ip].data = data; + network.sendSyn(nil, ip); +end + +network.updateNetworkState = function(updateData) + if gossip.updateCallback then gossip.updateCallback(updateData); end + for ip, data in pairs(updateData) do + if not utils.contains(gossip.config.seedList, ip) then + table.insert(gossip.config.seedList, ip); + end + gossip.networkState[ip] = data; + end +end + +-- luacheck: push no unused +network.sendSyn = function(t, ip) + local destination = ip or network.pickRandomNode(); + gossip.networkState[gossip.ip].heartbeat = tmr.time(); + if destination then + network.sendData(destination, gossip.networkState, constants.updateType.SYN); + state.tickNodeState(destination); + end +end +-- luacheck: pop + +network.pickRandomNode = function() + if #gossip.config.seedList > 0 then + local randomListPick = node.random(1, #gossip.config.seedList); + utils.debug('Randomly picked: ' .. gossip.config.seedList[randomListPick]); + return gossip.config.seedList[randomListPick]; + end + utils.debug( + 'Seedlist is empty. Please provide one or wait for node to be contacted.'); + return nil; +end + +network.sendData = function(ip, data, sendType) + local outboundSocket = net.createUDPSocket(); + data.type = sendType; + local dataToSend = sjson.encode(data); + data.type = nil; + outboundSocket:send(gossip.config.comPort, ip, dataToSend); + outboundSocket:close(); +end + +network.receiveSyn = function(ip, synData) + utils.debug('Received SYN from ' .. ip); + local update = utils.getMinus(synData, gossip.networkState); + local diff = utils.getMinus(gossip.networkState, synData); + network.updateNetworkState(update); + network.sendAck(ip, diff); +end + +network.receiveAck = function(ip, ackData) + utils.debug('Received ACK from ' .. ip); + local update = utils.getMinus(ackData, gossip.networkState); + network.updateNetworkState(update); +end + +network.sendAck = function(ip, diff) + local diffIps = ''; + for k in pairs(diff) do diffIps = diffIps .. ' ' .. k; end + utils.debug('Sending ACK to ' .. ip .. ' with ' .. diffIps .. ' updates.'); + network.sendData(ip, diff, constants.updateType.ACK); +end + +-- luacheck: push no unused +network.receiveData = function(socket, data, port, ip) + if gossip.networkState[ip] then + gossip.networkState[ip].state = constants.nodeState.UP; + end + local messageDecoded, updateData = pcall(sjson.decode, data); + if not messageDecoded then + utils.debug('Invalid JSON received from ' .. ip); + return; + end + local updateType = updateData.type; + updateData.type = nil; + if updateType == constants.updateType.SYN then + network.receiveSyn(ip, updateData); + elseif updateType == constants.updateType.ACK then + network.receiveAck(ip, updateData); + else + utils.debug('Invalid data comming from ip ' .. ip .. + '. No valid type specified.'); + end +end +-- luacheck: pop + +-- Constants + +constants.nodeState = {TICK = 1, UP = 0, SUSPECT = 2, DOWN = 3, REMOVE = 4}; + +constants.defaultConfig = { + seedList = {}, + roundInterval = 15000, + comPort = 5000, + debug = false +}; + +constants.comparisonFields = {'revision', 'heartbeat', 'state'}; + +constants.updateType = {ACK = 'ACK', SYN = 'SYN'} + +constants.revFileName = 'gossip/rev.dat'; + +-- Return + +gossip = { + started = false, + config = constants.defaultConfig, + setConfig = utils.setConfig, + start = state.start, + setRevFileValue = state.setRevFileValue, + networkState = {}, + getNetworkState = utils.getNetworkState, + pushGossip = network.pushGossip +}; + +-- return + +if (... == 'test') then + return { + _gossip = gossip, + _constants = constants, + _utils = utils, + _network = network, + _state = state + }; +elseif net and file and tmr and wifi then + return gossip; +else + error('Gossip requires these modules to work: net, file, tmr, wifi'); +end diff --git a/lua_modules/gossip/gossip_tests.lua b/lua_modules/gossip/gossip_tests.lua new file mode 100644 index 0000000000..dec7a719d8 --- /dev/null +++ b/lua_modules/gossip/gossip_tests.lua @@ -0,0 +1,277 @@ +-- Gossip protocol implementation tests +-- https://github.com/alexandruantochi/ +local gossipSubmodules = loadfile('gossip.lua')('test'); + +local gossip = gossipSubmodules._gossip; +local constants = gossipSubmodules._constants; +local utils = gossipSubmodules._utils; +local network = gossipSubmodules._network; +local state = gossipSubmodules._state; + +-- test constants and mocks + +local function dummy() return nil; end + +-- luacheck: push allow defined +tmr = {}; +tmr.time = function() return 200; end +sjson = {}; +sjson.decode = function(data) return data; end +file = {}; +file.exists = dummy +file.putcontents = dummy +-- luacheck: pop + +local Ip_1 = '192.168.0.1'; +local Ip_2 = '192.168.0.2'; + +-- test runner + +local Test = {}; + +local RunTests = function() + local failures = {}; + print('\nRunning tests...\n'); + for testName, test in pairs(Test) do + if type(test) == 'function' then + local result = testName .. ': '; + local passed, res = pcall(test); + if passed then + result = result .. ' Passed.'; + else + result = result .. ' Failed ->'; + result = '>>>' .. result .. res; + table.insert(failures, testName); + end + print(result); + end + end + if (#failures ~= 0) then + print('\n\n'); + print('Failed tests (' .. #failures .. '): \n'); + for k in pairs(failures) do print(failures[k]); end + print('\n'); + end +end + +-- utils + +function Test.utils_contains() + local seedList = {}; + assert(not utils.contains(seedList, Ip_1)); + table.insert(seedList, Ip_1); + assert(utils.contains(seedList, Ip_1)); + table.insert(seedList, Ip_2); + assert(utils.contains(seedList, Ip_1) and utils.contains(seedList, Ip_2)); +end + +function Test.utils_setConfig() + local config = { + seedList = {Ip_1}, + roundInterval = 1500, + comPort = 8000, + junk = 'junk' + }; + gossip.config = constants.defaultConfig; + utils.setConfig(config); + + assert(#gossip.config.seedList == 1, 'Config failed when adding seedList'); + assert(gossip.config.seedList[1] == Ip_1, + 'Config failed to add ip to seedList'); + assert(gossip.config.roundInterval == 1500, + 'Config failed to add round interval.'); + assert(gossip.config.comPort == 8000, 'Config failed to add comPort.'); + assert(gossip.config.debug == false, 'Debug should be false.'); + assert(gossip.config.junk == nil, 'Junk data inserted in config.'); + + gossip.config = constants.defaultConfig; +end + +function Test.utils_compare() + assert(utils.compare(1, 2) == 1); + assert(utils.compare(2, 1) == -1); + assert(utils.compare(0, 0) == 0); +end + +function Test.utils_compareNodeData_on_revision() + local networkData_1 = { + revision = 1, + heartbeat = 500, + state = constants.nodeState.UP + }; + local networkData_2 = { + revision = 2, + heartbeat = 500, + state = constants.nodeState.UP + }; + assert(utils.compareNodeData(networkData_1, networkData_2) == 1); + assert(utils.compareNodeData(networkData_2, networkData_1) == -1); + networkData_1.revision = networkData_2.revision; + assert(utils.compareNodeData(networkData_1, networkData_2) == 0); +end + +function Test.utils_compareNodeData_on_heartbeat() + local networkData_1 = { + revision = 1, + heartbeat = 500, + state = constants.nodeState.UP + }; + local networkData_2 = { + revision = 1, + heartbeat = 600, + state = constants.nodeState.UP + }; + assert(utils.compareNodeData(networkData_1, networkData_2) == 1); + assert(utils.compareNodeData(networkData_2, networkData_1) == -1); + networkData_1.heartbeat = networkData_2.heartbeat; + assert(utils.compareNodeData(networkData_1, networkData_2) == 0); +end + +function Test.utils_compareNodeData_on_state() + local networkData_1 = { + revision = 1, + heartbeat = 500, + state = constants.nodeState.UP + }; + local networkData_2 = { + revision = 1, + heartbeat = 500, + state = constants.nodeState.SUSPECT + }; + assert(utils.compareNodeData(networkData_1, networkData_2) == 1); + assert(utils.compareNodeData(networkData_2, networkData_1) == -1); + networkData_1.state = networkData_2.state; + assert(utils.compareNodeData(networkData_1, networkData_2) == 0); +end + +function Test.utils_compareNodeData_on_bad_data() + local networkData_1 = { + revision = 1, + heartbeat = nil, + state = constants.nodeState.UP + }; + local networkData_2 = { + revision = 1, + heartbeat = 600, + state = constants.nodeState.UP + }; + assert(utils.compareNodeData(networkData_1, networkData_2) == 1); + assert(utils.compareNodeData(networkData_2, networkData_1) == -1); + networkData_2.state = nil; + assert(utils.compareNodeData(networkData_1, networkData_2) == 0); +end + +function Test.utils_getMinus() + local data1 = {}; + local data2 = {}; + + data1[Ip_1] = { + revision = 1, + heartbeat = 500, + state = constants.nodeState.UP + }; + data1[Ip_2] = { + revision = 1, + heartbeat = 400, + state = constants.nodeState.UP + }; + data2[Ip_1] = { + revision = 1, + heartbeat = 400, + state = constants.nodeState.UP + }; + data2[Ip_2] = { + revision = 1, + heartbeat = 400, + state = constants.nodeState.SUSPECT; + }; + + --local diff1 = utils.getMinus(data1, data2); + local diff2 = utils.getMinus(data2, data1); + + --assert(diff1[Ip_1] ~= nil and diff1[Ip_2] == nil); + assert(diff2[Ip_1] == nil and diff2[Ip_2] ~= nil); + +end + +-- state + +function Test.state_setRev() + gossip.ip = Ip_1; + gossip.networkState[Ip_1] = {}; + gossip.networkState[Ip_1].revision = -1; + assert(state.setRev() == 0, 'Revision not initialized to 0.'); +end + +function Test.state_tickNodeState() + local ip_1 = Ip_1; + local ip_2 = Ip_2; + gossip.networkState[ip_1] = {}; + gossip.networkState[ip_2] = {}; + gossip.networkState[ip_1].state = constants.nodeState.UP; + gossip.networkState[ip_2].state = constants.nodeState.DOWN; + state.tickNodeState(ip_1); + state.tickNodeState(ip_2); + assert(gossip.networkState[ip_1].state == constants.nodeState.UP + + constants.nodeState.TICK); + assert(gossip.networkState[ip_2].state == constants.nodeState.REMOVE); + state.tickNodeState(ip_1); + assert(gossip.networkState[ip_1].state == constants.nodeState.SUSPECT); + gossip.networkState = {}; +end + +-- network + +function Test.network_updateNetworkState_no_callback() + local updateData = {} + updateData[Ip_1] = { + revision = 1, + heartbeat = 400, + state = constants.nodeState.UP + }; + updateData[Ip_2] = { + revision = 1, + heartbeat = 700, + state = constants.nodeState.UP + }; + network.updateNetworkState(updateData); + -- send duplicate data + network.updateNetworkState(updateData); + assert(#gossip.config.seedList == 2); + assert(gossip.config.seedList[1] == Ip_1); + assert(gossip.config.seedList[2] == Ip_2); + assert(gossip.networkState[Ip_1] ~= nil and gossip.networkState[Ip_2] ~= nil); + gossip.networkState = {}; + gossip.config = constants.defaultConfig; +end + +function Test.network_updateNetworkState_with_callback() + local callbackTriggered = false; + local function updateCallback() callbackTriggered = true; end + gossip.updateCallback = updateCallback; + Test.network_updateNetworkState_no_callback(); + assert(callbackTriggered); + gossip.updateCallback = nil; +end + +function Test.network_receiveData_when_receive_syn() + local originalReceiveSyn = network.receiveSyn; + local receiveSynCalled = false; + network.receiveSyn = function() receiveSynCalled = true; end + network.receiveData('socket', {type = constants.updateType.SYN}); + network.receiveSyn = originalReceiveSyn; + assert(receiveSynCalled); +end + +function Test.network_receiveData_when_receive_ack() + local originalReceiveAck = network.receiveAck; + local receiveAckCalled = false; + network.receiveAck = function() receiveAckCalled = true; end + network.receiveData('socket', {type = constants.updateType.ACK}); + network.receiveAck = originalReceiveAck; + assert(receiveAckCalled); +end + +-- run tests + +RunTests(); diff --git a/mkdocs.yml b/mkdocs.yml index 6e07270242..64ab69fdea 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,6 +45,7 @@ pages: - 'fifo' : 'lua-modules/fifo.md' - 'fifosock' : 'lua-modules/fifosock.md' - 'ftpserver': 'lua-modules/ftpserver.md' + - 'gossip': 'lua-modules/gossip.md' - 'hdc1000': 'lua-modules/hdc1000.md' - 'httpserver': 'lua-modules/httpserver.md' - 'imap': 'lua-modules/imap.md' From 787ac7ccb90d80789ece31a544e5c8ac41bd9998 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Sat, 14 Mar 2020 22:51:03 +0000 Subject: [PATCH 37/59] WIP: MQTT fixes (#2986) * mqtt: expose "connfail" callback via :on() This makes it just like all the other callbacks in the module and is a revision of behavior called out in https://github.com/nodemcu/nodemcu-firmware/pull/2967 * mqtt: clarify when puback callback fires * mqtt: Don't reference stack buffers from the heap The confusingly-named "mqtt_connection_t" object is just a triple of - a serialized mqtt message pointer and length - a buffer pointer (to which the above can be written) - a message identifier The last of these must be passed around the mqtt state machine, but the first two are very local and the buffer is always sourced from the C stack. Unfortunately, because the entire structure is persisted in the heap, some callers assume that they can always use the structure without reinitialization (see mqtt_socket_close), which will trash the C stack. Sever the pairing between message id and local state, punt the local state entirely out of the heap, and rename things to be less confusing. --- app/modules/mqtt.c | 94 ++++++++++------ app/mqtt/mqtt_msg.c | 255 +++++++++++++++++++++---------------------- app/mqtt/mqtt_msg.h | 44 ++++---- docs/modules/mqtt.md | 35 +++++- 4 files changed, 238 insertions(+), 190 deletions(-) diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index 035c005932..09b4d4544a 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -61,8 +61,8 @@ typedef struct mqtt_state_t { uint16_t port; mqtt_connect_info_t* connect_info; - mqtt_connection_t mqtt_connection; msg_queue_t* pending_msg_q; + uint16_t next_message_id; uint8_t * recv_buffer; // heap buffer for multi-packet rx uint8_t * recv_buffer_wp; // write pointer in multi-packet rx @@ -108,6 +108,15 @@ static void mqtt_socket_reconnected(void *arg, sint8_t err); static void mqtt_socket_connected(void *arg); static void mqtt_connack_fail(lmqtt_userdata * mud, int reason_code); +static uint16_t mqtt_next_message_id(lmqtt_userdata * mud) +{ + mud->mqtt_state.next_message_id++; + if (mud->mqtt_state.next_message_id == 0) + mud->mqtt_state.next_message_id++; + + return mud->mqtt_state.next_message_id; +} + static void mqtt_socket_disconnected(void *arg) // tcp only { NODE_DBG("enter mqtt_socket_disconnected.\n"); @@ -399,7 +408,8 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) // temp buffer for control messages uint8_t temp_buffer[MQTT_BUF_SIZE]; - mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); + mqtt_message_buffer_t msgb; + mqtt_msg_init(&msgb, temp_buffer, MQTT_BUF_SIZE); mqtt_message_t *temp_msg = NULL; lua_State *L = lua_getstate(); @@ -450,8 +460,6 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) mud->connState = MQTT_DATA; NODE_DBG("MQTT: Connected\r\n"); mud->keepalive_sent = 0; - luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_fail_ref); - mud->cb_connect_fail_ref = LUA_NOREF; if(mud->cb_connect_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) @@ -492,12 +500,12 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) // buffering and special code to handle this corner-case. Server will most likely have // written all to OS socket anyway, and not be aware that we "should" not have received it all yet. if(msg_qos == 1){ - temp_msg = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id); + temp_msg = mqtt_msg_puback(&msgb, msg_id); msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBACK, (int)mqtt_get_qos(temp_msg->data) ); } else if(msg_qos == 2){ - temp_msg = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id); + temp_msg = mqtt_msg_pubrec(&msgb, msg_id); msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBREC, (int)mqtt_get_qos(temp_msg->data) ); } @@ -596,12 +604,12 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) break; case MQTT_MSG_TYPE_PUBLISH: if(msg_qos == 1){ - temp_msg = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id); + temp_msg = mqtt_msg_puback(&msgb, msg_id); msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBACK, (int)mqtt_get_qos(temp_msg->data) ); } else if(msg_qos == 2){ - temp_msg = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id); + temp_msg = mqtt_msg_pubrec(&msgb, msg_id); msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBREC, (int)mqtt_get_qos(temp_msg->data) ); } @@ -629,7 +637,7 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) NODE_DBG("MQTT: Publish with QoS = 2 Received PUBREC\r\n"); // Note: actually, should not destroy the msg until PUBCOMP is received. msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); - temp_msg = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id); + temp_msg = mqtt_msg_pubrel(&msgb, msg_id); msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBREL, (int)mqtt_get_qos(temp_msg->data) ); NODE_DBG("MQTT: Response PUBREL\r\n"); @@ -638,7 +646,7 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) case MQTT_MSG_TYPE_PUBREL: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBREC && pending_msg->msg_id == msg_id){ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); - temp_msg = mqtt_msg_pubcomp(&mud->mqtt_state.mqtt_connection, msg_id); + temp_msg = mqtt_msg_pubcomp(&msgb, msg_id); msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBCOMP, (int)mqtt_get_qos(temp_msg->data) ); NODE_DBG("MQTT: Response PUBCOMP\r\n"); @@ -658,7 +666,7 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) } break; case MQTT_MSG_TYPE_PINGREQ: - temp_msg = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection); + temp_msg = mqtt_msg_pingresp(&msgb); msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PINGRESP, (int)mqtt_get_qos(temp_msg->data) ); NODE_DBG("MQTT: Response PINGRESP\r\n"); @@ -770,10 +778,12 @@ static void mqtt_socket_connected(void *arg) espconn_regist_disconcb(pesp_conn, mqtt_socket_disconnected); uint8_t temp_buffer[MQTT_BUF_SIZE]; - // call mqtt_connect() to start a mqtt connect stage. - mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); - mqtt_message_t* temp_msg = mqtt_msg_connect(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.connect_info); + mqtt_message_buffer_t msgb; + mqtt_msg_init(&msgb, temp_buffer, MQTT_BUF_SIZE); + + mqtt_message_t* temp_msg = mqtt_msg_connect(&msgb, mud->mqtt_state.connect_info); NODE_DBG("Send MQTT connection infomation, data len: %d, d[0]=%d \r\n", temp_msg->length, temp_msg->data[0]); + mud->event_timeout = MQTT_SEND_TIMEOUT; // not queue this message. should send right now. or should enqueue this before head. #ifdef CLIENT_SSL_ENABLE @@ -879,9 +889,11 @@ void mqtt_socket_timer(void *arg) mqtt_socket_reconnected(mud->pesp_conn, 0); } else { uint8_t temp_buffer[MQTT_BUF_SIZE]; - mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); + mqtt_message_buffer_t msgb; + mqtt_msg_init(&msgb, temp_buffer, MQTT_BUF_SIZE); + NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); - mqtt_message_t* temp_msg = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); + mqtt_message_t* temp_msg = mqtt_msg_pingreq(&msgb); msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg, 0, MQTT_MSG_TYPE_PINGREQ, (int)mqtt_get_qos(temp_msg->data) ); mud->keepalive_sent = 1; @@ -1380,8 +1392,12 @@ static int mqtt_socket_close( lua_State* L ) sint8 espconn_status = ESPCONN_CONN; if (mud->connected) { + uint8_t temp_buffer[MQTT_BUF_SIZE]; + mqtt_message_buffer_t msgb; + mqtt_msg_init(&msgb, temp_buffer, MQTT_BUF_SIZE); + // Send disconnect message - mqtt_message_t* temp_msg = mqtt_msg_disconnect(&mud->mqtt_state.mqtt_connection); + mqtt_message_t* temp_msg = mqtt_msg_disconnect(&msgb); NODE_DBG("Send MQTT disconnect infomation, data len: %d, d[0]=%d \r\n", temp_msg->length, temp_msg->data[0]); #ifdef CLIENT_SSL_ENABLE @@ -1437,6 +1453,9 @@ static int mqtt_socket_on( lua_State* L ) if( sl == 7 && strcmp(method, "connect") == 0){ luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref); mud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX); + }else if( sl == 7 && strcmp(method, "connfail") == 0){ + luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_fail_ref); + mud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX); }else if( sl == 7 && strcmp(method, "offline") == 0){ luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_disconnect_ref); mud->cb_disconnect_ref = luaL_ref(L, LUA_REGISTRYINDEX); @@ -1468,7 +1487,7 @@ static int mqtt_socket_unsubscribe( lua_State* L ) { NODE_DBG("enter mqtt_socket_unsubscribe.\n"); uint8_t stack = 1; - uint16_t msg_id = 0; + uint16_t msg_id; const char *topic; size_t il; lmqtt_userdata *mud; @@ -1496,7 +1515,8 @@ static int mqtt_socket_unsubscribe( lua_State* L ) { } uint8_t temp_buffer[MQTT_BUF_SIZE]; - mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); + mqtt_message_buffer_t msgb; + mqtt_msg_init(&msgb, temp_buffer, MQTT_BUF_SIZE); mqtt_message_t *temp_msg = NULL; if( lua_istable( L, stack ) ) { @@ -1510,9 +1530,10 @@ static int mqtt_socket_unsubscribe( lua_State* L ) { topic = luaL_checkstring( L, -2 ); if (topic_count == 0) { - temp_msg = mqtt_msg_unsubscribe_init( &mud->mqtt_state.mqtt_connection, &msg_id ); + msg_id = mqtt_next_message_id(mud); + temp_msg = mqtt_msg_unsubscribe_init( &msgb, msg_id ); } - temp_msg = mqtt_msg_unsubscribe_topic( &mud->mqtt_state.mqtt_connection, topic ); + temp_msg = mqtt_msg_unsubscribe_topic( &msgb, topic ); topic_count++; NODE_DBG("topic: %s - length: %d\n", topic, temp_msg->length); @@ -1533,7 +1554,7 @@ static int mqtt_socket_unsubscribe( lua_State* L ) { return luaL_error( L, "buffer overflow, can't enqueue all unsubscriptions" ); } - temp_msg = mqtt_msg_unsubscribe_fini( &mud->mqtt_state.mqtt_connection ); + temp_msg = mqtt_msg_unsubscribe_fini( &msgb ); if (temp_msg->length == 0) { return luaL_error( L, "buffer overflow, can't enqueue all unsubscriptions" ); } @@ -1546,7 +1567,8 @@ static int mqtt_socket_unsubscribe( lua_State* L ) { if( topic == NULL ){ return luaL_error( L, "need topic name" ); } - temp_msg = mqtt_msg_unsubscribe( &mud->mqtt_state.mqtt_connection, topic, &msg_id ); + msg_id = mqtt_next_message_id(mud); + temp_msg = mqtt_msg_unsubscribe( &msgb, topic, msg_id ); } if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { // TODO: this will overwrite the previous one. @@ -1580,7 +1602,7 @@ static int mqtt_socket_subscribe( lua_State* L ) { NODE_DBG("enter mqtt_socket_subscribe.\n"); uint8_t stack = 1, qos = 0; - uint16_t msg_id = 0; + uint16_t msg_id; const char *topic; size_t il; lmqtt_userdata *mud; @@ -1608,7 +1630,8 @@ static int mqtt_socket_subscribe( lua_State* L ) { } uint8_t temp_buffer[MQTT_BUF_SIZE]; - mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); + mqtt_message_buffer_t msgb; + mqtt_msg_init(&msgb, temp_buffer, MQTT_BUF_SIZE); mqtt_message_t *temp_msg = NULL; if( lua_istable( L, stack ) ) { @@ -1623,9 +1646,10 @@ static int mqtt_socket_subscribe( lua_State* L ) { qos = luaL_checkinteger( L, -1 ); if (topic_count == 0) { - temp_msg = mqtt_msg_subscribe_init( &mud->mqtt_state.mqtt_connection, &msg_id ); + msg_id = mqtt_next_message_id(mud); + temp_msg = mqtt_msg_subscribe_init( &msgb, msg_id ); } - temp_msg = mqtt_msg_subscribe_topic( &mud->mqtt_state.mqtt_connection, topic, qos ); + temp_msg = mqtt_msg_subscribe_topic( &msgb, topic, qos ); topic_count++; NODE_DBG("topic: %s - qos: %d, length: %d\n", topic, qos, temp_msg->length); @@ -1646,7 +1670,7 @@ static int mqtt_socket_subscribe( lua_State* L ) { return luaL_error( L, "buffer overflow, can't enqueue all subscriptions" ); } - temp_msg = mqtt_msg_subscribe_fini( &mud->mqtt_state.mqtt_connection ); + temp_msg = mqtt_msg_subscribe_fini( &msgb ); if (temp_msg->length == 0) { return luaL_error( L, "buffer overflow, can't enqueue all subscriptions" ); } @@ -1660,7 +1684,8 @@ static int mqtt_socket_subscribe( lua_State* L ) { return luaL_error( L, "need topic name" ); } qos = luaL_checkinteger( L, stack ); - temp_msg = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); + msg_id = mqtt_next_message_id(mud); + temp_msg = mqtt_msg_subscribe( &msgb, topic, qos, msg_id ); stack++; } @@ -1732,12 +1757,17 @@ static int mqtt_socket_publish( lua_State* L ) uint8_t retain = luaL_checkinteger( L, stack); stack ++; + if (qos != 0) { + msg_id = mqtt_next_message_id(mud); + } + uint8_t temp_buffer[MQTT_BUF_SIZE]; - mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); - mqtt_message_t *temp_msg = mqtt_msg_publish(&mud->mqtt_state.mqtt_connection, + mqtt_message_buffer_t msgb; + mqtt_msg_init(&msgb, temp_buffer, MQTT_BUF_SIZE); + mqtt_message_t *temp_msg = mqtt_msg_publish(&msgb, topic, payload, l, qos, retain, - &msg_id); + msg_id); if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack diff --git a/app/mqtt/mqtt_msg.c b/app/mqtt/mqtt_msg.c index f397569507..aab91e20e3 100644 --- a/app/mqtt/mqtt_msg.c +++ b/app/mqtt/mqtt_msg.c @@ -54,76 +54,71 @@ struct __attribute((__packed__)) mqtt_connect_variable_header uint8_t keepaliveLsb; }; -static int append_string(mqtt_connection_t* connection, const char* string, int len) +static int append_string(mqtt_message_buffer_t *msgb, const char* string, int len) { - if(connection->message.length + len + 2 > connection->buffer_length) + if(msgb->message.length + len + 2 > msgb->buffer_length) return -1; - connection->buffer[connection->message.length++] = len >> 8; - connection->buffer[connection->message.length++] = len & 0xff; - memcpy(connection->buffer + connection->message.length, string, len); - connection->message.length += len; + msgb->buffer[msgb->message.length++] = len >> 8; + msgb->buffer[msgb->message.length++] = len & 0xff; + memcpy(msgb->buffer + msgb->message.length, string, len); + msgb->message.length += len; return len + 2; } -static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t message_id) +static uint16_t append_message_id(mqtt_message_buffer_t* msgb, uint16_t message_id) { - // If message_id is zero then we should assign one, otherwise - // we'll use the one supplied by the caller - while(message_id == 0) - message_id = ++connection->message_id; - - if(connection->message.length + 2 > connection->buffer_length) + if(msgb->message.length + 2 > msgb->buffer_length) return 0; - connection->buffer[connection->message.length++] = message_id >> 8; - connection->buffer[connection->message.length++] = message_id & 0xff; + msgb->buffer[msgb->message.length++] = message_id >> 8; + msgb->buffer[msgb->message.length++] = message_id & 0xff; - return message_id; + return 1; } -static int init_message(mqtt_connection_t* connection) +static int init_message(mqtt_message_buffer_t* msgb) { - connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; + msgb->message.length = MQTT_MAX_FIXED_HEADER_SIZE; return MQTT_MAX_FIXED_HEADER_SIZE; } -static mqtt_message_t* fail_message(mqtt_connection_t* connection) +static mqtt_message_t* fail_message(mqtt_message_buffer_t* msgb) { - connection->message.data = connection->buffer; - connection->message.length = 0; - return &connection->message; + msgb->message.data = msgb->buffer; + msgb->message.length = 0; + return &msgb->message; } -static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) +static mqtt_message_t* fini_message(mqtt_message_buffer_t* msgb, int type, int dup, int qos, int retain) { - int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; + int remaining_length = msgb->message.length - MQTT_MAX_FIXED_HEADER_SIZE; if(remaining_length > 127) { - connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - connection->buffer[1] = 0x80 | (remaining_length % 128); - connection->buffer[2] = remaining_length / 128; - connection->message.length = remaining_length + 3; - connection->message.data = connection->buffer; + msgb->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + msgb->buffer[1] = 0x80 | (remaining_length % 128); + msgb->buffer[2] = remaining_length / 128; + msgb->message.length = remaining_length + 3; + msgb->message.data = msgb->buffer; } else { - connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - connection->buffer[2] = remaining_length; - connection->message.length = remaining_length + 2; - connection->message.data = connection->buffer + 1; + msgb->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + msgb->buffer[2] = remaining_length; + msgb->message.length = remaining_length + 2; + msgb->message.data = msgb->buffer + 1; } - return &connection->message; + return &msgb->message; } -void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) +void mqtt_msg_init(mqtt_message_buffer_t* msgb, uint8_t* buffer, uint16_t buffer_length) { - memset(connection, 0, sizeof(connection)); - connection->buffer = buffer; - connection->buffer_length = buffer_length; + memset(msgb, 0, sizeof(msgb)); + msgb->buffer = buffer; + msgb->buffer_length = buffer_length; } // Returns total length of message, or -1 if not enough bytes are available @@ -286,16 +281,16 @@ uint16_t mqtt_get_id(uint8_t* buffer, uint16_t buffer_length) } } -mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) +mqtt_message_t* mqtt_msg_connect(mqtt_message_buffer_t* msgb, mqtt_connect_info_t* info) { struct mqtt_connect_variable_header* variable_header; - init_message(connection); + init_message(msgb); - if(connection->message.length + sizeof(*variable_header) > connection->buffer_length) - return fail_message(connection); - variable_header = (void*)(connection->buffer + connection->message.length); - connection->message.length += sizeof(*variable_header); + if(msgb->message.length + sizeof(*variable_header) > msgb->buffer_length) + return fail_message(msgb); + variable_header = (void*)(msgb->buffer + msgb->message.length); + msgb->message.length += sizeof(*variable_header); variable_header->lengthMsb = 0; variable_header->lengthLsb = 4; @@ -310,19 +305,19 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->client_id != NULL && info->client_id[0] != '\0') { - if(append_string(connection, info->client_id, strlen(info->client_id)) < 0) - return fail_message(connection); + if(append_string(msgb, info->client_id, strlen(info->client_id)) < 0) + return fail_message(msgb); } else - return fail_message(connection); + return fail_message(msgb); if(info->will_topic != NULL && info->will_topic[0] != '\0') { - if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) - return fail_message(connection); + if(append_string(msgb, info->will_topic, strlen(info->will_topic)) < 0) + return fail_message(msgb); - if(append_string(connection, info->will_message, strlen(info->will_message)) < 0) - return fail_message(connection); + if(append_string(msgb, info->will_message, strlen(info->will_message)) < 0) + return fail_message(msgb); variable_header->flags |= MQTT_CONNECT_FLAG_WILL; if(info->will_retain) @@ -332,176 +327,174 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->username != NULL && info->username[0] != '\0') { - if(append_string(connection, info->username, strlen(info->username)) < 0) - return fail_message(connection); + if(append_string(msgb, info->username, strlen(info->username)) < 0) + return fail_message(msgb); variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; } if(info->password != NULL && info->password[0] != '\0') { - if(append_string(connection, info->password, strlen(info->password)) < 0) - return fail_message(connection); + if(append_string(msgb, info->password, strlen(info->password)) < 0) + return fail_message(msgb); variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; } - return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); + return fini_message(msgb, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); } -mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) +mqtt_message_t* mqtt_msg_publish(mqtt_message_buffer_t* msgb, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t message_id) { - init_message(connection); + init_message(msgb); if(topic == NULL || topic[0] == '\0') - return fail_message(connection); + return fail_message(msgb); - if(append_string(connection, topic, strlen(topic)) < 0) - return fail_message(connection); + if(append_string(msgb, topic, strlen(topic)) < 0) + return fail_message(msgb); if(qos > 0) { - if((*message_id = append_message_id(connection, 0)) == 0) - return fail_message(connection); + if(!append_message_id(msgb, message_id)) + return fail_message(msgb); } - else - *message_id = 0; - if(connection->message.length + data_length > connection->buffer_length) - return fail_message(connection); - memcpy(connection->buffer + connection->message.length, data, data_length); - connection->message.length += data_length; + if(msgb->message.length + data_length > msgb->buffer_length) + return fail_message(msgb); + memcpy(msgb->buffer + msgb->message.length, data, data_length); + msgb->message.length += data_length; - return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); + return fini_message(msgb, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); } -mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t* mqtt_msg_puback(mqtt_message_buffer_t* msgb, uint16_t message_id) { - init_message(connection); - if(append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); + init_message(msgb); + if(!append_message_id(msgb, message_id)) + return fail_message(msgb); + return fini_message(msgb, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); } -mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t* mqtt_msg_pubrec(mqtt_message_buffer_t* msgb, uint16_t message_id) { - init_message(connection); - if(append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); + init_message(msgb); + if(!append_message_id(msgb, message_id)) + return fail_message(msgb); + return fini_message(msgb, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); } -mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t* mqtt_msg_pubrel(mqtt_message_buffer_t* msgb, uint16_t message_id) { - init_message(connection); - if(append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); + init_message(msgb); + if(!append_message_id(msgb, message_id)) + return fail_message(msgb); + return fini_message(msgb, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); } -mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t* mqtt_msg_pubcomp(mqtt_message_buffer_t* msgb, uint16_t message_id) { - init_message(connection); - if(append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); + init_message(msgb); + if(!append_message_id(msgb, message_id)) + return fail_message(msgb); + return fini_message(msgb, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); } -mqtt_message_t* mqtt_msg_subscribe_init(mqtt_connection_t* connection, uint16_t *message_id) +mqtt_message_t* mqtt_msg_subscribe_init(mqtt_message_buffer_t* msgb, uint16_t message_id) { - init_message(connection); + init_message(msgb); - if((*message_id = append_message_id(connection, 0)) == 0) - return fail_message(connection); + if(!append_message_id(msgb, message_id)) + return fail_message(msgb); - return &connection->message; + return &msgb->message; } -mqtt_message_t* mqtt_msg_subscribe_topic(mqtt_connection_t* connection, const char* topic, int qos) +mqtt_message_t* mqtt_msg_subscribe_topic(mqtt_message_buffer_t* msgb, const char* topic, int qos) { if(topic == NULL || topic[0] == '\0') - return fail_message(connection); + return fail_message(msgb); - if(append_string(connection, topic, strlen(topic)) < 0) - return fail_message(connection); + if(append_string(msgb, topic, strlen(topic)) < 0) + return fail_message(msgb); - if(connection->message.length + 1 > connection->buffer_length) - return fail_message(connection); - connection->buffer[connection->message.length++] = qos; + if(msgb->message.length + 1 > msgb->buffer_length) + return fail_message(msgb); + msgb->buffer[msgb->message.length++] = qos; - return &connection->message; + return &msgb->message; } -mqtt_message_t* mqtt_msg_subscribe_fini(mqtt_connection_t* connection) +mqtt_message_t* mqtt_msg_subscribe_fini(mqtt_message_buffer_t* msgb) { - return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); + return fini_message(msgb, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); } -mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) +mqtt_message_t* mqtt_msg_subscribe(mqtt_message_buffer_t* msgb, const char* topic, int qos, uint16_t message_id) { mqtt_message_t* result; - result = mqtt_msg_subscribe_init(connection, message_id); + result = mqtt_msg_subscribe_init(msgb, message_id); if (result->length != 0) { - result = mqtt_msg_subscribe_topic(connection, topic, qos); + result = mqtt_msg_subscribe_topic(msgb, topic, qos); } if (result->length != 0) { - result = mqtt_msg_subscribe_fini(connection); + result = mqtt_msg_subscribe_fini(msgb); } return result; } -mqtt_message_t* mqtt_msg_unsubscribe_init(mqtt_connection_t* connection, uint16_t *message_id) +mqtt_message_t* mqtt_msg_unsubscribe_init(mqtt_message_buffer_t* msgb, uint16_t message_id) { - return mqtt_msg_subscribe_init(connection, message_id); + return mqtt_msg_subscribe_init(msgb, message_id); } -mqtt_message_t* mqtt_msg_unsubscribe_topic(mqtt_connection_t* connection, const char* topic) +mqtt_message_t* mqtt_msg_unsubscribe_topic(mqtt_message_buffer_t* msgb, const char* topic) { if(topic == NULL || topic[0] == '\0') - return fail_message(connection); + return fail_message(msgb); - if(append_string(connection, topic, strlen(topic)) < 0) - return fail_message(connection); + if(append_string(msgb, topic, strlen(topic)) < 0) + return fail_message(msgb); - return &connection->message; + return &msgb->message; } -mqtt_message_t* mqtt_msg_unsubscribe_fini(mqtt_connection_t* connection) +mqtt_message_t* mqtt_msg_unsubscribe_fini(mqtt_message_buffer_t* msgb) { - return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); + return fini_message(msgb, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); } -mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) +mqtt_message_t* mqtt_msg_unsubscribe(mqtt_message_buffer_t* msgb, const char* topic, uint16_t message_id) { mqtt_message_t* result; - result = mqtt_msg_unsubscribe_init(connection, message_id); + result = mqtt_msg_unsubscribe_init(msgb, message_id); if (result->length != 0) { - result = mqtt_msg_unsubscribe_topic(connection, topic); + result = mqtt_msg_unsubscribe_topic(msgb, topic); } if (result->length != 0) { - result = mqtt_msg_unsubscribe_fini(connection); + result = mqtt_msg_unsubscribe_fini(msgb); } return result; } -mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection) +mqtt_message_t* mqtt_msg_pingreq(mqtt_message_buffer_t* msgb) { - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); + init_message(msgb); + return fini_message(msgb, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); } -mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection) +mqtt_message_t* mqtt_msg_pingresp(mqtt_message_buffer_t* msgb) { - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); + init_message(msgb); + return fini_message(msgb, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); } -mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection) +mqtt_message_t* mqtt_msg_disconnect(mqtt_message_buffer_t* msgb) { - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); + init_message(msgb); + return fini_message(msgb, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); } diff --git a/app/mqtt/mqtt_msg.h b/app/mqtt/mqtt_msg.h index 85f70f6d73..bdaeb3e601 100644 --- a/app/mqtt/mqtt_msg.h +++ b/app/mqtt/mqtt_msg.h @@ -87,7 +87,7 @@ typedef struct mqtt_message } mqtt_message_t; -typedef struct mqtt_connection +typedef struct mqtt_message_buffer { mqtt_message_t message; @@ -95,7 +95,7 @@ typedef struct mqtt_connection uint8_t* buffer; uint16_t buffer_length; -} mqtt_connection_t; +} mqtt_message_buffer_t; typedef struct mqtt_connect_info { @@ -119,31 +119,31 @@ static inline uint8_t mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) static inline uint8_t mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } static inline uint8_t mqtt_get_connect_ret_code(uint8_t* buffer) { return (buffer[3]); } -void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); +void mqtt_msg_init(mqtt_message_buffer_t* msgb, uint8_t* buffer, uint16_t buffer_length); int32_t mqtt_get_total_length(uint8_t* buffer, uint16_t buffer_length); const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* buffer_length); const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* buffer_length); uint16_t mqtt_get_id(uint8_t* buffer, uint16_t buffer_length); -mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); -mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id); -mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); -mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); -mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection); -mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection); -mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection); - -mqtt_message_t* mqtt_msg_subscribe_init(mqtt_connection_t* connection, uint16_t* message_id); -mqtt_message_t* mqtt_msg_subscribe_topic(mqtt_connection_t* connection, const char* topic, int qos); -mqtt_message_t* mqtt_msg_subscribe_fini(mqtt_connection_t* connection); - -mqtt_message_t* mqtt_msg_unsubscribe_init(mqtt_connection_t* connection, uint16_t* message_id); -mqtt_message_t* mqtt_msg_unsubscribe_topic(mqtt_connection_t* connection, const char* topic); -mqtt_message_t* mqtt_msg_unsubscribe_fini(mqtt_connection_t* connection); +mqtt_message_t* mqtt_msg_connect(mqtt_message_buffer_t* msgb, mqtt_connect_info_t* info); +mqtt_message_t* mqtt_msg_publish(mqtt_message_buffer_t* msgb, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t message_id); +mqtt_message_t* mqtt_msg_puback(mqtt_message_buffer_t* msgb, uint16_t message_id); +mqtt_message_t* mqtt_msg_pubrec(mqtt_message_buffer_t* msgb, uint16_t message_id); +mqtt_message_t* mqtt_msg_pubrel(mqtt_message_buffer_t* msgb, uint16_t message_id); +mqtt_message_t* mqtt_msg_pubcomp(mqtt_message_buffer_t* msgb, uint16_t message_id); +mqtt_message_t* mqtt_msg_subscribe(mqtt_message_buffer_t* msgb, const char* topic, int qos, uint16_t message_id); +mqtt_message_t* mqtt_msg_unsubscribe(mqtt_message_buffer_t* msgb, const char* topic, uint16_t message_id); +mqtt_message_t* mqtt_msg_pingreq(mqtt_message_buffer_t* msgb); +mqtt_message_t* mqtt_msg_pingresp(mqtt_message_buffer_t* msgb); +mqtt_message_t* mqtt_msg_disconnect(mqtt_message_buffer_t* msgb); + +mqtt_message_t* mqtt_msg_subscribe_init(mqtt_message_buffer_t* msgb, uint16_t message_id); +mqtt_message_t* mqtt_msg_subscribe_topic(mqtt_message_buffer_t* msgb, const char* topic, int qos); +mqtt_message_t* mqtt_msg_subscribe_fini(mqtt_message_buffer_t* msgb); + +mqtt_message_t* mqtt_msg_unsubscribe_init(mqtt_message_buffer_t* msgb, uint16_t message_id); +mqtt_message_t* mqtt_msg_unsubscribe_topic(mqtt_message_buffer_t* msgb, const char* topic); +mqtt_message_t* mqtt_msg_unsubscribe_fini(mqtt_message_buffer_t* msgb); #ifdef __cplusplus diff --git a/docs/modules/mqtt.md b/docs/modules/mqtt.md index 0b9261df80..fd1e36bccf 100644 --- a/docs/modules/mqtt.md +++ b/docs/modules/mqtt.md @@ -65,6 +65,7 @@ m = mqtt.Client("clientid", 120, "user", "password") m:lwt("/lwt", "offline", 0, 0) m:on("connect", function(client) print ("connected") end) +m:on("connfail", function(client, reason) print ("connection failed", reason) end) m:on("offline", function(client) print ("offline") end) -- on publish message receive event @@ -157,8 +158,16 @@ end In reality, the connected function should do something useful! -The first callback to `:connect()` aliases with the "connect" callback available through `:on()` (the last passed callback to either of those are used). -The second (failure) callback is however not the same as the "offline" `:on()` callback. The "offline" callback is only called after an already established connection becomes closed. If the `connect()` call fails to establish a connection, the callback passed to `:connect()` is called and nothing else. +The first callback to `:connect()` aliases with the "connect" callback +available through `:on()` (the last passed callback to either of those are +used). However, if `nil` is passed to `:connect()`, any existing callback +will be preserved, rather than removed. + +The second (failure) callback aliases with the "connfail" callback available +through `:on()`. (The "offline" callback is only called after an already +established connection becomes closed. If the `connect()` call fails to +establish a connection, the callback passed to `:connect()` is called and +nothing else.) Previously, we instructed an application to pass either the *integer* 0 or *integer* 1 for `secure`. Now, this will trigger a deprecation warning; please @@ -213,8 +222,23 @@ Registers a callback function for an event. `mqtt:on(event, function(client[, topic[, message]]))` #### Parameters -- `event` can be "connect", "suback", "unsuback", "puback", "message", "overflow", or "offline" -- `function(client[, topic[, message]])` callback function. The first parameter is the client. If event is "message", the 2nd and 3rd param are received topic and message (strings). +- `event` can be "connect", "connfail", "suback", "unsuback", "puback", "message", "overflow", or "offline" +- callback function. The first parameter is always the client object itself. + Any remaining parameters passed differ by event: + + - If event is "message", the 2nd and 3rd parameters are received topic and + message, respectively, as Lua strings. + + - If the event is "overflow", the parameters are as with "message", save + that the message string is truncated to the maximum message size. + + - If the event is "connfail", the 2nd parameter will be the connection + failure code; see above. + + - Other event types do not provide additional arguments. This has some + unfortunate consequences: the broker-provided subscription maximum QoS + information is lost, and the application must, if it expects per-event + acknowledgements, manage a queue or queues itself. #### Returns `nil` @@ -231,7 +255,8 @@ Publishes a message. - `message` the message to publish, (buffer or string) - `qos` QoS level - `retain` retain flag -- `function(client)` optional callback fired when PUBACK received. +- `function(client)` optional callback fired when PUBACK received (for QoS 1 + or 2) or when message sent (for QoS 0). #### Notes From f265867890fffabcc125ac261e8c013503134f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Sun, 15 Mar 2020 09:34:12 +0100 Subject: [PATCH 38/59] Fix connect() params in example --- docs/modules/mqtt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/mqtt.md b/docs/modules/mqtt.md index fd1e36bccf..f9944baa9e 100644 --- a/docs/modules/mqtt.md +++ b/docs/modules/mqtt.md @@ -82,7 +82,7 @@ m:on("overflow", function(client, topic, data) end) -- for TLS: m:connect("192.168.11.118", secure-port, 1) -m:connect("192.168.11.118", 1883, 0, function(client) +m:connect("192.168.11.118", 1883, false, function(client) print("connected") -- Calling subscribe/publish only makes sense once the connection -- was successfully established. You can do that either here in the From 75db62f400ccdaaefdf50b16ce04d26a2d4e3efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Sun, 15 Mar 2020 09:39:33 +0100 Subject: [PATCH 39/59] Fix init.lua link --- docs/lua-developer-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/lua-developer-faq.md b/docs/lua-developer-faq.md index b7af9b7a2c..5ae459f40e 100644 --- a/docs/lua-developer-faq.md +++ b/docs/lua-developer-faq.md @@ -88,7 +88,7 @@ There are standard libraries to provide access to the various hardware options s The runtime system runs in interactive-mode. In this mode it first executes any `init.lua` script. It then "listens" to the serial port for input Lua chunks, and executes them once syntactically complete. -There is no batch support, although automated embedded processing is normally achieved by setting up the necessary event triggers in the [`init.lua`](../upload/#initlua) script. +There is no batch support, although automated embedded processing is normally achieved by setting up the necessary event triggers in the [`init.lua`](upload.md#initlua) script. The various libraries (`net`, `tmr`, `wifi`, etc.) use the SDK callback mechanism to bind Lua processing to individual events (for example a timer alarm firing). Developers should make full use of these events to keep Lua execution sequences short. From a9991c64d70b6ce0b388f448a5d5d73efe4f8fcb Mon Sep 17 00:00:00 2001 From: Christo Erasmus Date: Sun, 22 Mar 2020 12:17:01 +0100 Subject: [PATCH 40/59] Update getting-started docs hrefs for LFS examples (#3048) --- docs/getting-started.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 2f49ba65b9..d39be16159 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -268,10 +268,11 @@ The easiest approach is to maintain all the Lua files for your project in a sing For example to run the Telnet and FTP servers from LFS, put the following files in your project directory: -* [lua_examples/lfs/_init.lua](https://github.com/nodemcu/nodemcu-firmware/tree/dev/lua_examples/lfs/_init.lua). LFS helper routines and functions. -* [lua_examples/lfs/dummy_strings.lua](https://github.com/nodemcu/nodemcu-firmware/tree/dev/lua_examples/lfs/dummy_strings.lua). Moving common strings into LFS. -* [lua_examples/telnet/telnet.lua](https://github.com/nodemcu/nodemcu-firmware/tree/dev/lua_examples/telnet/telnet.lua). A simple **telnet** server. -* [lua_modules/ftp/ftpserver.lua](https://github.com/nodemcu/nodemcu-firmware/tree/dev/lua_modules/ftp/ftpserver.lua). A simple **FTP** server. +* [lua_examples/lfs/_init.lua](../lua_examples/lfs/_init.lua). LFS helper routines and functions. +* [lua_examples/lfs/dummy_strings.lua](../lua_examples/lfs/dummy_strings.lua). Moving common strings into LFS. +* [lua_examples/telnet/telnet_fifosock.lua](../lua_examples/telnet/telnet_fifosock.lua). A simple **telnet** server (example 1). +* [lua_examples/telnet/telnet_pipe.lua](../lua_examples/telnet/telnet_pipe.lua). A simple **telnet** server (example 2). +* [lua_modules/ftp/ftpserver.lua](../lua_modules/ftp/ftpserver.lua). A simple **FTP** server. You should always include the first two modules, but the remaining files would normally be replaced by your own project files. Also remember that these are examples and that you are entirely free to modify or to replace them for your own application needs. From f45a9ef43335b0958876bf9ba7969951737d2dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Sun, 22 Mar 2020 13:56:39 +0100 Subject: [PATCH 41/59] Add hint about locally built docs Fixes #2868 --- mkdocs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index 64ab69fdea..360b651405 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,6 +6,10 @@ theme: name: "readthedocs" strict: false #Allows to build and test documentation in local environment where some links are unreachable +# Uncomment the line below to build docs to be used locally; site/index.html +# will then be the root of a locally-linked documentation tree. +# use_directory_urls: false + markdown_extensions: #http://pythonhosted.org/Markdown/extensions/admonition.html - admonition: From cb2636dcc8772b3d73ed190f2b34316c8f438b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Sun, 22 Mar 2020 21:43:26 +0100 Subject: [PATCH 42/59] Add page about Lua module directory Fixes #3034 --- docs/lua-modules/README.md | 9 +++++++++ mkdocs.yml | 1 + 2 files changed, 10 insertions(+) create mode 100644 docs/lua-modules/README.md diff --git a/docs/lua-modules/README.md b/docs/lua-modules/README.md new file mode 100644 index 0000000000..ec0e3fe32d --- /dev/null +++ b/docs/lua-modules/README.md @@ -0,0 +1,9 @@ +# NodeMCU Lua modules directory + +Reviewing, hosting and thus potentially maintaining an ever growing list of NodeMCU Lua modules (the ones here) does not scale well for the project team. Instead, we give the community a chance - and the responsibility - to maintain a directory of Lua modules found in the wild through the [GitHub wiki](https://github.com/nodemcu/nodemcu-firmware/wiki/Lua-modules-directory). + +In the (hopefully not too distant) future, we will request that Lua modules to be hosted _in this repository_ come with a test program in whatever framework [we end up adopting](https://github.com/nodemcu/nodemcu-firmware/issues/2145). + +**A module being listed on the wiki does NOT mean the NodeMCU project team endorses it in any way.** + +→ [https://github.com/nodemcu/nodemcu-firmware/wiki/Lua-modules-directory](https://github.com/nodemcu/nodemcu-firmware/wiki/Lua-modules-directory) \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 360b651405..0a7d78c3b3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -42,6 +42,7 @@ pages: - Lua Compact Debug (LCD): 'lcd.md' - Lua Flash Store (LFS): 'lfs.md' - Lua Modules: + - 'Lua modules directory': 'lua-modules/README.md' - 'bh1750': 'lua-modules/bh1750.md' - 'cohelper': 'lua-modules/cohelper.md' - 'ds18b20': 'lua-modules/ds18b20.md' From e358c4a1b7c2c60e320e0389919f0c1952099246 Mon Sep 17 00:00:00 2001 From: plomi Date: Fri, 10 Apr 2020 20:36:48 +0200 Subject: [PATCH 43/59] adding mcp23017 support as a lua module --- docs/lua-modules/mcp23017.md | 234 ++++++++++++++++ lua_examples/mcp23017/mcp23017_example.lua | 112 ++++++++ lua_modules/mcp23017/README.md | 3 + lua_modules/mcp23017/mcp23017.lua | 299 +++++++++++++++++++++ mkdocs.yml | 1 + 5 files changed, 649 insertions(+) create mode 100644 docs/lua-modules/mcp23017.md create mode 100644 lua_examples/mcp23017/mcp23017_example.lua create mode 100644 lua_modules/mcp23017/README.md create mode 100644 lua_modules/mcp23017/mcp23017.lua diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md new file mode 100644 index 0000000000..2cf2d350dd --- /dev/null +++ b/docs/lua-modules/mcp23017.md @@ -0,0 +1,234 @@ +# Lua MCP23017 Module for NodeMCU / ESP8266 + +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2020-04-10 | [Marcel P.](https://github.com/plomi-net) | [Marcel P.](https://github.com/plomi-net) | [mcp23017.lua](../../lua_modules/mcp23017/mcp23017.lua) | + + +This Lua module provides access to the MCP23017 module. + +The [MCP23017](http://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf) is a port expander and provides 16 channels for inputs and outputs. +Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2). + +Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B. +A single pin can be set or a whole byte. + +The numbering of the individual pins starts at 0 and ends with 15. +The numbers up to 7 are on register GPIO A and from 8 to 15 on GPIO B. + + +!!! important + The module requires `i2c` and `bit` C module built into firmware. + + +### Require +```lua +mcp23017 = require("mcp23017") +``` + +## Example Script +The example script can be found [here](../../lua_examples/mcp23017/mcp23017_example.lua) + +## setup() +Configures the interface and sets the i2c pins and the address of the device. +Automatically resets the device state (see `mcp23017.reset()`) + +#### Syntax +`mcp23017.setup(address, customSCL, customSDA)` + +#### Parameter +- `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) +- `customSCL` Pin for i²c SCL Signal, default: GPIO 5, Pin 1 +- `customSDA` Pin for i²c SDA Signal, default: GPIO 4, Pin 2 + +#### Return +`true` if device found, otherwise `false`. + +#### possible Errors +- `MCP23017 device on address not found` +- `MCP23017 address is out of range` + +#### Example +```lua +local mcp23017 = require('mcp23017') + +local address = 0x20 +local cSCL = 1 +local cSDA = 2 + +mcp23017.setup(address, cSCL,cSDA) +``` + +## setMode() +Set the mode of a single channel. This can be OUTPUT or INPUT. + +#### Syntax +`mcp23017.setMode(pin, mode)` + +#### Parameter +- `pin` the number to be set for the channel (0-15) +- `mode` the mode for the channel. This can be `mcp23017.INPUT` or `mcp23017.OUTPUT` + +#### Return +`true`, in case of error `nil`. + +#### Example +```lua +-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input +mcp23017.setMode(7, mcp23017.OUTPUT) +mcp23017.setMode(8, mcp23017.OUTPUT) +mcp23017.setMode(9, mcp23017.INPUT) +``` + +## setPin() +Set the state of a single channel. This can be HIGH or LOW. + +#### Syntax +`mcp23017.setMode(pin, state)` + +#### Parameter +- `pin` the number to be set for the channel (0-15) +- `state` the state for the channel. This can be `mcp23017.HIGH` or `mcp23017.LOW` + +#### Return +`true`, in case of error `nil`. + +#### Example +```lua +-- set pin 7 to high (GPA7) +mcp23017.setPin(7, mcp23017.HIGH) +-- set pin 8 to low (GPB0) +mcp23017.setPin(8, mcp23017.LOW) +``` + +## getPinState() +get the state for a single channel. This can be HIGH or LOW. + +#### Syntax +`mcp23017.getPinState(pin)` + +#### Parameter +- `pin` the number for which a state is to be queried (0-15) + +#### Return +`true` for HIGH, `false` for LOW, in case of error `nil`. + +#### Example +```lua +-- get the state for pin 9 (GPB1) +print(mcp23017.getPinState(9)) +``` + +## reset() +By calling this function, a safe state is established. +All channels are set to input and internal pullup resistors are disabled. +This function can be used for a panic program. + +#### Syntax +`mcp23017.reset()` + +#### Parameter +None + +#### Return +None + +#### Example +```lua +-- reset the mcp23017 to startup defaults +mcp23017.reset() +``` + +## setInternalPullUp() +Enable or disable the internal pullup resistors. +Same for register A and B +Please note that the setting is overwritten with reset() + +#### Syntax +`mcp23017.setInternalPullUp(byte)` + +#### Parameter +- `byte` byte to set the pullup resistors + +#### Return +None + +#### Example +```lua +-- enable all pullup resistors +print(mcp23017.setInternalPullUp(0xFF)) +-- disable all pullup resistors (default) +print(mcp23017.setInternalPullUp(0x00)) +``` + +## writeIODIRA() +Setup the mode of the channels with a whole byte. In this case for register A. + + +#### Syntax +`mcp23017.writeIODIRA(byte)` + +#### Parameter +- `byte` byte to set the mode for all channels for this register + +#### Return +None + +#### Example +```lua +-- set all GPA to input +print(mcp23017.writeIODIRA(0xFF)) +-- set all GPA to output +print(mcp23017.writeIODIRA(0x00)) +``` + +## writeIODIRB() +Setup the mode of the channels with a whole byte. In this case for register B. +The function is equivalent to `mcp23017.writeIODIRA()` + +## writeGPIOA() +Setup the output state of the channels with a whole byte. In this case for register A. + +#### Syntax +`mcp23017.writeGPIOA(byte)` + +#### Parameter +- `byte` byte to set the state for all channels for this register + +#### Return +None + +#### Example +```lua +-- set all GPA to HIGH +print(mcp23017.writeGPIOA(0xFF)) +-- set all GPA to LOW +print(mcp23017.writeGPIOA(0x00)) +``` + +## writeGPIOB() +Setup the output state of the channels with a whole byte. In this case for register B. +The function is equivalent to `mcp23017.writeGPIOA()` + +## readGPIOA() +Read the input states of the channels with a whole byte. In this case for register A. + +#### Syntax +`mcp23017.readGPIOA()` + +#### Parameter +None + +#### Return +byte with states + +#### Example +```lua +-- get states for GPA +print(mcp23017.readGPIOA()) +``` + +## readGPIOB() +Read the input states of the channels with a whole byte. In this case for register B. +The function is equivalent to `mcp23017.readGPIOA()` + diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua new file mode 100644 index 0000000000..b08e17efd4 --- /dev/null +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -0,0 +1,112 @@ +--[[ + + This example demonstrates how to use the different functions of the mcp23017 lua module. + + @author Marcel P. | Plomi.net + @github https://github.com/plomi-net + + @version 1.0.0 + +]] + + + + + +--[[ + + initialize and setup + +]] + +-- initialize module +local mcp23017 = require('mcp23017') + +-- set the address for MCP23017 +local address = 0x20 + +-- SCL pin = 1 = D1 / GPIO 5 (ESP8266) +local cSCL = 1 + +-- SDA pin = 2 = D2 / GPIO4 (ESP8266) +local cSDA = 2 + +-- setup mcp23017 +mcp23017.setup(address, cSCL, cSDA) + + +--[[ + + set output and input channels + +]] + +-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input +mcp23017.setMode(7, mcp23017.OUTPUT) +mcp23017.setMode(8, mcp23017.OUTPUT) +mcp23017.setMode(9, mcp23017.INPUT) + + + +--[[ + + set output channels to high and low + +]] + +-- set pin 7 to high (GPA7) +mcp23017.setPin(7, mcp23017.HIGH) +-- set pin 8 to low (GPB0) +mcp23017.setPin(8, mcp23017.LOW) + + + + +--[[ + + toggle pin 6 channel state every second (blinking) + +]] + +local currentPin = 6 +local currentState = false + +mcp23017.setMode(currentPin, mcp23017.OUTPUT) + +if not tmr.create():alarm(1000, tmr.ALARM_AUTO, function() + if currentState == true then + -- print("set to low") + mcp23017.setPin(currentPin, mcp23017.LOW) + currentState = false + else + -- print("set to high") + mcp23017.setPin(currentPin, mcp23017.HIGH) + currentState = true + end +end) then + print("Timer can't be created") +end + + + + + +--[[ + + read input channels and display every 7 seconds + +]] + +-- read input register +if not tmr.create():alarm(7000, tmr.ALARM_AUTO, function() + local a = mcp23017.readGPIOA() + print(" ") + print("GPIO A input states: " .. a) + + local b = mcp23017.readGPIOB() + print("GPIO B input states: " .. b) + print(" ") + +end) then + print("Timer can't be created") +end \ No newline at end of file diff --git a/lua_modules/mcp23017/README.md b/lua_modules/mcp23017/README.md new file mode 100644 index 0000000000..f6d6d8089c --- /dev/null +++ b/lua_modules/mcp23017/README.md @@ -0,0 +1,3 @@ +# MCP23017 Module + +Documentation for this Lua module is available in the [mcp23017.md](../../docs/lua-modules/mcp23017.md) file and in the [Official NodeMCU Documentation](https://nodemcu.readthedocs.io/) in `Lua Modules` section. diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua new file mode 100644 index 0000000000..c8e5010eb5 --- /dev/null +++ b/lua_modules/mcp23017/mcp23017.lua @@ -0,0 +1,299 @@ +--[[ + + This Lua module provides access to the MCP23017 module. + + The MCP23017 is a port expander and provides 16 channels for inputs and outputs. + Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2 Pins). + + Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B. + A single pin can be set or a whole byte. The numbering of the individual pins starts at 0 and ends with 15. + The numbers up to 7 are on register GPIO A and from 8 to 15 on GPIO B. + + The module requires `i2c` and `bit` C module built into firmware. + + + @author Marcel P. | Plomi.net + @github https://github.com/plomi-net + + @version 1.0.0 + +]] + +local i2c, string = i2c, string +local issetBit = bit.isset +local setBit = bit.set +local clearBit = bit.clear + +local MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) +-- MCP23017_SDA = 2 -- D2/GPIO 4 +-- MCP23017_SCL = 1 -- D1/GPIO 5 + +local OUTPUT = false +local INPUT = true +local HIGH = true +local LOW = false + +-- registers (not used registers are commented out) +local MCP23017_IODIRA = 0x00 +local MCP23017_IODIRB = 0x01 +local MCP23017_DEFVALA = 0x06 +local MCP23017_DEFVALB = 0x07 +local MCP23017_GPIOA = 0x12 +local MCP23017_GPIOB = 0x13 + +--[[ +local MCP23017_IPOLA = 0x02 +local MCP23017_IPOLB = 0x03 +local MCP23017_GPINTENA = 0x04 +local MCP23017_GPINTENB = 0x05 +local MCP23017_DEFVALA = 0x06 +local MCP23017_DEFVALB = 0x07 +local MCP23017_INTCONA = 0x08 +local MCP23017_INTCONB = 0x09 +local MCP23017_IOCON = 0x0A +local MCP23017_IOCON2 = 0x0B +local MCP23017_GPPUA = 0x0C +local MCP23017_GPPUB = 0x0D +local MCP23017_INTFA = 0x0E +local MCP23017_INTFB = 0x0F + +local MCP23017_INTCAPA = 0x10 +local MCP23017_INTCAPB = 0x11 +local MCP23017_OLATA = 0x14 +local MCP23017_OLATB = 0x15 +]] + +-- internal +local MCP23017_id = 0 +local MCP23017_SPEED = i2c.SLOW +local MCP23017_DEVICE_OK = false + +-- check device is available on address +local function checkDevice(address) + i2c.start(MCP23017_id) + local response = i2c.address(MCP23017_id, address, i2c.TRANSMITTER) + i2c.stop(MCP23017_id) + if response ~= true then + print("MCP23017 device on " .. string.format('0x%02X', address) .. " not found") + end + return response +end + +-- check device address (0x20 to 0x27) +local function checkAddress(address) + local addr = tonumber(address) + if (addr > 31 and addr < 40) then + return true + else + print("MCP23017 address is out of range") + return false + end +end + +-- write byte +local function writeByte(registerAddr, val) + i2c.start(MCP23017_id) + i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) + i2c.write(MCP23017_id, registerAddr) + i2c.write(MCP23017_id, val) + i2c.stop(MCP23017_id) +end + +-- read byte +local function readByte(registerAddr) + i2c.start(MCP23017_id) + i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) + i2c.write(MCP23017_id, registerAddr) + i2c.stop(MCP23017_id) + i2c.start(MCP23017_id) + i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.RECEIVER) + local data = i2c.read(MCP23017_id, 1) + i2c.stop(MCP23017_id) + return string.byte(data) +end + +-- get IO dir register +local function getDirRegisterAddr(pin) + if pin > 7 then + return MCP23017_IODIRB + else + return MCP23017_IODIRA + end +end + +-- get GPIO register address +local function getGPIORegisterAddr(pin) + if pin > 7 then + return MCP23017_GPIOB + else + return MCP23017_GPIOA + end +end + +-- convert pin number for A/B register +local function convertPin(pin) + if pin > 15 or pin < 0 then + print("The pin must be between 0 and 15") + return nil + end + return pin % 8 +end + +-- setup internal pullup +local function setInternalPullUp(iByte) + writeByte(MCP23017_DEFVALA, iByte) + writeByte(MCP23017_DEFVALB, iByte) +end + +-- set default GPIO mode +local function setDefaultMode(iByte) + writeByte(MCP23017_IODIRA, iByte) + writeByte(MCP23017_IODIRB, iByte) +end + +local function numberToBool(val) + if val == 1 or val == true or val == '1' then + return true + else + return false + end +end + +-- reset gpio mode and pullup +local function reset() + setDefaultMode(0xFF) -- all to input + setInternalPullUp(0x00) -- disable pullup +end + +-- setup device +local function setup(address, sclPin, sdaPin) + + MCP23017_ADDRESS = string.format('0x%02X', address) + + i2c.setup(MCP23017_id, sdaPin, sclPin, MCP23017_SPEED) + + if (checkAddress(address) ~= true) or (checkDevice(address) ~= true) then + MCP23017_DEVICE_OK = false + return 0 + else + MCP23017_DEVICE_OK = true + reset() + return 1 + end +end + +-- set mode for a pin +local function setMode(pin, mode) + if MCP23017_DEVICE_OK == false then + return nil + end + + local inReq = getDirRegisterAddr(pin) + local inPin = convertPin(pin) + local response = readByte(inReq) + local newState + + if numberToBool(mode) == OUTPUT then + newState = clearBit(response, inPin) + else + newState = setBit(response, inPin) + end + + writeByte(inReq, newState) + return true +end + +-- set pin to low or high +local function setPin(pin, state) + if MCP23017_DEVICE_OK == false then + return nil + end + + local inReq = getGPIORegisterAddr(pin) + local inPin = convertPin(pin) + local response = readByte(inReq) + local newState + + if numberToBool(state) == HIGH then + newState = setBit(response, inPin) + else + newState = clearBit(response, inPin) + end + + writeByte(inReq, newState) + return true +end + +-- read pin input +local function getPinState(pin) + if MCP23017_DEVICE_OK == false then + return nil + end + + local inReq = getGPIORegisterAddr(pin) + local inPin = convertPin(pin) + local response = readByte(inReq) + return issetBit(response, inPin) +end + +local function writeToRegsiter(registerAddr, newByte) + if MCP23017_DEVICE_OK == false then + return nil + end + return writeByte(registerAddr, newByte) +end + +local function readFromRegsiter(registerAddr) + if MCP23017_DEVICE_OK == false then + return nil + end + return readByte(registerAddr) +end + +local function writeIODIRA(newByte) + return writeToRegsiter(MCP23017_IODIRA, newByte) +end + +local function writeIODIRB(newByte) + return writeToRegsiter(MCP23017_IODIRB, newByte) +end + +local function writeGPIOA(newByte) + return writeToRegsiter(MCP23017_GPIOA, newByte) +end + +local function writeGPIOB(newByte) + return writeToRegsiter(MCP23017_GPIOB, newByte) +end + +local function readGPIOA() + return readFromRegsiter(MCP23017_GPIOA) +end + +local function readGPIOB() + return readFromRegsiter(MCP23017_GPIOB) +end + +-- Set module name as parameter of require and return module table +local M = { + HIGH = HIGH, + LOW = LOW, + OUTPUT = OUTPUT, + INPUT = INPUT, + checkDevice = checkDevice, + setup = setup, + setMode = setMode, + setPin = setPin, + getPinState = getPinState, + reset = reset, + setInternalPullUp = setInternalPullUp, + writeIODIRA = writeIODIRA, + writeIODIRB = writeIODIRB, + writeGPIOA = writeGPIOA, + writeGPIOB = writeGPIOB, + readGPIOA = readGPIOA, + readGPIOB = readGPIOB, +} + +_G[modname or 'mcp23017'] = M +return M diff --git a/mkdocs.yml b/mkdocs.yml index 0a7d78c3b3..0eb5dfd77e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,6 +56,7 @@ pages: - 'imap': 'lua-modules/imap.md' - 'lm92': 'lua-modules/lm92.md' - 'mcp23008': 'lua-modules/mcp23008.md' + - 'mcp23017': 'lua-modules/mcp23017.md' - 'redis': 'lua-modules/redis.md' - 'yeelink': 'lua-modules/yeelink.md' - C Modules: From 1d7e7d9579d54026178dd845954ce4e1dade30e6 Mon Sep 17 00:00:00 2001 From: plomi Date: Fri, 10 Apr 2020 20:43:18 +0200 Subject: [PATCH 44/59] adding mcp23017 support as a lua module --- lua_modules/mcp23017/mcp23017.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index c8e5010eb5..777d754bce 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -295,5 +295,6 @@ local M = { readGPIOB = readGPIOB, } -_G[modname or 'mcp23017'] = M +local moduleName = ... +_G[moduleName or 'mcp23017'] = M return M From a4c30e47391a0f624bacea7a6e4c303c127f6d2b Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 08:06:51 +0200 Subject: [PATCH 45/59] Correcting functions for a/b register, update doc and remove unnecessary checks in example --- docs/lua-modules/mcp23017.md | 84 ++++++++++++-------------- lua_modules/mcp23017/mcp23017.lua | 99 ++++++++++++++----------------- 2 files changed, 84 insertions(+), 99 deletions(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index 2cf2d350dd..3054d62976 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -13,8 +13,8 @@ Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2 Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B. A single pin can be set or a whole byte. -The numbering of the individual pins starts at 0 and ends with 15. -The numbers up to 7 are on register GPIO A and from 8 to 15 on GPIO B. +The numbering of the individual pins starts at 0 and ends with 7. +The numbers are for each register GPIO A and GPIO B. !!! important @@ -63,9 +63,10 @@ mcp23017.setup(address, cSCL,cSDA) Set the mode of a single channel. This can be OUTPUT or INPUT. #### Syntax -`mcp23017.setMode(pin, mode)` +`mcp23017.setMode(register, pin, mode)` #### Parameter +- `register` the side of channels (GPA or GPB) - `pin` the number to be set for the channel (0-15) - `mode` the mode for the channel. This can be `mcp23017.INPUT` or `mcp23017.OUTPUT` @@ -75,18 +76,19 @@ Set the mode of a single channel. This can be OUTPUT or INPUT. #### Example ```lua -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(7, mcp23017.OUTPUT) -mcp23017.setMode(8, mcp23017.OUTPUT) -mcp23017.setMode(9, mcp23017.INPUT) +mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) ``` ## setPin() Set the state of a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.setMode(pin, state)` +`mcp23017.setMode(register, pin, state)` #### Parameter +- `register` the side of channels (GPA or GPB) - `pin` the number to be set for the channel (0-15) - `state` the state for the channel. This can be `mcp23017.HIGH` or `mcp23017.LOW` @@ -96,18 +98,19 @@ Set the state of a single channel. This can be HIGH or LOW. #### Example ```lua -- set pin 7 to high (GPA7) -mcp23017.setPin(7, mcp23017.HIGH) +mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(8, mcp23017.LOW) +mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) ``` ## getPinState() get the state for a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.getPinState(pin)` +`mcp23017.getPinState(register, pin)` #### Parameter +- `register` the side of channels (GPA or GPB) - `pin` the number for which a state is to be queried (0-15) #### Return @@ -116,12 +119,12 @@ get the state for a single channel. This can be HIGH or LOW. #### Example ```lua -- get the state for pin 9 (GPB1) -print(mcp23017.getPinState(9)) +print(mcp23017.getPinState(mcp23017.GPB, 1)) ``` ## reset() By calling this function, a safe state is established. -All channels are set to input and internal pullup resistors are disabled. +All channels are set to input. This function can be used for a panic program. #### Syntax @@ -141,13 +144,12 @@ mcp23017.reset() ## setInternalPullUp() Enable or disable the internal pullup resistors. -Same for register A and B -Please note that the setting is overwritten with reset() #### Syntax -`mcp23017.setInternalPullUp(byte)` +`mcp23017.setInternalPullUp(register, byte)` #### Parameter +- `register` the side of channels (GPA or GPB) - `byte` byte to set the pullup resistors #### Return @@ -155,20 +157,21 @@ None #### Example ```lua --- enable all pullup resistors -print(mcp23017.setInternalPullUp(0xFF)) --- disable all pullup resistors (default) -print(mcp23017.setInternalPullUp(0x00)) +-- enable all pullup resistors for GPA +print(mcp23017.setInternalPullUp(mcp23017.GPA, 0xFF)) +-- disable all pullup resistors for GPA +print(mcp23017.setInternalPullUp(mcp23017.GPA, 0x00)) ``` -## writeIODIRA() -Setup the mode of the channels with a whole byte. In this case for register A. +## writeIODIR() +Setup the mode of the channels with a whole byte. #### Syntax -`mcp23017.writeIODIRA(byte)` +`mcp23017.writeIODIR(register, byte)` #### Parameter +- `register` the side of channels (GPA or GPB) - `byte` byte to set the mode for all channels for this register #### Return @@ -177,22 +180,19 @@ None #### Example ```lua -- set all GPA to input -print(mcp23017.writeIODIRA(0xFF)) +print(mcp23017.writeIODIR(mcp23017.GPA, 0xFF)) -- set all GPA to output -print(mcp23017.writeIODIRA(0x00)) +print(mcp23017.writeIODIR(mcp23017.GPA, 0x00)) ``` -## writeIODIRB() -Setup the mode of the channels with a whole byte. In this case for register B. -The function is equivalent to `mcp23017.writeIODIRA()` - -## writeGPIOA() -Setup the output state of the channels with a whole byte. In this case for register A. +## writeGPIO() +Setup the output state of the channels with a whole byte. #### Syntax -`mcp23017.writeGPIOA(byte)` +`mcp23017.writeGPIO(register, byte)` #### Parameter +- `register` the side of channels (GPA or GPB) - `byte` byte to set the state for all channels for this register #### Return @@ -201,23 +201,19 @@ None #### Example ```lua -- set all GPA to HIGH -print(mcp23017.writeGPIOA(0xFF)) +print(mcp23017.writeGPIO(mcp23017.GPA, 0xFF)) -- set all GPA to LOW -print(mcp23017.writeGPIOA(0x00)) +print(mcp23017.writeGPIO(mcp23017.GPA, 0x00)) ``` -## writeGPIOB() -Setup the output state of the channels with a whole byte. In this case for register B. -The function is equivalent to `mcp23017.writeGPIOA()` - -## readGPIOA() -Read the input states of the channels with a whole byte. In this case for register A. +## readGPIO() +Read the input states of the channels with a whole byte. #### Syntax -`mcp23017.readGPIOA()` +`mcp23017.readGPIO(register)` #### Parameter -None +- `register` the side of channels (GPA or GPB) #### Return byte with states @@ -225,10 +221,6 @@ byte with states #### Example ```lua -- get states for GPA -print(mcp23017.readGPIOA()) +print(mcp23017.readGPIO(mcp23017.GPA)) ``` -## readGPIOB() -Read the input states of the channels with a whole byte. In this case for register B. -The function is equivalent to `mcp23017.readGPIOA()` - diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index 777d754bce..d0e393e7ca 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -30,6 +30,8 @@ local MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) local OUTPUT = false local INPUT = true +local GPA = false +local GPB = true local HIGH = true local LOW = false @@ -113,8 +115,8 @@ local function readByte(registerAddr) end -- get IO dir register -local function getDirRegisterAddr(pin) - if pin > 7 then +local function getDirRegisterAddr(bReg) + if bReg == GPB then return MCP23017_IODIRB else return MCP23017_IODIRA @@ -122,33 +124,35 @@ local function getDirRegisterAddr(pin) end -- get GPIO register address -local function getGPIORegisterAddr(pin) - if pin > 7 then +local function getGPIORegisterAddr(bReg) + if bReg == GPB then return MCP23017_GPIOB else return MCP23017_GPIOA end end --- convert pin number for A/B register -local function convertPin(pin) - if pin > 15 or pin < 0 then - print("The pin must be between 0 and 15") +-- check pin is in range +local function checkPinIsInRange(pin) + if pin > 7 or pin < 0 then + print("The pin must be between 0 and 7") return nil end - return pin % 8 + return pin end -- setup internal pullup -local function setInternalPullUp(iByte) - writeByte(MCP23017_DEFVALA, iByte) - writeByte(MCP23017_DEFVALB, iByte) +local function setInternalPullUp(bReg, iByte) + if bReg == GPB then + writeByte(MCP23017_DEFVALB, iByte) + else + writeByte(MCP23017_DEFVALA, iByte) + end end -- set default GPIO mode -local function setDefaultMode(iByte) - writeByte(MCP23017_IODIRA, iByte) - writeByte(MCP23017_IODIRB, iByte) +local function setDefaultMode(bReg, iByte) + writeByte(getDirRegisterAddr(bReg), iByte) end local function numberToBool(val) @@ -159,10 +163,11 @@ local function numberToBool(val) end end --- reset gpio mode and pullup +-- reset gpio mode local function reset() - setDefaultMode(0xFF) -- all to input - setInternalPullUp(0x00) -- disable pullup + -- all to input + setDefaultMode(GPA, 0xFF) + setDefaultMode(GPB, 0xFF) end -- setup device @@ -183,13 +188,13 @@ local function setup(address, sclPin, sdaPin) end -- set mode for a pin -local function setMode(pin, mode) +local function setMode(bReg, pin, mode) if MCP23017_DEVICE_OK == false then return nil end - local inReq = getDirRegisterAddr(pin) - local inPin = convertPin(pin) + local inReq = getDirRegisterAddr(bReg) + local inPin = checkPinIsInRange(pin) local response = readByte(inReq) local newState @@ -204,13 +209,13 @@ local function setMode(pin, mode) end -- set pin to low or high -local function setPin(pin, state) +local function setPin(bReg, pin, state) if MCP23017_DEVICE_OK == false then return nil end - local inReq = getGPIORegisterAddr(pin) - local inPin = convertPin(pin) + local inReq = getGPIORegisterAddr(bReg) + local inPin = checkPinIsInRange(pin) local response = readByte(inReq) local newState @@ -225,13 +230,13 @@ local function setPin(pin, state) end -- read pin input -local function getPinState(pin) +local function getPinState(bReg, pin) if MCP23017_DEVICE_OK == false then return nil end - local inReq = getGPIORegisterAddr(pin) - local inPin = convertPin(pin) + local inReq = getGPIORegisterAddr(bReg) + local inPin = checkPinIsInRange(pin) local response = readByte(inReq) return issetBit(response, inPin) end @@ -250,36 +255,27 @@ local function readFromRegsiter(registerAddr) return readByte(registerAddr) end -local function writeIODIRA(newByte) - return writeToRegsiter(MCP23017_IODIRA, newByte) -end - -local function writeIODIRB(newByte) - return writeToRegsiter(MCP23017_IODIRB, newByte) +local function writeIODIR(bReg, newByte) + return writeToRegsiter(getDirRegisterAddr(bReg), newByte) end -local function writeGPIOA(newByte) - return writeToRegsiter(MCP23017_GPIOA, newByte) +local function writeGPIO(bReg, newByte) + return writeToRegsiter(getGPIORegisterAddr(bReg), newByte) end -local function writeGPIOB(newByte) - return writeToRegsiter(MCP23017_GPIOB, newByte) +local function readGPIO(bReg) + return readFromRegsiter(getGPIORegisterAddr(bReg)) end -local function readGPIOA() - return readFromRegsiter(MCP23017_GPIOA) -end -local function readGPIOB() - return readFromRegsiter(MCP23017_GPIOB) -end - --- Set module name as parameter of require and return module table +-- Set module name as parameter of require and rgetGPIORegisterAddreturn module table local M = { - HIGH = HIGH, - LOW = LOW, OUTPUT = OUTPUT, INPUT = INPUT, + GPA = GPA, + GPB = GPB, + HIGH = HIGH, + LOW = LOW, checkDevice = checkDevice, setup = setup, setMode = setMode, @@ -287,12 +283,9 @@ local M = { getPinState = getPinState, reset = reset, setInternalPullUp = setInternalPullUp, - writeIODIRA = writeIODIRA, - writeIODIRB = writeIODIRB, - writeGPIOA = writeGPIOA, - writeGPIOB = writeGPIOB, - readGPIOA = readGPIOA, - readGPIOB = readGPIOB, + writeIODIR = writeIODIR, + writeGPIO = writeGPIO, + readGPIO = readGPIO, } local moduleName = ... From c39949bf1db7a59c4b9ec7a37b422d89ad64f922 Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 08:17:12 +0200 Subject: [PATCH 46/59] Correcting functions for a/b register, update doc and remove unnecessary checks in example --- lua_examples/mcp23017/mcp23017_example.lua | 33 +++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua index b08e17efd4..76b75a6fc1 100644 --- a/lua_examples/mcp23017/mcp23017_example.lua +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -42,9 +42,9 @@ mcp23017.setup(address, cSCL, cSDA) ]] -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(7, mcp23017.OUTPUT) -mcp23017.setMode(8, mcp23017.OUTPUT) -mcp23017.setMode(9, mcp23017.INPUT) +mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) @@ -55,9 +55,9 @@ mcp23017.setMode(9, mcp23017.INPUT) ]] -- set pin 7 to high (GPA7) -mcp23017.setPin(7, mcp23017.HIGH) +mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(8, mcp23017.LOW) +mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) @@ -71,21 +71,19 @@ mcp23017.setPin(8, mcp23017.LOW) local currentPin = 6 local currentState = false -mcp23017.setMode(currentPin, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPA, currentPin, mcp23017.OUTPUT) -if not tmr.create():alarm(1000, tmr.ALARM_AUTO, function() +tmr.create():alarm(1000, tmr.ALARM_AUTO, function() if currentState == true then -- print("set to low") - mcp23017.setPin(currentPin, mcp23017.LOW) + mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.LOW) currentState = false else -- print("set to high") - mcp23017.setPin(currentPin, mcp23017.HIGH) + mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.HIGH) currentState = true end -end) then - print("Timer can't be created") -end +end) @@ -98,15 +96,12 @@ end ]] -- read input register -if not tmr.create():alarm(7000, tmr.ALARM_AUTO, function() - local a = mcp23017.readGPIOA() +tmr.create():alarm(7000, tmr.ALARM_AUTO, function() + local a = mcp23017.readGPIO(mcp23017.GPA) print(" ") print("GPIO A input states: " .. a) - local b = mcp23017.readGPIOB() + local b = mcp23017.readGPIO(mcp23017.GPB) print("GPIO B input states: " .. b) print(" ") - -end) then - print("Timer can't be created") -end \ No newline at end of file +end) \ No newline at end of file From ceadbbe55636c2e621c33b822b5387433f501d18 Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 21:59:30 +0200 Subject: [PATCH 47/59] remove mandatory i2c setup from mcp setup function, add optional setup and require i2c id, update doc and example --- docs/lua-modules/mcp23017.md | 13 +++++++++---- lua_examples/mcp23017/mcp23017_example.lua | 9 ++++++--- lua_modules/mcp23017/mcp23017.lua | 18 +++++++++++++++--- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index 3054d62976..f57af55b0b 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -30,7 +30,9 @@ mcp23017 = require("mcp23017") The example script can be found [here](../../lua_examples/mcp23017/mcp23017_example.lua) ## setup() -Configures the interface and sets the i2c pins and the address of the device. +Configures the address of the module and tests the connection to the i2c bus. +The i2c id is required for an existing i2c interface, alternatively the sda and scl pins can be specified. +Then this function will establish the connection. Automatically resets the device state (see `mcp23017.reset()`) #### Syntax @@ -38,8 +40,9 @@ Automatically resets the device state (see `mcp23017.reset()`) #### Parameter - `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) -- `customSCL` Pin for i²c SCL Signal, default: GPIO 5, Pin 1 -- `customSDA` Pin for i²c SDA Signal, default: GPIO 4, Pin 2 +- `i2c_id` id for the i2c bus connection (i2c.setup separately) +- `customSCL` (optional) Pin for i²c SCL Signal, default: GPIO 5, Pin 1 +- `customSDA` (optional) Pin for i²c SDA Signal, default: GPIO 4, Pin 2 #### Return `true` if device found, otherwise `false`. @@ -55,8 +58,10 @@ local mcp23017 = require('mcp23017') local address = 0x20 local cSCL = 1 local cSDA = 2 +local cID = 0 -mcp23017.setup(address, cSCL,cSDA) +i2c.setup(cID, cSDA, cSCL, i2c.SLOW) +mcp23017.setup(address, cID) ``` ## setMode() diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua index 76b75a6fc1..b59abc460a 100644 --- a/lua_examples/mcp23017/mcp23017_example.lua +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -31,8 +31,11 @@ local cSCL = 1 -- SDA pin = 2 = D2 / GPIO4 (ESP8266) local cSDA = 2 --- setup mcp23017 -mcp23017.setup(address, cSCL, cSDA) +local i2cId = 0 + +-- setup i2c bus and mcp23017 +i2c.setup(i2cId, cSDA, cSCL, i2c.SLOW) +mcp23017.setup(address, i2cId) --[[ @@ -104,4 +107,4 @@ tmr.create():alarm(7000, tmr.ALARM_AUTO, function() local b = mcp23017.readGPIO(mcp23017.GPB) print("GPIO B input states: " .. b) print(" ") -end) \ No newline at end of file +end) diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index d0e393e7ca..ec9d4cabd3 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -67,7 +67,6 @@ local MCP23017_OLATB = 0x15 -- internal local MCP23017_id = 0 -local MCP23017_SPEED = i2c.SLOW local MCP23017_DEVICE_OK = false -- check device is available on address @@ -171,11 +170,15 @@ local function reset() end -- setup device -local function setup(address, sclPin, sdaPin) +local function setup(address, i2c_id, sclPin, sdaPin) MCP23017_ADDRESS = string.format('0x%02X', address) - i2c.setup(MCP23017_id, sdaPin, sclPin, MCP23017_SPEED) + if sclPin ~= nil and sdaPin ~= nil then + i2c.setup(i2c_id, sdaPin, sclPin, i2c.SLOW) + else + MCP23017_id = i2c_id + end if (checkAddress(address) ~= true) or (checkDevice(address) ~= true) then MCP23017_DEVICE_OK = false @@ -256,14 +259,23 @@ local function readFromRegsiter(registerAddr) end local function writeIODIR(bReg, newByte) + if MCP23017_DEVICE_OK == false then + return nil + end return writeToRegsiter(getDirRegisterAddr(bReg), newByte) end local function writeGPIO(bReg, newByte) + if MCP23017_DEVICE_OK == false then + return nil + end return writeToRegsiter(getGPIORegisterAddr(bReg), newByte) end local function readGPIO(bReg) + if MCP23017_DEVICE_OK == false then + return nil + end return readFromRegsiter(getGPIORegisterAddr(bReg)) end From b77d8659cfbc72f59d9679e75a56017be2ebb2f1 Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 22:12:31 +0200 Subject: [PATCH 48/59] update setup syntax in doc --- docs/lua-modules/mcp23017.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index f57af55b0b..1620a00aaa 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -36,7 +36,7 @@ Then this function will establish the connection. Automatically resets the device state (see `mcp23017.reset()`) #### Syntax -`mcp23017.setup(address, customSCL, customSDA)` +`mcp23017.setup(address, i2c_id)` #### Parameter - `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) From e0bd9a49fd023ad63a4888484042680c9fcae33c Mon Sep 17 00:00:00 2001 From: plomi Date: Sun, 5 Jul 2020 09:24:43 +0200 Subject: [PATCH 49/59] changing mcp23017 module to factory style --- lua_modules/mcp23017/mcp23017.lua | 220 ++++++++++++++---------------- 1 file changed, 102 insertions(+), 118 deletions(-) diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index ec9d4cabd3..38eb4ec876 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -24,16 +24,14 @@ local issetBit = bit.isset local setBit = bit.set local clearBit = bit.clear -local MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) +-- MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) -- MCP23017_SDA = 2 -- D2/GPIO 4 -- MCP23017_SCL = 1 -- D1/GPIO 5 -local OUTPUT = false -local INPUT = true -local GPA = false -local GPB = true -local HIGH = true -local LOW = false + +-- metatable +local mcp23017 = {} +mcp23017.__index = mcp23017 -- registers (not used registers are commented out) local MCP23017_IODIRA = 0x00 @@ -65,24 +63,20 @@ local MCP23017_OLATA = 0x14 local MCP23017_OLATB = 0x15 ]] --- internal -local MCP23017_id = 0 -local MCP23017_DEVICE_OK = false - -- check device is available on address -local function checkDevice(address) - i2c.start(MCP23017_id) - local response = i2c.address(MCP23017_id, address, i2c.TRANSMITTER) - i2c.stop(MCP23017_id) +function mcp23017:checkDevice() + i2c.start(self.i2cId) + local response = i2c.address(self.i2cId, self.address, i2c.TRANSMITTER) + i2c.stop(self.i2cId) if response ~= true then - print("MCP23017 device on " .. string.format('0x%02X', address) .. " not found") + print("MCP23017 device on " .. string.format('0x%02X', self.address) .. " not found") end return response end -- check device address (0x20 to 0x27) -local function checkAddress(address) - local addr = tonumber(address) +function mcp23017:checkAddress() + local addr = tonumber(self.address) if (addr > 31 and addr < 40) then return true else @@ -92,30 +86,30 @@ local function checkAddress(address) end -- write byte -local function writeByte(registerAddr, val) - i2c.start(MCP23017_id) - i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) - i2c.write(MCP23017_id, registerAddr) - i2c.write(MCP23017_id, val) - i2c.stop(MCP23017_id) +function mcp23017:writeByte(registerAddr, val) + i2c.start(self.i2cId) + i2c.address(self.i2cId, self.address, i2c.TRANSMITTER) + i2c.write(self.i2cId, registerAddr) + i2c.write(self.i2cId, val) + i2c.stop(self.i2cId) end -- read byte -local function readByte(registerAddr) - i2c.start(MCP23017_id) - i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) - i2c.write(MCP23017_id, registerAddr) - i2c.stop(MCP23017_id) - i2c.start(MCP23017_id) - i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.RECEIVER) - local data = i2c.read(MCP23017_id, 1) - i2c.stop(MCP23017_id) +function mcp23017:readByte(registerAddr) + i2c.start(self.i2cId) + i2c.address(self.i2cId, self.address, i2c.TRANSMITTER) + i2c.write(self.i2cId, registerAddr) + i2c.stop(self.i2cId) + i2c.start(self.i2cId) + i2c.address(self.i2cId, self.address, i2c.RECEIVER) + local data = i2c.read(self.i2cId, 1) + i2c.stop(self.i2cId) return string.byte(data) end -- get IO dir register -local function getDirRegisterAddr(bReg) - if bReg == GPB then +function mcp23017:getDirRegisterAddr(bReg) + if bReg == self.GPB then return MCP23017_IODIRB else return MCP23017_IODIRA @@ -123,8 +117,8 @@ local function getDirRegisterAddr(bReg) end -- get GPIO register address -local function getGPIORegisterAddr(bReg) - if bReg == GPB then +function mcp23017:getGPIORegisterAddr(bReg) + if bReg == self.GPB then return MCP23017_GPIOB else return MCP23017_GPIOA @@ -132,7 +126,7 @@ local function getGPIORegisterAddr(bReg) end -- check pin is in range -local function checkPinIsInRange(pin) +function mcp23017:checkPinIsInRange(pin) if pin > 7 or pin < 0 then print("The pin must be between 0 and 7") return nil @@ -141,20 +135,20 @@ local function checkPinIsInRange(pin) end -- setup internal pullup -local function setInternalPullUp(bReg, iByte) - if bReg == GPB then - writeByte(MCP23017_DEFVALB, iByte) +function mcp23017:setInternalPullUp(bReg, iByte) + if bReg == self.GPB then + self:writeByte(MCP23017_DEFVALB, iByte) else - writeByte(MCP23017_DEFVALA, iByte) + self:writeByte(MCP23017_DEFVALA, iByte) end end -- set default GPIO mode -local function setDefaultMode(bReg, iByte) - writeByte(getDirRegisterAddr(bReg), iByte) +function mcp23017:setDefaultMode(bReg, iByte) + self:writeByte(self:getDirRegisterAddr(bReg), iByte) end -local function numberToBool(val) +function mcp23017:numberToBool(val) if val == 1 or val == true or val == '1' then return true else @@ -163,143 +157,133 @@ local function numberToBool(val) end -- reset gpio mode -local function reset() +function mcp23017:reset() -- all to input - setDefaultMode(GPA, 0xFF) - setDefaultMode(GPB, 0xFF) + self:setDefaultMode(self.GPA, 0xFF) + self:setDefaultMode(self.GPB, 0xFF) end -- setup device -local function setup(address, i2c_id, sclPin, sdaPin) - - MCP23017_ADDRESS = string.format('0x%02X', address) - - if sclPin ~= nil and sdaPin ~= nil then - i2c.setup(i2c_id, sdaPin, sclPin, i2c.SLOW) - else - MCP23017_id = i2c_id - end +function mcp23017:setup(address, i2cId) - if (checkAddress(address) ~= true) or (checkDevice(address) ~= true) then - MCP23017_DEVICE_OK = false + self.address = string.format('0x%02X', address) + self.i2cId = i2cId + if (self:checkAddress() ~= true) or (self:checkDevice() ~= true) then + self.deviceOk = false return 0 else - MCP23017_DEVICE_OK = true - reset() + self.deviceOk = true + self:reset() return 1 end end -- set mode for a pin -local function setMode(bReg, pin, mode) - if MCP23017_DEVICE_OK == false then +function mcp23017:setMode(bReg, pin, mode) + if self.deviceOk == false then return nil end - local inReq = getDirRegisterAddr(bReg) - local inPin = checkPinIsInRange(pin) - local response = readByte(inReq) + local inReq = self:getDirRegisterAddr(bReg) + local inPin = self:checkPinIsInRange(pin) + local response = self:readByte(inReq) local newState - if numberToBool(mode) == OUTPUT then + if self:numberToBool(mode) == self.OUTPUT then newState = clearBit(response, inPin) else newState = setBit(response, inPin) end - writeByte(inReq, newState) + self:writeByte(inReq, newState) return true end -- set pin to low or high -local function setPin(bReg, pin, state) - if MCP23017_DEVICE_OK == false then +function mcp23017:setPin(bReg, pin, state) + if self.deviceOk == false then return nil end - local inReq = getGPIORegisterAddr(bReg) - local inPin = checkPinIsInRange(pin) - local response = readByte(inReq) + local inReq = self:getGPIORegisterAddr(bReg) + local inPin = self:checkPinIsInRange(pin) + local response = self:readByte(inReq) local newState - if numberToBool(state) == HIGH then + if self:numberToBool(state) == self.HIGH then newState = setBit(response, inPin) else newState = clearBit(response, inPin) end - writeByte(inReq, newState) + self:writeByte(inReq, newState) return true end -- read pin input -local function getPinState(bReg, pin) - if MCP23017_DEVICE_OK == false then +function mcp23017:getPinState(bReg, pin) + if self.deviceOk == false then return nil end - local inReq = getGPIORegisterAddr(bReg) - local inPin = checkPinIsInRange(pin) - local response = readByte(inReq) + local inReq = self:getGPIORegisterAddr(bReg) + local inPin = self:checkPinIsInRange(pin) + local response = self:readByte(inReq) return issetBit(response, inPin) end -local function writeToRegsiter(registerAddr, newByte) - if MCP23017_DEVICE_OK == false then +function mcp23017:writeToRegister(registerAddr, newByte) + if self.deviceOk == false then return nil end - return writeByte(registerAddr, newByte) + return self:writeByte(registerAddr, newByte) end -local function readFromRegsiter(registerAddr) - if MCP23017_DEVICE_OK == false then +function mcp23017:readFromRegister(registerAddr) + if self.deviceOk == false then return nil end - return readByte(registerAddr) + return self:readByte(registerAddr) end -local function writeIODIR(bReg, newByte) - if MCP23017_DEVICE_OK == false then +function mcp23017:writeIODIR(bReg, newByte) + if self.deviceOk == false then return nil end - return writeToRegsiter(getDirRegisterAddr(bReg), newByte) + return self:writeToRegister(self:getDirRegisterAddr(bReg), newByte) end -local function writeGPIO(bReg, newByte) - if MCP23017_DEVICE_OK == false then +function mcp23017:writeGPIO(bReg, newByte) + if self.deviceOk == false then return nil end - return writeToRegsiter(getGPIORegisterAddr(bReg), newByte) + return self:writeToRegister(self:getGPIORegisterAddr(bReg), newByte) end -local function readGPIO(bReg) - if MCP23017_DEVICE_OK == false then +function mcp23017:readGPIO(bReg) + if self.deviceOk == false then return nil end - return readFromRegsiter(getGPIORegisterAddr(bReg)) + return self:readFromRegister(self:getGPIORegisterAddr(bReg)) +end + +return function(address, i2cId) + local self = {} + setmetatable(self, mcp23017) + + -- defaults + self.deviceOK = false + self.i2cId = 0 + self.address = nil + self.OUTPUT = false + self.INPUT = true + self.GPA = false + self.GPB = true + self.HIGH = true + self.LOW = false + + self:setup(address, i2cId) + return self end --- Set module name as parameter of require and rgetGPIORegisterAddreturn module table -local M = { - OUTPUT = OUTPUT, - INPUT = INPUT, - GPA = GPA, - GPB = GPB, - HIGH = HIGH, - LOW = LOW, - checkDevice = checkDevice, - setup = setup, - setMode = setMode, - setPin = setPin, - getPinState = getPinState, - reset = reset, - setInternalPullUp = setInternalPullUp, - writeIODIR = writeIODIR, - writeGPIO = writeGPIO, - readGPIO = readGPIO, -} - -local moduleName = ... -_G[moduleName or 'mcp23017'] = M -return M From 6766acbca4aa1a316eaeb005a95afd42b0659911 Mon Sep 17 00:00:00 2001 From: plomi Date: Sun, 5 Jul 2020 09:30:49 +0200 Subject: [PATCH 50/59] mcp23017 module: update example and docs for factory style --- docs/lua-modules/mcp23017.md | 61 +++++++++++----------- lua_examples/mcp23017/mcp23017_example.lua | 26 ++++----- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index 1620a00aaa..35bf91e84f 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -23,7 +23,7 @@ The numbers are for each register GPIO A and GPIO B. ### Require ```lua -mcp23017 = require("mcp23017") +mcp = require "mcp23017" ``` ## Example Script @@ -33,16 +33,14 @@ The example script can be found [here](../../lua_examples/mcp23017/mcp23017_exam Configures the address of the module and tests the connection to the i2c bus. The i2c id is required for an existing i2c interface, alternatively the sda and scl pins can be specified. Then this function will establish the connection. -Automatically resets the device state (see `mcp23017.reset()`) +Automatically resets the device state (see `mcp23017:reset()`) #### Syntax -`mcp23017.setup(address, i2c_id)` +`mcp23017:setup(address, i2c_id)` #### Parameter - `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) - `i2c_id` id for the i2c bus connection (i2c.setup separately) -- `customSCL` (optional) Pin for i²c SCL Signal, default: GPIO 5, Pin 1 -- `customSDA` (optional) Pin for i²c SDA Signal, default: GPIO 4, Pin 2 #### Return `true` if device found, otherwise `false`. @@ -53,22 +51,23 @@ Automatically resets the device state (see `mcp23017.reset()`) #### Example ```lua -local mcp23017 = require('mcp23017') +local mcp23017 = require "mcp23017" local address = 0x20 local cSCL = 1 local cSDA = 2 -local cID = 0 +local i2c_instance = 0 -i2c.setup(cID, cSDA, cSCL, i2c.SLOW) -mcp23017.setup(address, cID) +-- setup i2c bus and create instance for mcp23017 (assigned to mcp) +i2c.setup(i2c_instance, cSDA, cSCL, i2c.SLOW) +local mcp = mcp23017(address, i2c_instance) ``` ## setMode() Set the mode of a single channel. This can be OUTPUT or INPUT. #### Syntax -`mcp23017.setMode(register, pin, mode)` +`mcp23017:setMode(register, pin, mode)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -81,16 +80,16 @@ Set the mode of a single channel. This can be OUTPUT or INPUT. #### Example ```lua -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) +mcp:setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) +mcp:setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) +mcp:setMode(mcp23017.GPB, 1, mcp23017.INPUT) ``` ## setPin() Set the state of a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.setMode(register, pin, state)` +`mcp23017:setMode(register, pin, state)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -103,16 +102,16 @@ Set the state of a single channel. This can be HIGH or LOW. #### Example ```lua -- set pin 7 to high (GPA7) -mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) +mcp:setPin(mcp23017.GPA, 7, mcp23017.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) +mcp:setPin(mcp23017.GPB, 0, mcp23017.LOW) ``` ## getPinState() get the state for a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.getPinState(register, pin)` +`mcp23017:getPinState(register, pin)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -124,7 +123,7 @@ get the state for a single channel. This can be HIGH or LOW. #### Example ```lua -- get the state for pin 9 (GPB1) -print(mcp23017.getPinState(mcp23017.GPB, 1)) +print(mcp:getPinState(mcp23017.GPB, 1)) ``` ## reset() @@ -133,7 +132,7 @@ All channels are set to input. This function can be used for a panic program. #### Syntax -`mcp23017.reset()` +`mcp23017:reset()` #### Parameter None @@ -144,14 +143,14 @@ None #### Example ```lua -- reset the mcp23017 to startup defaults -mcp23017.reset() +mcp:reset() ``` ## setInternalPullUp() Enable or disable the internal pullup resistors. #### Syntax -`mcp23017.setInternalPullUp(register, byte)` +`mcp23017:setInternalPullUp(register, byte)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -163,9 +162,9 @@ None #### Example ```lua -- enable all pullup resistors for GPA -print(mcp23017.setInternalPullUp(mcp23017.GPA, 0xFF)) +print(mcp:setInternalPullUp(mcp23017.GPA, 0xFF)) -- disable all pullup resistors for GPA -print(mcp23017.setInternalPullUp(mcp23017.GPA, 0x00)) +print(mcp:setInternalPullUp(mcp23017.GPA, 0x00)) ``` ## writeIODIR() @@ -173,7 +172,7 @@ Setup the mode of the channels with a whole byte. #### Syntax -`mcp23017.writeIODIR(register, byte)` +`mcp23017:writeIODIR(register, byte)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -185,16 +184,16 @@ None #### Example ```lua -- set all GPA to input -print(mcp23017.writeIODIR(mcp23017.GPA, 0xFF)) +print(mcp:writeIODIR(mcp23017.GPA, 0xFF)) -- set all GPA to output -print(mcp23017.writeIODIR(mcp23017.GPA, 0x00)) +print(mcp:writeIODIR(mcp23017.GPA, 0x00)) ``` ## writeGPIO() Setup the output state of the channels with a whole byte. #### Syntax -`mcp23017.writeGPIO(register, byte)` +`mcp23017:writeGPIO(register, byte)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -206,16 +205,16 @@ None #### Example ```lua -- set all GPA to HIGH -print(mcp23017.writeGPIO(mcp23017.GPA, 0xFF)) +print(mcp:writeGPIO(mcp23017.GPA, 0xFF)) -- set all GPA to LOW -print(mcp23017.writeGPIO(mcp23017.GPA, 0x00)) +print(mcp:writeGPIO(mcp23017.GPA, 0x00)) ``` ## readGPIO() Read the input states of the channels with a whole byte. #### Syntax -`mcp23017.readGPIO(register)` +`mcp23017:readGPIO(register)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -226,6 +225,6 @@ byte with states #### Example ```lua -- get states for GPA -print(mcp23017.readGPIO(mcp23017.GPA)) +print(mcp:readGPIO(mcp23017.GPA)) ``` diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua index b59abc460a..122f279c6d 100644 --- a/lua_examples/mcp23017/mcp23017_example.lua +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -20,7 +20,7 @@ ]] -- initialize module -local mcp23017 = require('mcp23017') +local mcp23017 = require "mcp23017" -- set the address for MCP23017 local address = 0x20 @@ -33,9 +33,9 @@ local cSDA = 2 local i2cId = 0 --- setup i2c bus and mcp23017 +-- setup i2c bus and create instance for mcp23017 (assigned to mcp) i2c.setup(i2cId, cSDA, cSCL, i2c.SLOW) -mcp23017.setup(address, i2cId) +local mcp = mcp23017(address, i2cId) --[[ @@ -45,9 +45,9 @@ mcp23017.setup(address, i2cId) ]] -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) +mcp:setMode(mcp.GPA, 7, mcp.OUTPUT) +mcp:setMode(mcp.GPB, 0, mcp.OUTPUT) +mcp:setMode(mcp.GPB, 1, mcp.INPUT) @@ -58,9 +58,9 @@ mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) ]] -- set pin 7 to high (GPA7) -mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) +mcp:setPin(mcp.GPA, 7, mcp.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) +mcp:setPin(mcp.GPB, 0, mcp.LOW) @@ -74,16 +74,16 @@ mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) local currentPin = 6 local currentState = false -mcp23017.setMode(mcp23017.GPA, currentPin, mcp23017.OUTPUT) +mcp:setMode(mcp.GPA, currentPin, mcp.OUTPUT) tmr.create():alarm(1000, tmr.ALARM_AUTO, function() if currentState == true then -- print("set to low") - mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.LOW) + mcp:setPin(mcp.GPA, currentPin, mcp.LOW) currentState = false else -- print("set to high") - mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.HIGH) + mcp:setPin(mcp.GPA, currentPin, mcp.HIGH) currentState = true end end) @@ -100,11 +100,11 @@ end) -- read input register tmr.create():alarm(7000, tmr.ALARM_AUTO, function() - local a = mcp23017.readGPIO(mcp23017.GPA) + local a = mcp:readGPIO(mcp.GPA) print(" ") print("GPIO A input states: " .. a) - local b = mcp23017.readGPIO(mcp23017.GPB) + local b = mcp:readGPIO(mcp.GPB) print("GPIO B input states: " .. b) print(" ") end) From 90258c465f53c043eaf02359bb8912b08f8af640 Mon Sep 17 00:00:00 2001 From: Marcel P <32096029+plomi-net@users.noreply.github.com> Date: Sun, 5 Jul 2020 10:35:20 +0200 Subject: [PATCH 51/59] Delete telnet_pipe.lua --- lua_examples/telnet/telnet_pipe.lua | 69 ----------------------------- 1 file changed, 69 deletions(-) delete mode 100644 lua_examples/telnet/telnet_pipe.lua diff --git a/lua_examples/telnet/telnet_pipe.lua b/lua_examples/telnet/telnet_pipe.lua deleted file mode 100644 index e33be27763..0000000000 --- a/lua_examples/telnet/telnet_pipe.lua +++ /dev/null @@ -1,69 +0,0 @@ ---[[ A telnet server T. Ellison, June 2019 - -This version of the telnet server demonstrates the use of the new stdin and stout -pipes, which is a C implementation of the Lua fifosock concept moved into the -Lua core. These two pipes are referenced in the Lua registry. - -]] ---luacheck: no unused args - -local M = {} -local modname = ... -local function telnet_session(socket) - local node = node - local stdout - - local function output_CB(opipe) -- upval: socket - stdout = opipe - local rec = opipe:read(1400) - if rec and #rec > 0 then socket:send(rec) end - return false -- don't repost as the on:sent will do this - end - - local function onsent_CB(skt) -- upval: stdout - local rec = stdout:read(1400) - if rec and #rec > 0 then skt:send(rec) end - end - - local function disconnect_CB(skt) -- upval: socket, stdout - node.output() - socket, stdout = nil, nil -- set upvals to nl to allow GC - end - - node.output(output_CB, 0) - socket:on("receive", function(_,rec) node.input(rec) end) - socket:on("sent", onsent_CB) - socket:on("disconnection", disconnect_CB) - print(("Welcome to NodeMCU world (%d mem free, %s)"):format( - node.heap(), wifi.sta.getip())) -end - -function M.open(this, ssid, pwd, port) - local tmr, wifi, uwrite = tmr, wifi, uart.write - if ssid then - wifi.setmode(wifi.STATION, false) - wifi.sta.config { ssid = ssid, pwd = pwd, save = false } - end - local t = tmr.create() - t:alarm(500, tmr.ALARM_AUTO, function() - if (wifi.sta.status() == wifi.STA_GOTIP) then - t:unregister() - t=nil - print(("Telnet server started (%d mem free, %s)"):format( - node.heap(), wifi.sta.getip())) - M.svr = net.createServer(net.TCP, 180) - M.svr:listen(port or 23, telnet_session) - else - uwrite(0,".") - end - end) -end - -function M.close(this) - if this.svr then this.svr:close() end - package.loaded[modname] = nil -end - -return M - - From e653d9484fba6a39938d6242825fdb4d661001f8 Mon Sep 17 00:00:00 2001 From: plomi Date: Fri, 10 Apr 2020 20:36:48 +0200 Subject: [PATCH 52/59] adding mcp23017 support as a lua module --- docs/lua-modules/mcp23017.md | 234 ++++++++++++++++ lua_examples/mcp23017/mcp23017_example.lua | 112 ++++++++ lua_modules/mcp23017/README.md | 3 + lua_modules/mcp23017/mcp23017.lua | 299 +++++++++++++++++++++ mkdocs.yml | 1 + 5 files changed, 649 insertions(+) create mode 100644 docs/lua-modules/mcp23017.md create mode 100644 lua_examples/mcp23017/mcp23017_example.lua create mode 100644 lua_modules/mcp23017/README.md create mode 100644 lua_modules/mcp23017/mcp23017.lua diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md new file mode 100644 index 0000000000..2cf2d350dd --- /dev/null +++ b/docs/lua-modules/mcp23017.md @@ -0,0 +1,234 @@ +# Lua MCP23017 Module for NodeMCU / ESP8266 + +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2020-04-10 | [Marcel P.](https://github.com/plomi-net) | [Marcel P.](https://github.com/plomi-net) | [mcp23017.lua](../../lua_modules/mcp23017/mcp23017.lua) | + + +This Lua module provides access to the MCP23017 module. + +The [MCP23017](http://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf) is a port expander and provides 16 channels for inputs and outputs. +Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2). + +Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B. +A single pin can be set or a whole byte. + +The numbering of the individual pins starts at 0 and ends with 15. +The numbers up to 7 are on register GPIO A and from 8 to 15 on GPIO B. + + +!!! important + The module requires `i2c` and `bit` C module built into firmware. + + +### Require +```lua +mcp23017 = require("mcp23017") +``` + +## Example Script +The example script can be found [here](../../lua_examples/mcp23017/mcp23017_example.lua) + +## setup() +Configures the interface and sets the i2c pins and the address of the device. +Automatically resets the device state (see `mcp23017.reset()`) + +#### Syntax +`mcp23017.setup(address, customSCL, customSDA)` + +#### Parameter +- `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) +- `customSCL` Pin for i²c SCL Signal, default: GPIO 5, Pin 1 +- `customSDA` Pin for i²c SDA Signal, default: GPIO 4, Pin 2 + +#### Return +`true` if device found, otherwise `false`. + +#### possible Errors +- `MCP23017 device on address not found` +- `MCP23017 address is out of range` + +#### Example +```lua +local mcp23017 = require('mcp23017') + +local address = 0x20 +local cSCL = 1 +local cSDA = 2 + +mcp23017.setup(address, cSCL,cSDA) +``` + +## setMode() +Set the mode of a single channel. This can be OUTPUT or INPUT. + +#### Syntax +`mcp23017.setMode(pin, mode)` + +#### Parameter +- `pin` the number to be set for the channel (0-15) +- `mode` the mode for the channel. This can be `mcp23017.INPUT` or `mcp23017.OUTPUT` + +#### Return +`true`, in case of error `nil`. + +#### Example +```lua +-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input +mcp23017.setMode(7, mcp23017.OUTPUT) +mcp23017.setMode(8, mcp23017.OUTPUT) +mcp23017.setMode(9, mcp23017.INPUT) +``` + +## setPin() +Set the state of a single channel. This can be HIGH or LOW. + +#### Syntax +`mcp23017.setMode(pin, state)` + +#### Parameter +- `pin` the number to be set for the channel (0-15) +- `state` the state for the channel. This can be `mcp23017.HIGH` or `mcp23017.LOW` + +#### Return +`true`, in case of error `nil`. + +#### Example +```lua +-- set pin 7 to high (GPA7) +mcp23017.setPin(7, mcp23017.HIGH) +-- set pin 8 to low (GPB0) +mcp23017.setPin(8, mcp23017.LOW) +``` + +## getPinState() +get the state for a single channel. This can be HIGH or LOW. + +#### Syntax +`mcp23017.getPinState(pin)` + +#### Parameter +- `pin` the number for which a state is to be queried (0-15) + +#### Return +`true` for HIGH, `false` for LOW, in case of error `nil`. + +#### Example +```lua +-- get the state for pin 9 (GPB1) +print(mcp23017.getPinState(9)) +``` + +## reset() +By calling this function, a safe state is established. +All channels are set to input and internal pullup resistors are disabled. +This function can be used for a panic program. + +#### Syntax +`mcp23017.reset()` + +#### Parameter +None + +#### Return +None + +#### Example +```lua +-- reset the mcp23017 to startup defaults +mcp23017.reset() +``` + +## setInternalPullUp() +Enable or disable the internal pullup resistors. +Same for register A and B +Please note that the setting is overwritten with reset() + +#### Syntax +`mcp23017.setInternalPullUp(byte)` + +#### Parameter +- `byte` byte to set the pullup resistors + +#### Return +None + +#### Example +```lua +-- enable all pullup resistors +print(mcp23017.setInternalPullUp(0xFF)) +-- disable all pullup resistors (default) +print(mcp23017.setInternalPullUp(0x00)) +``` + +## writeIODIRA() +Setup the mode of the channels with a whole byte. In this case for register A. + + +#### Syntax +`mcp23017.writeIODIRA(byte)` + +#### Parameter +- `byte` byte to set the mode for all channels for this register + +#### Return +None + +#### Example +```lua +-- set all GPA to input +print(mcp23017.writeIODIRA(0xFF)) +-- set all GPA to output +print(mcp23017.writeIODIRA(0x00)) +``` + +## writeIODIRB() +Setup the mode of the channels with a whole byte. In this case for register B. +The function is equivalent to `mcp23017.writeIODIRA()` + +## writeGPIOA() +Setup the output state of the channels with a whole byte. In this case for register A. + +#### Syntax +`mcp23017.writeGPIOA(byte)` + +#### Parameter +- `byte` byte to set the state for all channels for this register + +#### Return +None + +#### Example +```lua +-- set all GPA to HIGH +print(mcp23017.writeGPIOA(0xFF)) +-- set all GPA to LOW +print(mcp23017.writeGPIOA(0x00)) +``` + +## writeGPIOB() +Setup the output state of the channels with a whole byte. In this case for register B. +The function is equivalent to `mcp23017.writeGPIOA()` + +## readGPIOA() +Read the input states of the channels with a whole byte. In this case for register A. + +#### Syntax +`mcp23017.readGPIOA()` + +#### Parameter +None + +#### Return +byte with states + +#### Example +```lua +-- get states for GPA +print(mcp23017.readGPIOA()) +``` + +## readGPIOB() +Read the input states of the channels with a whole byte. In this case for register B. +The function is equivalent to `mcp23017.readGPIOA()` + diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua new file mode 100644 index 0000000000..b08e17efd4 --- /dev/null +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -0,0 +1,112 @@ +--[[ + + This example demonstrates how to use the different functions of the mcp23017 lua module. + + @author Marcel P. | Plomi.net + @github https://github.com/plomi-net + + @version 1.0.0 + +]] + + + + + +--[[ + + initialize and setup + +]] + +-- initialize module +local mcp23017 = require('mcp23017') + +-- set the address for MCP23017 +local address = 0x20 + +-- SCL pin = 1 = D1 / GPIO 5 (ESP8266) +local cSCL = 1 + +-- SDA pin = 2 = D2 / GPIO4 (ESP8266) +local cSDA = 2 + +-- setup mcp23017 +mcp23017.setup(address, cSCL, cSDA) + + +--[[ + + set output and input channels + +]] + +-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input +mcp23017.setMode(7, mcp23017.OUTPUT) +mcp23017.setMode(8, mcp23017.OUTPUT) +mcp23017.setMode(9, mcp23017.INPUT) + + + +--[[ + + set output channels to high and low + +]] + +-- set pin 7 to high (GPA7) +mcp23017.setPin(7, mcp23017.HIGH) +-- set pin 8 to low (GPB0) +mcp23017.setPin(8, mcp23017.LOW) + + + + +--[[ + + toggle pin 6 channel state every second (blinking) + +]] + +local currentPin = 6 +local currentState = false + +mcp23017.setMode(currentPin, mcp23017.OUTPUT) + +if not tmr.create():alarm(1000, tmr.ALARM_AUTO, function() + if currentState == true then + -- print("set to low") + mcp23017.setPin(currentPin, mcp23017.LOW) + currentState = false + else + -- print("set to high") + mcp23017.setPin(currentPin, mcp23017.HIGH) + currentState = true + end +end) then + print("Timer can't be created") +end + + + + + +--[[ + + read input channels and display every 7 seconds + +]] + +-- read input register +if not tmr.create():alarm(7000, tmr.ALARM_AUTO, function() + local a = mcp23017.readGPIOA() + print(" ") + print("GPIO A input states: " .. a) + + local b = mcp23017.readGPIOB() + print("GPIO B input states: " .. b) + print(" ") + +end) then + print("Timer can't be created") +end \ No newline at end of file diff --git a/lua_modules/mcp23017/README.md b/lua_modules/mcp23017/README.md new file mode 100644 index 0000000000..f6d6d8089c --- /dev/null +++ b/lua_modules/mcp23017/README.md @@ -0,0 +1,3 @@ +# MCP23017 Module + +Documentation for this Lua module is available in the [mcp23017.md](../../docs/lua-modules/mcp23017.md) file and in the [Official NodeMCU Documentation](https://nodemcu.readthedocs.io/) in `Lua Modules` section. diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua new file mode 100644 index 0000000000..c8e5010eb5 --- /dev/null +++ b/lua_modules/mcp23017/mcp23017.lua @@ -0,0 +1,299 @@ +--[[ + + This Lua module provides access to the MCP23017 module. + + The MCP23017 is a port expander and provides 16 channels for inputs and outputs. + Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2 Pins). + + Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B. + A single pin can be set or a whole byte. The numbering of the individual pins starts at 0 and ends with 15. + The numbers up to 7 are on register GPIO A and from 8 to 15 on GPIO B. + + The module requires `i2c` and `bit` C module built into firmware. + + + @author Marcel P. | Plomi.net + @github https://github.com/plomi-net + + @version 1.0.0 + +]] + +local i2c, string = i2c, string +local issetBit = bit.isset +local setBit = bit.set +local clearBit = bit.clear + +local MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) +-- MCP23017_SDA = 2 -- D2/GPIO 4 +-- MCP23017_SCL = 1 -- D1/GPIO 5 + +local OUTPUT = false +local INPUT = true +local HIGH = true +local LOW = false + +-- registers (not used registers are commented out) +local MCP23017_IODIRA = 0x00 +local MCP23017_IODIRB = 0x01 +local MCP23017_DEFVALA = 0x06 +local MCP23017_DEFVALB = 0x07 +local MCP23017_GPIOA = 0x12 +local MCP23017_GPIOB = 0x13 + +--[[ +local MCP23017_IPOLA = 0x02 +local MCP23017_IPOLB = 0x03 +local MCP23017_GPINTENA = 0x04 +local MCP23017_GPINTENB = 0x05 +local MCP23017_DEFVALA = 0x06 +local MCP23017_DEFVALB = 0x07 +local MCP23017_INTCONA = 0x08 +local MCP23017_INTCONB = 0x09 +local MCP23017_IOCON = 0x0A +local MCP23017_IOCON2 = 0x0B +local MCP23017_GPPUA = 0x0C +local MCP23017_GPPUB = 0x0D +local MCP23017_INTFA = 0x0E +local MCP23017_INTFB = 0x0F + +local MCP23017_INTCAPA = 0x10 +local MCP23017_INTCAPB = 0x11 +local MCP23017_OLATA = 0x14 +local MCP23017_OLATB = 0x15 +]] + +-- internal +local MCP23017_id = 0 +local MCP23017_SPEED = i2c.SLOW +local MCP23017_DEVICE_OK = false + +-- check device is available on address +local function checkDevice(address) + i2c.start(MCP23017_id) + local response = i2c.address(MCP23017_id, address, i2c.TRANSMITTER) + i2c.stop(MCP23017_id) + if response ~= true then + print("MCP23017 device on " .. string.format('0x%02X', address) .. " not found") + end + return response +end + +-- check device address (0x20 to 0x27) +local function checkAddress(address) + local addr = tonumber(address) + if (addr > 31 and addr < 40) then + return true + else + print("MCP23017 address is out of range") + return false + end +end + +-- write byte +local function writeByte(registerAddr, val) + i2c.start(MCP23017_id) + i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) + i2c.write(MCP23017_id, registerAddr) + i2c.write(MCP23017_id, val) + i2c.stop(MCP23017_id) +end + +-- read byte +local function readByte(registerAddr) + i2c.start(MCP23017_id) + i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) + i2c.write(MCP23017_id, registerAddr) + i2c.stop(MCP23017_id) + i2c.start(MCP23017_id) + i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.RECEIVER) + local data = i2c.read(MCP23017_id, 1) + i2c.stop(MCP23017_id) + return string.byte(data) +end + +-- get IO dir register +local function getDirRegisterAddr(pin) + if pin > 7 then + return MCP23017_IODIRB + else + return MCP23017_IODIRA + end +end + +-- get GPIO register address +local function getGPIORegisterAddr(pin) + if pin > 7 then + return MCP23017_GPIOB + else + return MCP23017_GPIOA + end +end + +-- convert pin number for A/B register +local function convertPin(pin) + if pin > 15 or pin < 0 then + print("The pin must be between 0 and 15") + return nil + end + return pin % 8 +end + +-- setup internal pullup +local function setInternalPullUp(iByte) + writeByte(MCP23017_DEFVALA, iByte) + writeByte(MCP23017_DEFVALB, iByte) +end + +-- set default GPIO mode +local function setDefaultMode(iByte) + writeByte(MCP23017_IODIRA, iByte) + writeByte(MCP23017_IODIRB, iByte) +end + +local function numberToBool(val) + if val == 1 or val == true or val == '1' then + return true + else + return false + end +end + +-- reset gpio mode and pullup +local function reset() + setDefaultMode(0xFF) -- all to input + setInternalPullUp(0x00) -- disable pullup +end + +-- setup device +local function setup(address, sclPin, sdaPin) + + MCP23017_ADDRESS = string.format('0x%02X', address) + + i2c.setup(MCP23017_id, sdaPin, sclPin, MCP23017_SPEED) + + if (checkAddress(address) ~= true) or (checkDevice(address) ~= true) then + MCP23017_DEVICE_OK = false + return 0 + else + MCP23017_DEVICE_OK = true + reset() + return 1 + end +end + +-- set mode for a pin +local function setMode(pin, mode) + if MCP23017_DEVICE_OK == false then + return nil + end + + local inReq = getDirRegisterAddr(pin) + local inPin = convertPin(pin) + local response = readByte(inReq) + local newState + + if numberToBool(mode) == OUTPUT then + newState = clearBit(response, inPin) + else + newState = setBit(response, inPin) + end + + writeByte(inReq, newState) + return true +end + +-- set pin to low or high +local function setPin(pin, state) + if MCP23017_DEVICE_OK == false then + return nil + end + + local inReq = getGPIORegisterAddr(pin) + local inPin = convertPin(pin) + local response = readByte(inReq) + local newState + + if numberToBool(state) == HIGH then + newState = setBit(response, inPin) + else + newState = clearBit(response, inPin) + end + + writeByte(inReq, newState) + return true +end + +-- read pin input +local function getPinState(pin) + if MCP23017_DEVICE_OK == false then + return nil + end + + local inReq = getGPIORegisterAddr(pin) + local inPin = convertPin(pin) + local response = readByte(inReq) + return issetBit(response, inPin) +end + +local function writeToRegsiter(registerAddr, newByte) + if MCP23017_DEVICE_OK == false then + return nil + end + return writeByte(registerAddr, newByte) +end + +local function readFromRegsiter(registerAddr) + if MCP23017_DEVICE_OK == false then + return nil + end + return readByte(registerAddr) +end + +local function writeIODIRA(newByte) + return writeToRegsiter(MCP23017_IODIRA, newByte) +end + +local function writeIODIRB(newByte) + return writeToRegsiter(MCP23017_IODIRB, newByte) +end + +local function writeGPIOA(newByte) + return writeToRegsiter(MCP23017_GPIOA, newByte) +end + +local function writeGPIOB(newByte) + return writeToRegsiter(MCP23017_GPIOB, newByte) +end + +local function readGPIOA() + return readFromRegsiter(MCP23017_GPIOA) +end + +local function readGPIOB() + return readFromRegsiter(MCP23017_GPIOB) +end + +-- Set module name as parameter of require and return module table +local M = { + HIGH = HIGH, + LOW = LOW, + OUTPUT = OUTPUT, + INPUT = INPUT, + checkDevice = checkDevice, + setup = setup, + setMode = setMode, + setPin = setPin, + getPinState = getPinState, + reset = reset, + setInternalPullUp = setInternalPullUp, + writeIODIRA = writeIODIRA, + writeIODIRB = writeIODIRB, + writeGPIOA = writeGPIOA, + writeGPIOB = writeGPIOB, + readGPIOA = readGPIOA, + readGPIOB = readGPIOB, +} + +_G[modname or 'mcp23017'] = M +return M diff --git a/mkdocs.yml b/mkdocs.yml index ff40812943..ae49be4f4a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -57,6 +57,7 @@ pages: - 'liquidcrystal': 'lua-modules/liquidcrystal.md' - 'lm92': 'lua-modules/lm92.md' - 'mcp23008': 'lua-modules/mcp23008.md' + - 'mcp23017': 'lua-modules/mcp23017.md' - 'redis': 'lua-modules/redis.md' - 'telnet': 'lua-modules/telnet.md' - 'yeelink': 'lua-modules/yeelink.md' From d88fcbfe56d7bb1d8269a65c8d5e2483dca461f6 Mon Sep 17 00:00:00 2001 From: plomi Date: Fri, 10 Apr 2020 20:43:18 +0200 Subject: [PATCH 53/59] adding mcp23017 support as a lua module --- lua_modules/mcp23017/mcp23017.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index c8e5010eb5..777d754bce 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -295,5 +295,6 @@ local M = { readGPIOB = readGPIOB, } -_G[modname or 'mcp23017'] = M +local moduleName = ... +_G[moduleName or 'mcp23017'] = M return M From 5c3774cee02de3a4456228b96af006cf038b6c92 Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 08:06:51 +0200 Subject: [PATCH 54/59] Correcting functions for a/b register, update doc and remove unnecessary checks in example --- docs/lua-modules/mcp23017.md | 84 ++++++++++++-------------- lua_modules/mcp23017/mcp23017.lua | 99 ++++++++++++++----------------- 2 files changed, 84 insertions(+), 99 deletions(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index 2cf2d350dd..3054d62976 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -13,8 +13,8 @@ Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2 Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B. A single pin can be set or a whole byte. -The numbering of the individual pins starts at 0 and ends with 15. -The numbers up to 7 are on register GPIO A and from 8 to 15 on GPIO B. +The numbering of the individual pins starts at 0 and ends with 7. +The numbers are for each register GPIO A and GPIO B. !!! important @@ -63,9 +63,10 @@ mcp23017.setup(address, cSCL,cSDA) Set the mode of a single channel. This can be OUTPUT or INPUT. #### Syntax -`mcp23017.setMode(pin, mode)` +`mcp23017.setMode(register, pin, mode)` #### Parameter +- `register` the side of channels (GPA or GPB) - `pin` the number to be set for the channel (0-15) - `mode` the mode for the channel. This can be `mcp23017.INPUT` or `mcp23017.OUTPUT` @@ -75,18 +76,19 @@ Set the mode of a single channel. This can be OUTPUT or INPUT. #### Example ```lua -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(7, mcp23017.OUTPUT) -mcp23017.setMode(8, mcp23017.OUTPUT) -mcp23017.setMode(9, mcp23017.INPUT) +mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) ``` ## setPin() Set the state of a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.setMode(pin, state)` +`mcp23017.setMode(register, pin, state)` #### Parameter +- `register` the side of channels (GPA or GPB) - `pin` the number to be set for the channel (0-15) - `state` the state for the channel. This can be `mcp23017.HIGH` or `mcp23017.LOW` @@ -96,18 +98,19 @@ Set the state of a single channel. This can be HIGH or LOW. #### Example ```lua -- set pin 7 to high (GPA7) -mcp23017.setPin(7, mcp23017.HIGH) +mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(8, mcp23017.LOW) +mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) ``` ## getPinState() get the state for a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.getPinState(pin)` +`mcp23017.getPinState(register, pin)` #### Parameter +- `register` the side of channels (GPA or GPB) - `pin` the number for which a state is to be queried (0-15) #### Return @@ -116,12 +119,12 @@ get the state for a single channel. This can be HIGH or LOW. #### Example ```lua -- get the state for pin 9 (GPB1) -print(mcp23017.getPinState(9)) +print(mcp23017.getPinState(mcp23017.GPB, 1)) ``` ## reset() By calling this function, a safe state is established. -All channels are set to input and internal pullup resistors are disabled. +All channels are set to input. This function can be used for a panic program. #### Syntax @@ -141,13 +144,12 @@ mcp23017.reset() ## setInternalPullUp() Enable or disable the internal pullup resistors. -Same for register A and B -Please note that the setting is overwritten with reset() #### Syntax -`mcp23017.setInternalPullUp(byte)` +`mcp23017.setInternalPullUp(register, byte)` #### Parameter +- `register` the side of channels (GPA or GPB) - `byte` byte to set the pullup resistors #### Return @@ -155,20 +157,21 @@ None #### Example ```lua --- enable all pullup resistors -print(mcp23017.setInternalPullUp(0xFF)) --- disable all pullup resistors (default) -print(mcp23017.setInternalPullUp(0x00)) +-- enable all pullup resistors for GPA +print(mcp23017.setInternalPullUp(mcp23017.GPA, 0xFF)) +-- disable all pullup resistors for GPA +print(mcp23017.setInternalPullUp(mcp23017.GPA, 0x00)) ``` -## writeIODIRA() -Setup the mode of the channels with a whole byte. In this case for register A. +## writeIODIR() +Setup the mode of the channels with a whole byte. #### Syntax -`mcp23017.writeIODIRA(byte)` +`mcp23017.writeIODIR(register, byte)` #### Parameter +- `register` the side of channels (GPA or GPB) - `byte` byte to set the mode for all channels for this register #### Return @@ -177,22 +180,19 @@ None #### Example ```lua -- set all GPA to input -print(mcp23017.writeIODIRA(0xFF)) +print(mcp23017.writeIODIR(mcp23017.GPA, 0xFF)) -- set all GPA to output -print(mcp23017.writeIODIRA(0x00)) +print(mcp23017.writeIODIR(mcp23017.GPA, 0x00)) ``` -## writeIODIRB() -Setup the mode of the channels with a whole byte. In this case for register B. -The function is equivalent to `mcp23017.writeIODIRA()` - -## writeGPIOA() -Setup the output state of the channels with a whole byte. In this case for register A. +## writeGPIO() +Setup the output state of the channels with a whole byte. #### Syntax -`mcp23017.writeGPIOA(byte)` +`mcp23017.writeGPIO(register, byte)` #### Parameter +- `register` the side of channels (GPA or GPB) - `byte` byte to set the state for all channels for this register #### Return @@ -201,23 +201,19 @@ None #### Example ```lua -- set all GPA to HIGH -print(mcp23017.writeGPIOA(0xFF)) +print(mcp23017.writeGPIO(mcp23017.GPA, 0xFF)) -- set all GPA to LOW -print(mcp23017.writeGPIOA(0x00)) +print(mcp23017.writeGPIO(mcp23017.GPA, 0x00)) ``` -## writeGPIOB() -Setup the output state of the channels with a whole byte. In this case for register B. -The function is equivalent to `mcp23017.writeGPIOA()` - -## readGPIOA() -Read the input states of the channels with a whole byte. In this case for register A. +## readGPIO() +Read the input states of the channels with a whole byte. #### Syntax -`mcp23017.readGPIOA()` +`mcp23017.readGPIO(register)` #### Parameter -None +- `register` the side of channels (GPA or GPB) #### Return byte with states @@ -225,10 +221,6 @@ byte with states #### Example ```lua -- get states for GPA -print(mcp23017.readGPIOA()) +print(mcp23017.readGPIO(mcp23017.GPA)) ``` -## readGPIOB() -Read the input states of the channels with a whole byte. In this case for register B. -The function is equivalent to `mcp23017.readGPIOA()` - diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index 777d754bce..d0e393e7ca 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -30,6 +30,8 @@ local MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) local OUTPUT = false local INPUT = true +local GPA = false +local GPB = true local HIGH = true local LOW = false @@ -113,8 +115,8 @@ local function readByte(registerAddr) end -- get IO dir register -local function getDirRegisterAddr(pin) - if pin > 7 then +local function getDirRegisterAddr(bReg) + if bReg == GPB then return MCP23017_IODIRB else return MCP23017_IODIRA @@ -122,33 +124,35 @@ local function getDirRegisterAddr(pin) end -- get GPIO register address -local function getGPIORegisterAddr(pin) - if pin > 7 then +local function getGPIORegisterAddr(bReg) + if bReg == GPB then return MCP23017_GPIOB else return MCP23017_GPIOA end end --- convert pin number for A/B register -local function convertPin(pin) - if pin > 15 or pin < 0 then - print("The pin must be between 0 and 15") +-- check pin is in range +local function checkPinIsInRange(pin) + if pin > 7 or pin < 0 then + print("The pin must be between 0 and 7") return nil end - return pin % 8 + return pin end -- setup internal pullup -local function setInternalPullUp(iByte) - writeByte(MCP23017_DEFVALA, iByte) - writeByte(MCP23017_DEFVALB, iByte) +local function setInternalPullUp(bReg, iByte) + if bReg == GPB then + writeByte(MCP23017_DEFVALB, iByte) + else + writeByte(MCP23017_DEFVALA, iByte) + end end -- set default GPIO mode -local function setDefaultMode(iByte) - writeByte(MCP23017_IODIRA, iByte) - writeByte(MCP23017_IODIRB, iByte) +local function setDefaultMode(bReg, iByte) + writeByte(getDirRegisterAddr(bReg), iByte) end local function numberToBool(val) @@ -159,10 +163,11 @@ local function numberToBool(val) end end --- reset gpio mode and pullup +-- reset gpio mode local function reset() - setDefaultMode(0xFF) -- all to input - setInternalPullUp(0x00) -- disable pullup + -- all to input + setDefaultMode(GPA, 0xFF) + setDefaultMode(GPB, 0xFF) end -- setup device @@ -183,13 +188,13 @@ local function setup(address, sclPin, sdaPin) end -- set mode for a pin -local function setMode(pin, mode) +local function setMode(bReg, pin, mode) if MCP23017_DEVICE_OK == false then return nil end - local inReq = getDirRegisterAddr(pin) - local inPin = convertPin(pin) + local inReq = getDirRegisterAddr(bReg) + local inPin = checkPinIsInRange(pin) local response = readByte(inReq) local newState @@ -204,13 +209,13 @@ local function setMode(pin, mode) end -- set pin to low or high -local function setPin(pin, state) +local function setPin(bReg, pin, state) if MCP23017_DEVICE_OK == false then return nil end - local inReq = getGPIORegisterAddr(pin) - local inPin = convertPin(pin) + local inReq = getGPIORegisterAddr(bReg) + local inPin = checkPinIsInRange(pin) local response = readByte(inReq) local newState @@ -225,13 +230,13 @@ local function setPin(pin, state) end -- read pin input -local function getPinState(pin) +local function getPinState(bReg, pin) if MCP23017_DEVICE_OK == false then return nil end - local inReq = getGPIORegisterAddr(pin) - local inPin = convertPin(pin) + local inReq = getGPIORegisterAddr(bReg) + local inPin = checkPinIsInRange(pin) local response = readByte(inReq) return issetBit(response, inPin) end @@ -250,36 +255,27 @@ local function readFromRegsiter(registerAddr) return readByte(registerAddr) end -local function writeIODIRA(newByte) - return writeToRegsiter(MCP23017_IODIRA, newByte) -end - -local function writeIODIRB(newByte) - return writeToRegsiter(MCP23017_IODIRB, newByte) +local function writeIODIR(bReg, newByte) + return writeToRegsiter(getDirRegisterAddr(bReg), newByte) end -local function writeGPIOA(newByte) - return writeToRegsiter(MCP23017_GPIOA, newByte) +local function writeGPIO(bReg, newByte) + return writeToRegsiter(getGPIORegisterAddr(bReg), newByte) end -local function writeGPIOB(newByte) - return writeToRegsiter(MCP23017_GPIOB, newByte) +local function readGPIO(bReg) + return readFromRegsiter(getGPIORegisterAddr(bReg)) end -local function readGPIOA() - return readFromRegsiter(MCP23017_GPIOA) -end -local function readGPIOB() - return readFromRegsiter(MCP23017_GPIOB) -end - --- Set module name as parameter of require and return module table +-- Set module name as parameter of require and rgetGPIORegisterAddreturn module table local M = { - HIGH = HIGH, - LOW = LOW, OUTPUT = OUTPUT, INPUT = INPUT, + GPA = GPA, + GPB = GPB, + HIGH = HIGH, + LOW = LOW, checkDevice = checkDevice, setup = setup, setMode = setMode, @@ -287,12 +283,9 @@ local M = { getPinState = getPinState, reset = reset, setInternalPullUp = setInternalPullUp, - writeIODIRA = writeIODIRA, - writeIODIRB = writeIODIRB, - writeGPIOA = writeGPIOA, - writeGPIOB = writeGPIOB, - readGPIOA = readGPIOA, - readGPIOB = readGPIOB, + writeIODIR = writeIODIR, + writeGPIO = writeGPIO, + readGPIO = readGPIO, } local moduleName = ... From 8c5845e29b5e8335ebd132ad2d9a453275571051 Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 08:17:12 +0200 Subject: [PATCH 55/59] Correcting functions for a/b register, update doc and remove unnecessary checks in example --- lua_examples/mcp23017/mcp23017_example.lua | 33 +++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua index b08e17efd4..76b75a6fc1 100644 --- a/lua_examples/mcp23017/mcp23017_example.lua +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -42,9 +42,9 @@ mcp23017.setup(address, cSCL, cSDA) ]] -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(7, mcp23017.OUTPUT) -mcp23017.setMode(8, mcp23017.OUTPUT) -mcp23017.setMode(9, mcp23017.INPUT) +mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) @@ -55,9 +55,9 @@ mcp23017.setMode(9, mcp23017.INPUT) ]] -- set pin 7 to high (GPA7) -mcp23017.setPin(7, mcp23017.HIGH) +mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(8, mcp23017.LOW) +mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) @@ -71,21 +71,19 @@ mcp23017.setPin(8, mcp23017.LOW) local currentPin = 6 local currentState = false -mcp23017.setMode(currentPin, mcp23017.OUTPUT) +mcp23017.setMode(mcp23017.GPA, currentPin, mcp23017.OUTPUT) -if not tmr.create():alarm(1000, tmr.ALARM_AUTO, function() +tmr.create():alarm(1000, tmr.ALARM_AUTO, function() if currentState == true then -- print("set to low") - mcp23017.setPin(currentPin, mcp23017.LOW) + mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.LOW) currentState = false else -- print("set to high") - mcp23017.setPin(currentPin, mcp23017.HIGH) + mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.HIGH) currentState = true end -end) then - print("Timer can't be created") -end +end) @@ -98,15 +96,12 @@ end ]] -- read input register -if not tmr.create():alarm(7000, tmr.ALARM_AUTO, function() - local a = mcp23017.readGPIOA() +tmr.create():alarm(7000, tmr.ALARM_AUTO, function() + local a = mcp23017.readGPIO(mcp23017.GPA) print(" ") print("GPIO A input states: " .. a) - local b = mcp23017.readGPIOB() + local b = mcp23017.readGPIO(mcp23017.GPB) print("GPIO B input states: " .. b) print(" ") - -end) then - print("Timer can't be created") -end \ No newline at end of file +end) \ No newline at end of file From 2ac2f6300a27d3ed5354a94766f871e8d20833b7 Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 21:59:30 +0200 Subject: [PATCH 56/59] remove mandatory i2c setup from mcp setup function, add optional setup and require i2c id, update doc and example --- docs/lua-modules/mcp23017.md | 13 +++++++++---- lua_examples/mcp23017/mcp23017_example.lua | 9 ++++++--- lua_modules/mcp23017/mcp23017.lua | 18 +++++++++++++++--- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index 3054d62976..f57af55b0b 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -30,7 +30,9 @@ mcp23017 = require("mcp23017") The example script can be found [here](../../lua_examples/mcp23017/mcp23017_example.lua) ## setup() -Configures the interface and sets the i2c pins and the address of the device. +Configures the address of the module and tests the connection to the i2c bus. +The i2c id is required for an existing i2c interface, alternatively the sda and scl pins can be specified. +Then this function will establish the connection. Automatically resets the device state (see `mcp23017.reset()`) #### Syntax @@ -38,8 +40,9 @@ Automatically resets the device state (see `mcp23017.reset()`) #### Parameter - `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) -- `customSCL` Pin for i²c SCL Signal, default: GPIO 5, Pin 1 -- `customSDA` Pin for i²c SDA Signal, default: GPIO 4, Pin 2 +- `i2c_id` id for the i2c bus connection (i2c.setup separately) +- `customSCL` (optional) Pin for i²c SCL Signal, default: GPIO 5, Pin 1 +- `customSDA` (optional) Pin for i²c SDA Signal, default: GPIO 4, Pin 2 #### Return `true` if device found, otherwise `false`. @@ -55,8 +58,10 @@ local mcp23017 = require('mcp23017') local address = 0x20 local cSCL = 1 local cSDA = 2 +local cID = 0 -mcp23017.setup(address, cSCL,cSDA) +i2c.setup(cID, cSDA, cSCL, i2c.SLOW) +mcp23017.setup(address, cID) ``` ## setMode() diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua index 76b75a6fc1..b59abc460a 100644 --- a/lua_examples/mcp23017/mcp23017_example.lua +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -31,8 +31,11 @@ local cSCL = 1 -- SDA pin = 2 = D2 / GPIO4 (ESP8266) local cSDA = 2 --- setup mcp23017 -mcp23017.setup(address, cSCL, cSDA) +local i2cId = 0 + +-- setup i2c bus and mcp23017 +i2c.setup(i2cId, cSDA, cSCL, i2c.SLOW) +mcp23017.setup(address, i2cId) --[[ @@ -104,4 +107,4 @@ tmr.create():alarm(7000, tmr.ALARM_AUTO, function() local b = mcp23017.readGPIO(mcp23017.GPB) print("GPIO B input states: " .. b) print(" ") -end) \ No newline at end of file +end) diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index d0e393e7ca..ec9d4cabd3 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -67,7 +67,6 @@ local MCP23017_OLATB = 0x15 -- internal local MCP23017_id = 0 -local MCP23017_SPEED = i2c.SLOW local MCP23017_DEVICE_OK = false -- check device is available on address @@ -171,11 +170,15 @@ local function reset() end -- setup device -local function setup(address, sclPin, sdaPin) +local function setup(address, i2c_id, sclPin, sdaPin) MCP23017_ADDRESS = string.format('0x%02X', address) - i2c.setup(MCP23017_id, sdaPin, sclPin, MCP23017_SPEED) + if sclPin ~= nil and sdaPin ~= nil then + i2c.setup(i2c_id, sdaPin, sclPin, i2c.SLOW) + else + MCP23017_id = i2c_id + end if (checkAddress(address) ~= true) or (checkDevice(address) ~= true) then MCP23017_DEVICE_OK = false @@ -256,14 +259,23 @@ local function readFromRegsiter(registerAddr) end local function writeIODIR(bReg, newByte) + if MCP23017_DEVICE_OK == false then + return nil + end return writeToRegsiter(getDirRegisterAddr(bReg), newByte) end local function writeGPIO(bReg, newByte) + if MCP23017_DEVICE_OK == false then + return nil + end return writeToRegsiter(getGPIORegisterAddr(bReg), newByte) end local function readGPIO(bReg) + if MCP23017_DEVICE_OK == false then + return nil + end return readFromRegsiter(getGPIORegisterAddr(bReg)) end From b3c5a34544bdf01ec726f9da163ab58fb6b5e3eb Mon Sep 17 00:00:00 2001 From: plomi Date: Wed, 22 Apr 2020 22:12:31 +0200 Subject: [PATCH 57/59] update setup syntax in doc --- docs/lua-modules/mcp23017.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index f57af55b0b..1620a00aaa 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -36,7 +36,7 @@ Then this function will establish the connection. Automatically resets the device state (see `mcp23017.reset()`) #### Syntax -`mcp23017.setup(address, customSCL, customSDA)` +`mcp23017.setup(address, i2c_id)` #### Parameter - `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) From 75c8cf6483a0c448af87ea66fce67d85df2ca49b Mon Sep 17 00:00:00 2001 From: plomi Date: Sun, 5 Jul 2020 09:24:43 +0200 Subject: [PATCH 58/59] changing mcp23017 module to factory style --- lua_modules/mcp23017/mcp23017.lua | 220 ++++++++++++++---------------- 1 file changed, 102 insertions(+), 118 deletions(-) diff --git a/lua_modules/mcp23017/mcp23017.lua b/lua_modules/mcp23017/mcp23017.lua index ec9d4cabd3..38eb4ec876 100644 --- a/lua_modules/mcp23017/mcp23017.lua +++ b/lua_modules/mcp23017/mcp23017.lua @@ -24,16 +24,14 @@ local issetBit = bit.isset local setBit = bit.set local clearBit = bit.clear -local MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) +-- MCP23017_ADDRESS = 0x20 -- (0x20 to 0x27) -- MCP23017_SDA = 2 -- D2/GPIO 4 -- MCP23017_SCL = 1 -- D1/GPIO 5 -local OUTPUT = false -local INPUT = true -local GPA = false -local GPB = true -local HIGH = true -local LOW = false + +-- metatable +local mcp23017 = {} +mcp23017.__index = mcp23017 -- registers (not used registers are commented out) local MCP23017_IODIRA = 0x00 @@ -65,24 +63,20 @@ local MCP23017_OLATA = 0x14 local MCP23017_OLATB = 0x15 ]] --- internal -local MCP23017_id = 0 -local MCP23017_DEVICE_OK = false - -- check device is available on address -local function checkDevice(address) - i2c.start(MCP23017_id) - local response = i2c.address(MCP23017_id, address, i2c.TRANSMITTER) - i2c.stop(MCP23017_id) +function mcp23017:checkDevice() + i2c.start(self.i2cId) + local response = i2c.address(self.i2cId, self.address, i2c.TRANSMITTER) + i2c.stop(self.i2cId) if response ~= true then - print("MCP23017 device on " .. string.format('0x%02X', address) .. " not found") + print("MCP23017 device on " .. string.format('0x%02X', self.address) .. " not found") end return response end -- check device address (0x20 to 0x27) -local function checkAddress(address) - local addr = tonumber(address) +function mcp23017:checkAddress() + local addr = tonumber(self.address) if (addr > 31 and addr < 40) then return true else @@ -92,30 +86,30 @@ local function checkAddress(address) end -- write byte -local function writeByte(registerAddr, val) - i2c.start(MCP23017_id) - i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) - i2c.write(MCP23017_id, registerAddr) - i2c.write(MCP23017_id, val) - i2c.stop(MCP23017_id) +function mcp23017:writeByte(registerAddr, val) + i2c.start(self.i2cId) + i2c.address(self.i2cId, self.address, i2c.TRANSMITTER) + i2c.write(self.i2cId, registerAddr) + i2c.write(self.i2cId, val) + i2c.stop(self.i2cId) end -- read byte -local function readByte(registerAddr) - i2c.start(MCP23017_id) - i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.TRANSMITTER) - i2c.write(MCP23017_id, registerAddr) - i2c.stop(MCP23017_id) - i2c.start(MCP23017_id) - i2c.address(MCP23017_id, MCP23017_ADDRESS, i2c.RECEIVER) - local data = i2c.read(MCP23017_id, 1) - i2c.stop(MCP23017_id) +function mcp23017:readByte(registerAddr) + i2c.start(self.i2cId) + i2c.address(self.i2cId, self.address, i2c.TRANSMITTER) + i2c.write(self.i2cId, registerAddr) + i2c.stop(self.i2cId) + i2c.start(self.i2cId) + i2c.address(self.i2cId, self.address, i2c.RECEIVER) + local data = i2c.read(self.i2cId, 1) + i2c.stop(self.i2cId) return string.byte(data) end -- get IO dir register -local function getDirRegisterAddr(bReg) - if bReg == GPB then +function mcp23017:getDirRegisterAddr(bReg) + if bReg == self.GPB then return MCP23017_IODIRB else return MCP23017_IODIRA @@ -123,8 +117,8 @@ local function getDirRegisterAddr(bReg) end -- get GPIO register address -local function getGPIORegisterAddr(bReg) - if bReg == GPB then +function mcp23017:getGPIORegisterAddr(bReg) + if bReg == self.GPB then return MCP23017_GPIOB else return MCP23017_GPIOA @@ -132,7 +126,7 @@ local function getGPIORegisterAddr(bReg) end -- check pin is in range -local function checkPinIsInRange(pin) +function mcp23017:checkPinIsInRange(pin) if pin > 7 or pin < 0 then print("The pin must be between 0 and 7") return nil @@ -141,20 +135,20 @@ local function checkPinIsInRange(pin) end -- setup internal pullup -local function setInternalPullUp(bReg, iByte) - if bReg == GPB then - writeByte(MCP23017_DEFVALB, iByte) +function mcp23017:setInternalPullUp(bReg, iByte) + if bReg == self.GPB then + self:writeByte(MCP23017_DEFVALB, iByte) else - writeByte(MCP23017_DEFVALA, iByte) + self:writeByte(MCP23017_DEFVALA, iByte) end end -- set default GPIO mode -local function setDefaultMode(bReg, iByte) - writeByte(getDirRegisterAddr(bReg), iByte) +function mcp23017:setDefaultMode(bReg, iByte) + self:writeByte(self:getDirRegisterAddr(bReg), iByte) end -local function numberToBool(val) +function mcp23017:numberToBool(val) if val == 1 or val == true or val == '1' then return true else @@ -163,143 +157,133 @@ local function numberToBool(val) end -- reset gpio mode -local function reset() +function mcp23017:reset() -- all to input - setDefaultMode(GPA, 0xFF) - setDefaultMode(GPB, 0xFF) + self:setDefaultMode(self.GPA, 0xFF) + self:setDefaultMode(self.GPB, 0xFF) end -- setup device -local function setup(address, i2c_id, sclPin, sdaPin) - - MCP23017_ADDRESS = string.format('0x%02X', address) - - if sclPin ~= nil and sdaPin ~= nil then - i2c.setup(i2c_id, sdaPin, sclPin, i2c.SLOW) - else - MCP23017_id = i2c_id - end +function mcp23017:setup(address, i2cId) - if (checkAddress(address) ~= true) or (checkDevice(address) ~= true) then - MCP23017_DEVICE_OK = false + self.address = string.format('0x%02X', address) + self.i2cId = i2cId + if (self:checkAddress() ~= true) or (self:checkDevice() ~= true) then + self.deviceOk = false return 0 else - MCP23017_DEVICE_OK = true - reset() + self.deviceOk = true + self:reset() return 1 end end -- set mode for a pin -local function setMode(bReg, pin, mode) - if MCP23017_DEVICE_OK == false then +function mcp23017:setMode(bReg, pin, mode) + if self.deviceOk == false then return nil end - local inReq = getDirRegisterAddr(bReg) - local inPin = checkPinIsInRange(pin) - local response = readByte(inReq) + local inReq = self:getDirRegisterAddr(bReg) + local inPin = self:checkPinIsInRange(pin) + local response = self:readByte(inReq) local newState - if numberToBool(mode) == OUTPUT then + if self:numberToBool(mode) == self.OUTPUT then newState = clearBit(response, inPin) else newState = setBit(response, inPin) end - writeByte(inReq, newState) + self:writeByte(inReq, newState) return true end -- set pin to low or high -local function setPin(bReg, pin, state) - if MCP23017_DEVICE_OK == false then +function mcp23017:setPin(bReg, pin, state) + if self.deviceOk == false then return nil end - local inReq = getGPIORegisterAddr(bReg) - local inPin = checkPinIsInRange(pin) - local response = readByte(inReq) + local inReq = self:getGPIORegisterAddr(bReg) + local inPin = self:checkPinIsInRange(pin) + local response = self:readByte(inReq) local newState - if numberToBool(state) == HIGH then + if self:numberToBool(state) == self.HIGH then newState = setBit(response, inPin) else newState = clearBit(response, inPin) end - writeByte(inReq, newState) + self:writeByte(inReq, newState) return true end -- read pin input -local function getPinState(bReg, pin) - if MCP23017_DEVICE_OK == false then +function mcp23017:getPinState(bReg, pin) + if self.deviceOk == false then return nil end - local inReq = getGPIORegisterAddr(bReg) - local inPin = checkPinIsInRange(pin) - local response = readByte(inReq) + local inReq = self:getGPIORegisterAddr(bReg) + local inPin = self:checkPinIsInRange(pin) + local response = self:readByte(inReq) return issetBit(response, inPin) end -local function writeToRegsiter(registerAddr, newByte) - if MCP23017_DEVICE_OK == false then +function mcp23017:writeToRegister(registerAddr, newByte) + if self.deviceOk == false then return nil end - return writeByte(registerAddr, newByte) + return self:writeByte(registerAddr, newByte) end -local function readFromRegsiter(registerAddr) - if MCP23017_DEVICE_OK == false then +function mcp23017:readFromRegister(registerAddr) + if self.deviceOk == false then return nil end - return readByte(registerAddr) + return self:readByte(registerAddr) end -local function writeIODIR(bReg, newByte) - if MCP23017_DEVICE_OK == false then +function mcp23017:writeIODIR(bReg, newByte) + if self.deviceOk == false then return nil end - return writeToRegsiter(getDirRegisterAddr(bReg), newByte) + return self:writeToRegister(self:getDirRegisterAddr(bReg), newByte) end -local function writeGPIO(bReg, newByte) - if MCP23017_DEVICE_OK == false then +function mcp23017:writeGPIO(bReg, newByte) + if self.deviceOk == false then return nil end - return writeToRegsiter(getGPIORegisterAddr(bReg), newByte) + return self:writeToRegister(self:getGPIORegisterAddr(bReg), newByte) end -local function readGPIO(bReg) - if MCP23017_DEVICE_OK == false then +function mcp23017:readGPIO(bReg) + if self.deviceOk == false then return nil end - return readFromRegsiter(getGPIORegisterAddr(bReg)) + return self:readFromRegister(self:getGPIORegisterAddr(bReg)) +end + +return function(address, i2cId) + local self = {} + setmetatable(self, mcp23017) + + -- defaults + self.deviceOK = false + self.i2cId = 0 + self.address = nil + self.OUTPUT = false + self.INPUT = true + self.GPA = false + self.GPB = true + self.HIGH = true + self.LOW = false + + self:setup(address, i2cId) + return self end --- Set module name as parameter of require and rgetGPIORegisterAddreturn module table -local M = { - OUTPUT = OUTPUT, - INPUT = INPUT, - GPA = GPA, - GPB = GPB, - HIGH = HIGH, - LOW = LOW, - checkDevice = checkDevice, - setup = setup, - setMode = setMode, - setPin = setPin, - getPinState = getPinState, - reset = reset, - setInternalPullUp = setInternalPullUp, - writeIODIR = writeIODIR, - writeGPIO = writeGPIO, - readGPIO = readGPIO, -} - -local moduleName = ... -_G[moduleName or 'mcp23017'] = M -return M From 60963eacfbae3ab0cebe968852b5fbe3351ff606 Mon Sep 17 00:00:00 2001 From: plomi Date: Sun, 5 Jul 2020 09:30:49 +0200 Subject: [PATCH 59/59] mcp23017 module: update example and docs for factory style --- docs/lua-modules/mcp23017.md | 61 +++++++++++----------- lua_examples/mcp23017/mcp23017_example.lua | 26 ++++----- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/docs/lua-modules/mcp23017.md b/docs/lua-modules/mcp23017.md index 1620a00aaa..35bf91e84f 100644 --- a/docs/lua-modules/mcp23017.md +++ b/docs/lua-modules/mcp23017.md @@ -23,7 +23,7 @@ The numbers are for each register GPIO A and GPIO B. ### Require ```lua -mcp23017 = require("mcp23017") +mcp = require "mcp23017" ``` ## Example Script @@ -33,16 +33,14 @@ The example script can be found [here](../../lua_examples/mcp23017/mcp23017_exam Configures the address of the module and tests the connection to the i2c bus. The i2c id is required for an existing i2c interface, alternatively the sda and scl pins can be specified. Then this function will establish the connection. -Automatically resets the device state (see `mcp23017.reset()`) +Automatically resets the device state (see `mcp23017:reset()`) #### Syntax -`mcp23017.setup(address, i2c_id)` +`mcp23017:setup(address, i2c_id)` #### Parameter - `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27) - `i2c_id` id for the i2c bus connection (i2c.setup separately) -- `customSCL` (optional) Pin for i²c SCL Signal, default: GPIO 5, Pin 1 -- `customSDA` (optional) Pin for i²c SDA Signal, default: GPIO 4, Pin 2 #### Return `true` if device found, otherwise `false`. @@ -53,22 +51,23 @@ Automatically resets the device state (see `mcp23017.reset()`) #### Example ```lua -local mcp23017 = require('mcp23017') +local mcp23017 = require "mcp23017" local address = 0x20 local cSCL = 1 local cSDA = 2 -local cID = 0 +local i2c_instance = 0 -i2c.setup(cID, cSDA, cSCL, i2c.SLOW) -mcp23017.setup(address, cID) +-- setup i2c bus and create instance for mcp23017 (assigned to mcp) +i2c.setup(i2c_instance, cSDA, cSCL, i2c.SLOW) +local mcp = mcp23017(address, i2c_instance) ``` ## setMode() Set the mode of a single channel. This can be OUTPUT or INPUT. #### Syntax -`mcp23017.setMode(register, pin, mode)` +`mcp23017:setMode(register, pin, mode)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -81,16 +80,16 @@ Set the mode of a single channel. This can be OUTPUT or INPUT. #### Example ```lua -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) +mcp:setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) +mcp:setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) +mcp:setMode(mcp23017.GPB, 1, mcp23017.INPUT) ``` ## setPin() Set the state of a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.setMode(register, pin, state)` +`mcp23017:setMode(register, pin, state)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -103,16 +102,16 @@ Set the state of a single channel. This can be HIGH or LOW. #### Example ```lua -- set pin 7 to high (GPA7) -mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) +mcp:setPin(mcp23017.GPA, 7, mcp23017.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) +mcp:setPin(mcp23017.GPB, 0, mcp23017.LOW) ``` ## getPinState() get the state for a single channel. This can be HIGH or LOW. #### Syntax -`mcp23017.getPinState(register, pin)` +`mcp23017:getPinState(register, pin)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -124,7 +123,7 @@ get the state for a single channel. This can be HIGH or LOW. #### Example ```lua -- get the state for pin 9 (GPB1) -print(mcp23017.getPinState(mcp23017.GPB, 1)) +print(mcp:getPinState(mcp23017.GPB, 1)) ``` ## reset() @@ -133,7 +132,7 @@ All channels are set to input. This function can be used for a panic program. #### Syntax -`mcp23017.reset()` +`mcp23017:reset()` #### Parameter None @@ -144,14 +143,14 @@ None #### Example ```lua -- reset the mcp23017 to startup defaults -mcp23017.reset() +mcp:reset() ``` ## setInternalPullUp() Enable or disable the internal pullup resistors. #### Syntax -`mcp23017.setInternalPullUp(register, byte)` +`mcp23017:setInternalPullUp(register, byte)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -163,9 +162,9 @@ None #### Example ```lua -- enable all pullup resistors for GPA -print(mcp23017.setInternalPullUp(mcp23017.GPA, 0xFF)) +print(mcp:setInternalPullUp(mcp23017.GPA, 0xFF)) -- disable all pullup resistors for GPA -print(mcp23017.setInternalPullUp(mcp23017.GPA, 0x00)) +print(mcp:setInternalPullUp(mcp23017.GPA, 0x00)) ``` ## writeIODIR() @@ -173,7 +172,7 @@ Setup the mode of the channels with a whole byte. #### Syntax -`mcp23017.writeIODIR(register, byte)` +`mcp23017:writeIODIR(register, byte)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -185,16 +184,16 @@ None #### Example ```lua -- set all GPA to input -print(mcp23017.writeIODIR(mcp23017.GPA, 0xFF)) +print(mcp:writeIODIR(mcp23017.GPA, 0xFF)) -- set all GPA to output -print(mcp23017.writeIODIR(mcp23017.GPA, 0x00)) +print(mcp:writeIODIR(mcp23017.GPA, 0x00)) ``` ## writeGPIO() Setup the output state of the channels with a whole byte. #### Syntax -`mcp23017.writeGPIO(register, byte)` +`mcp23017:writeGPIO(register, byte)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -206,16 +205,16 @@ None #### Example ```lua -- set all GPA to HIGH -print(mcp23017.writeGPIO(mcp23017.GPA, 0xFF)) +print(mcp:writeGPIO(mcp23017.GPA, 0xFF)) -- set all GPA to LOW -print(mcp23017.writeGPIO(mcp23017.GPA, 0x00)) +print(mcp:writeGPIO(mcp23017.GPA, 0x00)) ``` ## readGPIO() Read the input states of the channels with a whole byte. #### Syntax -`mcp23017.readGPIO(register)` +`mcp23017:readGPIO(register)` #### Parameter - `register` the side of channels (GPA or GPB) @@ -226,6 +225,6 @@ byte with states #### Example ```lua -- get states for GPA -print(mcp23017.readGPIO(mcp23017.GPA)) +print(mcp:readGPIO(mcp23017.GPA)) ``` diff --git a/lua_examples/mcp23017/mcp23017_example.lua b/lua_examples/mcp23017/mcp23017_example.lua index b59abc460a..122f279c6d 100644 --- a/lua_examples/mcp23017/mcp23017_example.lua +++ b/lua_examples/mcp23017/mcp23017_example.lua @@ -20,7 +20,7 @@ ]] -- initialize module -local mcp23017 = require('mcp23017') +local mcp23017 = require "mcp23017" -- set the address for MCP23017 local address = 0x20 @@ -33,9 +33,9 @@ local cSDA = 2 local i2cId = 0 --- setup i2c bus and mcp23017 +-- setup i2c bus and create instance for mcp23017 (assigned to mcp) i2c.setup(i2cId, cSDA, cSCL, i2c.SLOW) -mcp23017.setup(address, i2cId) +local mcp = mcp23017(address, i2cId) --[[ @@ -45,9 +45,9 @@ mcp23017.setup(address, i2cId) ]] -- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input -mcp23017.setMode(mcp23017.GPA, 7, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 0, mcp23017.OUTPUT) -mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) +mcp:setMode(mcp.GPA, 7, mcp.OUTPUT) +mcp:setMode(mcp.GPB, 0, mcp.OUTPUT) +mcp:setMode(mcp.GPB, 1, mcp.INPUT) @@ -58,9 +58,9 @@ mcp23017.setMode(mcp23017.GPB, 1, mcp23017.INPUT) ]] -- set pin 7 to high (GPA7) -mcp23017.setPin(mcp23017.GPA, 7, mcp23017.HIGH) +mcp:setPin(mcp.GPA, 7, mcp.HIGH) -- set pin 8 to low (GPB0) -mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) +mcp:setPin(mcp.GPB, 0, mcp.LOW) @@ -74,16 +74,16 @@ mcp23017.setPin(mcp23017.GPB, 0, mcp23017.LOW) local currentPin = 6 local currentState = false -mcp23017.setMode(mcp23017.GPA, currentPin, mcp23017.OUTPUT) +mcp:setMode(mcp.GPA, currentPin, mcp.OUTPUT) tmr.create():alarm(1000, tmr.ALARM_AUTO, function() if currentState == true then -- print("set to low") - mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.LOW) + mcp:setPin(mcp.GPA, currentPin, mcp.LOW) currentState = false else -- print("set to high") - mcp23017.setPin(mcp23017.GPA, currentPin, mcp23017.HIGH) + mcp:setPin(mcp.GPA, currentPin, mcp.HIGH) currentState = true end end) @@ -100,11 +100,11 @@ end) -- read input register tmr.create():alarm(7000, tmr.ALARM_AUTO, function() - local a = mcp23017.readGPIO(mcp23017.GPA) + local a = mcp:readGPIO(mcp.GPA) print(" ") print("GPIO A input states: " .. a) - local b = mcp23017.readGPIO(mcp23017.GPB) + local b = mcp:readGPIO(mcp.GPB) print("GPIO B input states: " .. b) print(" ") end)