From 2c5242ca5513e4e2a959c5710e4a17b435b11c1d Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Fri, 19 Nov 2021 18:42:35 +0100 Subject: [PATCH] Add libsodium, cbor and jsmn components --- .gitignore | 1 + .gitmodules | 6 + cbor/CMakeLists.txt | 20 ++ cbor/LICENSE | 1 + cbor/README.md | 1 + cbor/idf_component.yml | 5 + cbor/port/include/cbor.h | 2 + cbor/tinycbor | 1 + jsmn/CMakeLists.txt | 10 + jsmn/Kconfig | 16 + jsmn/LICENSE | 19 + jsmn/README.md | 168 +++++++++ jsmn/idf_component.yml | 5 + jsmn/include/jsmn.h | 106 ++++++ jsmn/src/jsmn.c | 340 ++++++++++++++++++ libsodium/CMakeLists.txt | 178 +++++++++ libsodium/Kconfig | 15 + libsodium/LICENSE | 1 + libsodium/README.md | 1 + libsodium/idf_component.yml | 6 + libsodium/libsodium | 1 + .../crypto_hash_sha256_mbedtls.c | 93 +++++ .../crypto_hash_sha512_mbedtls.c | 97 +++++ libsodium/port/randombytes_esp32.c | 28 ++ libsodium/port/randombytes_internal.h | 20 ++ libsodium/port_include/sodium/version.h | 40 +++ libsodium/test/CMakeLists.txt | 36 ++ libsodium/test/test_sodium.c | 124 +++++++ pid_ctrl/idf_component.yml | 1 + qrcode/idf_component.yml | 1 + 30 files changed, 1343 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 cbor/CMakeLists.txt create mode 120000 cbor/LICENSE create mode 120000 cbor/README.md create mode 100644 cbor/idf_component.yml create mode 100644 cbor/port/include/cbor.h create mode 160000 cbor/tinycbor create mode 100644 jsmn/CMakeLists.txt create mode 100644 jsmn/Kconfig create mode 100644 jsmn/LICENSE create mode 100644 jsmn/README.md create mode 100644 jsmn/idf_component.yml create mode 100644 jsmn/include/jsmn.h create mode 100644 jsmn/src/jsmn.c create mode 100644 libsodium/CMakeLists.txt create mode 100644 libsodium/Kconfig create mode 120000 libsodium/LICENSE create mode 120000 libsodium/README.md create mode 100644 libsodium/idf_component.yml create mode 160000 libsodium/libsodium create mode 100644 libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c create mode 100644 libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c create mode 100644 libsodium/port/randombytes_esp32.c create mode 100644 libsodium/port/randombytes_internal.h create mode 100644 libsodium/port_include/sodium/version.h create mode 100644 libsodium/test/CMakeLists.txt create mode 100644 libsodium/test/test_sodium.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..934b9d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*/dist/** \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..082cd43 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "libsodium/libsodium"] + path = libsodium/libsodium + url = https://github.com/jedisct1/libsodium.git +[submodule "cbor/tinycbor"] + path = cbor/tinycbor + url = https://github.com/intel/tinycbor.git diff --git a/cbor/CMakeLists.txt b/cbor/CMakeLists.txt new file mode 100644 index 0000000..f213c22 --- /dev/null +++ b/cbor/CMakeLists.txt @@ -0,0 +1,20 @@ +idf_component_register(SRCS "tinycbor/src/cborencoder_close_container_checked.c" + "tinycbor/src/cborencoder.c" + "tinycbor/src/cborerrorstrings.c" + "tinycbor/src/cborparser_dup_string.c" + "tinycbor/src/cborparser.c" + "tinycbor/src/cborpretty_stdio.c" + "tinycbor/src/cborpretty.c" + "tinycbor/src/cbortojson.c" + "tinycbor/src/cborvalidation.c" + "tinycbor/src/open_memstream.c" + INCLUDE_DIRS "port/include" + PRIV_INCLUDE_DIRS "tinycbor/src") + +# for open_memstream.c +set_source_files_properties(tinycbor/src/open_memstream.c PROPERTIES COMPILE_DEFINITIONS "__linux__") + +# workaround for the fact that we are passing -ffreestanding to Clang +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + target_compile_options(${COMPONENT_LIB} PRIVATE "-U __STDC_HOSTED__") +endif() diff --git a/cbor/LICENSE b/cbor/LICENSE new file mode 120000 index 0000000..7dfaefc --- /dev/null +++ b/cbor/LICENSE @@ -0,0 +1 @@ +tinycbor/LICENSE \ No newline at end of file diff --git a/cbor/README.md b/cbor/README.md new file mode 120000 index 0000000..f7f75f4 --- /dev/null +++ b/cbor/README.md @@ -0,0 +1 @@ +tinycbor/README \ No newline at end of file diff --git a/cbor/idf_component.yml b/cbor/idf_component.yml new file mode 100644 index 0000000..ff92d94 --- /dev/null +++ b/cbor/idf_component.yml @@ -0,0 +1,5 @@ +version: "0.5.4" +description: "CBOR: Concise Binary Object Representation Library" +url: https://github.com/espressif/idf-extra-components/tree/master/cbor +dependencies: + idf: ">=4.3" \ No newline at end of file diff --git a/cbor/port/include/cbor.h b/cbor/port/include/cbor.h new file mode 100644 index 0000000..c8e6ccf --- /dev/null +++ b/cbor/port/include/cbor.h @@ -0,0 +1,2 @@ +#include "../../tinycbor/src/cbor.h" +#include "../../tinycbor/src/cborjson.h" diff --git a/cbor/tinycbor b/cbor/tinycbor new file mode 160000 index 0000000..7c349db --- /dev/null +++ b/cbor/tinycbor @@ -0,0 +1 @@ +Subproject commit 7c349dbb6b8d76db39383b226d3ebdf59b8ab37d diff --git a/jsmn/CMakeLists.txt b/jsmn/CMakeLists.txt new file mode 100644 index 0000000..d05badb --- /dev/null +++ b/jsmn/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register(SRCS "src/jsmn.c" + INCLUDE_DIRS "include") + +if(CONFIG_JSMN_PARENT_LINKS) + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DJSMN_PARENT_LINKS") +endif() + +if(CONFIG_JSMN_STRICT) + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DJSMN_STRICT") +endif() diff --git a/jsmn/Kconfig b/jsmn/Kconfig new file mode 100644 index 0000000..114fbe4 --- /dev/null +++ b/jsmn/Kconfig @@ -0,0 +1,16 @@ +menu "jsmn" + + + config JSMN_PARENT_LINKS + bool "Enable parent links" + default n + help + You can access to parent node of parsed json + + config JSMN_STRICT + bool "Enable strict mode" + default n + help + In strict mode primitives are: numbers and booleans + +endmenu diff --git a/jsmn/LICENSE b/jsmn/LICENSE new file mode 100644 index 0000000..e50f5ae --- /dev/null +++ b/jsmn/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Serge A. Zaitsev + +Permission is hereby granted, 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. diff --git a/jsmn/README.md b/jsmn/README.md new file mode 100644 index 0000000..5bde6fb --- /dev/null +++ b/jsmn/README.md @@ -0,0 +1,168 @@ +JSMN +==== + +[![Build Status](https://travis-ci.org/zserge/jsmn.svg?branch=master)](https://travis-ci.org/zserge/jsmn) + +jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be +easily integrated into resource-limited or embedded projects. + +You can find more information about JSON format at [json.org][1] + +Library sources are available at https://github.com/zserge/jsmn + +The web page with some information about jsmn can be found at +[http://zserge.com/jsmn.html][2] + +Philosophy +---------- + +Most JSON parsers offer you a bunch of functions to load JSON data, parse it +and extract any value by its name. jsmn proves that checking the correctness of +every JSON packet or allocating temporary objects to store parsed JSON fields +often is an overkill. + +JSON format itself is extremely simple, so why should we complicate it? + +jsmn is designed to be **robust** (it should work fine even with erroneous +data), **fast** (it should parse data on the fly), **portable** (no superfluous +dependencies or non-standard C extensions). And of course, **simplicity** is a +key feature - simple code style, simple algorithm, simple integration into +other projects. + +Features +-------- + +* compatible with C89 +* no dependencies (even libc!) +* highly portable (tested on x86/amd64, ARM, AVR) +* about 200 lines of code +* extremely small code footprint +* API contains only 2 functions +* no dynamic memory allocation +* incremental single-pass parsing +* library code is covered with unit-tests + +Design +------ + +The rudimentary jsmn object is a **token**. Let's consider a JSON string: + + '{ "name" : "Jack", "age" : 27 }' + +It holds the following tokens: + +* Object: `{ "name" : "Jack", "age" : 27}` (the whole object) +* Strings: `"name"`, `"Jack"`, `"age"` (keys and some values) +* Number: `27` + +In jsmn, tokens do not hold any data, but point to token boundaries in JSON +string instead. In the example above jsmn will create tokens like: Object +[0..31], String [3..7], String [12..16], String [20..23], Number [27..29]. + +Every jsmn token has a type, which indicates the type of corresponding JSON +token. jsmn supports the following token types: + +* Object - a container of key-value pairs, e.g.: + `{ "foo":"bar", "x":0.3 }` +* Array - a sequence of values, e.g.: + `[ 1, 2, 3 ]` +* String - a quoted sequence of chars, e.g.: `"foo"` +* Primitive - a number, a boolean (`true`, `false`) or `null` + +Besides start/end positions, jsmn tokens for complex types (like arrays +or objects) also contain a number of child items, so you can easily follow +object hierarchy. + +This approach provides enough information for parsing any JSON data and makes +it possible to use zero-copy techniques. + +Install +------- + +To clone the repository you should have Git installed. Just run: + + $ git clone https://github.com/zserge/jsmn + +Repository layout is simple: jsmn.c and jsmn.h are library files, tests are in +the jsmn\_test.c, you will also find README, LICENSE and Makefile files inside. + +To build the library, run `make`. It is also recommended to run `make test`. +Let me know, if some tests fail. + +If build was successful, you should get a `libjsmn.a` library. +The header file you should include is called `"jsmn.h"`. + +API +--- + +Token types are described by `jsmntype_t`: + + typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3, + JSMN_PRIMITIVE = 4 + } jsmntype_t; + +**Note:** Unlike JSON data types, primitive tokens are not divided into +numbers, booleans and null, because one can easily tell the type using the +first character: + +* 't', 'f' - boolean +* 'n' - null +* '-', '0'..'9' - number + +Token is an object of `jsmntok_t` type: + + typedef struct { + jsmntype_t type; // Token type + int start; // Token start position + int end; // Token end position + int size; // Number of child (nested) tokens + } jsmntok_t; + +**Note:** string tokens point to the first character after +the opening quote and the previous symbol before final quote. This was made +to simplify string extraction from JSON data. + +All job is done by `jsmn_parser` object. You can initialize a new parser using: + + jsmn_parser parser; + jsmntok_t tokens[10]; + + jsmn_init(&parser); + + // js - pointer to JSON string + // tokens - an array of tokens available + // 10 - number of tokens available + jsmn_parse(&parser, js, strlen(js), tokens, 10); + +This will create a parser, and then it tries to parse up to 10 JSON tokens from +the `js` string. + +A non-negative return value of `jsmn_parse` is the number of tokens actually +used by the parser. +Passing NULL instead of the tokens array would not store parsing results, but +instead the function will return the value of tokens needed to parse the given +string. This can be useful if you don't know yet how many tokens to allocate. + +If something goes wrong, you will get an error. Error will be one of these: + +* `JSMN_ERROR_INVAL` - bad token, JSON string is corrupted +* `JSMN_ERROR_NOMEM` - not enough tokens, JSON string is too large +* `JSMN_ERROR_PART` - JSON string is too short, expecting more JSON data + +If you get `JSMN_ERROR_NOMEM`, you can re-allocate more tokens and call +`jsmn_parse` once more. If you read json data from the stream, you can +periodically call `jsmn_parse` and check if return value is `JSMN_ERROR_PART`. +You will get this error until you reach the end of JSON data. + +Other info +---------- + +This software is distributed under [MIT license](http://www.opensource.org/licenses/mit-license.php), + so feel free to integrate it in your commercial products. + +[1]: http://www.json.org/ +[2]: http://zserge.com/jsmn.html \ No newline at end of file diff --git a/jsmn/idf_component.yml b/jsmn/idf_component.yml new file mode 100644 index 0000000..180edbd --- /dev/null +++ b/jsmn/idf_component.yml @@ -0,0 +1,5 @@ +version: "1.0.0" +description: "JSMN: minimalistic JSON parser in C" +url: https://github.com/espressif/idf-extra-components/tree/master/jsmn +dependencies: + idf: ">=4.3" diff --git a/jsmn/include/jsmn.h b/jsmn/include/jsmn.h new file mode 100644 index 0000000..1df808e --- /dev/null +++ b/jsmn/include/jsmn.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010 Serge A. Zaitsev + * + * Permission is hereby granted, 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. + */ + +/** + * @file jsmn.h + * @brief Definition of the JSMN (Jasmine) JSON parser. + * + * For more information on JSMN: + * @see http://zserge.com/jsmn.html + */ + +#ifndef __JSMN_H_ +#define __JSMN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ +typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3, + JSMN_PRIMITIVE = 4 +} jsmntype_t; + +enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +}; + +/** + * JSON token description. + * @param type type (object, array, string etc.) + * @param start start position in JSON data string + * @param end end position in JSON data string + */ +typedef struct { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; + +/** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string + */ +typedef struct { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g parent object or array */ +} jsmn_parser; + +/** + * Create JSON parser over an array of tokens + */ +void jsmn_init(jsmn_parser *parser); + +/** + * Run JSON parser. It parses a JSON data string into and array of tokens, each describing + * a single JSON object. + */ +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens); + +#ifdef __cplusplus +} +#endif + +#endif /* __JSMN_H_ */ diff --git a/jsmn/src/jsmn.c b/jsmn/src/jsmn.c new file mode 100644 index 0000000..2769b1d --- /dev/null +++ b/jsmn/src/jsmn.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2010 Serge A. Zaitsev + * + * Permission is hereby granted, 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. + */ + +/** + * @file jsmn.c + * @brief Implementation of the JSMN (Jasmine) JSON parser. + * + * For more information on JSMN: + * @see http://zserge.com/jsmn.html + */ + +#include "jsmn.h" + +/** + * Allocates a fresh unused token from the token pull. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, + jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, + int start, int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t' : case '\r' : case '\n' : case ' ' : + case ',' : case ']' : case '}' : + goto found; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Fills next token with JSON string. + */ +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + + int start = parser->pos; + + parser->pos++; + + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': case '/' : case '\\' : case 'b' : + case 'f' : case 'r' : case 'n' : case 't' : + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { + /* If it isn't a hex character we have an error */ + if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) { + tokens[parser->toksuper].size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t' : case '\r' : case '\n' : case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': case '0': case '1' : case '2': case '3' : case '4': + case '5': case '6': case '7' : case '8': case '9': + case 't': case 'f': case 'n' : + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} diff --git a/libsodium/CMakeLists.txt b/libsodium/CMakeLists.txt new file mode 100644 index 0000000..ac3e87f --- /dev/null +++ b/libsodium/CMakeLists.txt @@ -0,0 +1,178 @@ +set(SRC libsodium/src/libsodium) +# Derived from libsodium/src/libsodium/Makefile.am +# (ignoring the !MINIMAL set) +set(srcs + "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c" + "${SRC}/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c" + "${SRC}/crypto_auth/crypto_auth.c" + "${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c" + "${SRC}/crypto_auth/hmacsha512/auth_hmacsha512.c" + "${SRC}/crypto_auth/hmacsha512256/auth_hmacsha512256.c" + "${SRC}/crypto_box/crypto_box.c" + "${SRC}/crypto_box/crypto_box_easy.c" + "${SRC}/crypto_box/crypto_box_seal.c" + "${SRC}/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c" + "${SRC}/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c" + "${SRC}/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c" + "${SRC}/crypto_core/ed25519/core_ed25519.c" + "${SRC}/crypto_core/ed25519/core_ristretto255.c" + "${SRC}/crypto_core/ed25519/ref10/ed25519_ref10.c" + "${SRC}/crypto_core/hchacha20/core_hchacha20.c" + "${SRC}/crypto_core/hsalsa20/core_hsalsa20.c" + "${SRC}/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c" + "${SRC}/crypto_core/salsa/ref/core_salsa_ref.c" + "${SRC}/crypto_generichash/blake2b/generichash_blake2.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ref.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-ref.c" + "${SRC}/crypto_generichash/blake2b/ref/generichash_blake2b.c" + "${SRC}/crypto_generichash/crypto_generichash.c" + "${SRC}/crypto_hash/crypto_hash.c" + "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" + "${SRC}/crypto_hash/sha256/hash_sha256.c" + "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c" + "${SRC}/crypto_hash/sha512/hash_sha512.c" + "${SRC}/crypto_kdf/blake2b/kdf_blake2b.c" + "${SRC}/crypto_kdf/crypto_kdf.c" + "${SRC}/crypto_kx/crypto_kx.c" + "${SRC}/crypto_onetimeauth/crypto_onetimeauth.c" + "${SRC}/crypto_onetimeauth/poly1305/donna/poly1305_donna.c" + "${SRC}/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c" + "${SRC}/crypto_pwhash/argon2/argon2-core.c" + "${SRC}/crypto_pwhash/argon2/argon2-encoding.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-avx2.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-avx512f.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ssse3.c" + "${SRC}/crypto_pwhash/argon2/argon2.c" + "${SRC}/crypto_pwhash/argon2/blake2b-long.c" + "${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c" + "${SRC}/crypto_pwhash/argon2/pwhash_argon2id.c" + "${SRC}/crypto_pwhash/crypto_pwhash.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c" + "${SRC}/crypto_scalarmult/crypto_scalarmult.c" + "${SRC}/crypto_scalarmult/curve25519/ref10/x25519_ref10.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/consts.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/sandy2x.S" + "${SRC}/crypto_scalarmult/curve25519/scalarmult_curve25519.c" + "${SRC}/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c" + "${SRC}/crypto_scalarmult/ristretto255/ref10/scalarmult_ristretto255_ref10.c" + "${SRC}/crypto_secretbox/crypto_secretbox.c" + "${SRC}/crypto_secretbox/crypto_secretbox_easy.c" + "${SRC}/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c" + "${SRC}/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c" + "${SRC}/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c" + "${SRC}/crypto_shorthash/crypto_shorthash.c" + "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c" + "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c" + "${SRC}/crypto_shorthash/siphash24/shorthash_siphash24.c" + "${SRC}/crypto_shorthash/siphash24/shorthash_siphashx24.c" + "${SRC}/crypto_sign/crypto_sign.c" + "${SRC}/crypto_sign/ed25519/ref10/keypair.c" + "${SRC}/crypto_sign/ed25519/ref10/obsolete.c" + "${SRC}/crypto_sign/ed25519/ref10/open.c" + "${SRC}/crypto_sign/ed25519/ref10/sign.c" + "${SRC}/crypto_sign/ed25519/sign_ed25519.c" + "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c" + "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c" + "${SRC}/crypto_stream/chacha20/ref/chacha20_ref.c" + "${SRC}/crypto_stream/chacha20/stream_chacha20.c" + "${SRC}/crypto_stream/crypto_stream.c" + "${SRC}/crypto_stream/salsa20/ref/salsa20_ref.c" + "${SRC}/crypto_stream/salsa20/stream_salsa20.c" + "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S" + "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6.c" + "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c" + "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c" + "${SRC}/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c" + "${SRC}/crypto_stream/salsa2012/stream_salsa2012.c" + "${SRC}/crypto_stream/salsa208/ref/stream_salsa208_ref.c" + "${SRC}/crypto_stream/salsa208/stream_salsa208.c" + "${SRC}/crypto_stream/xchacha20/stream_xchacha20.c" + "${SRC}/crypto_stream/xsalsa20/stream_xsalsa20.c" + "${SRC}/crypto_verify/sodium/verify.c" + "${SRC}/randombytes/randombytes.c" + "${SRC}/sodium/codecs.c" + "${SRC}/sodium/core.c" + "${SRC}/sodium/runtime.c" + "${SRC}/sodium/utils.c" + "${SRC}/sodium/version.c" + "port/randombytes_esp32.c") + +if(CONFIG_LIBSODIUM_USE_MBEDTLS_SHA) + list(APPEND srcs + "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c" + "port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c") +else() + list(APPEND srcs + "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" + "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c") +endif() + +set(include_dirs ${SRC}/include port_include) +set(priv_include_dirs ${SRC}/include/sodium port_include/sodium port) +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES mbedtls) + +target_compile_definitions(${COMPONENT_LIB} PRIVATE + CONFIGURED + NATIVE_LITTLE_ENDIAN + HAVE_WEAK_SYMBOLS + __STDC_LIMIT_MACROS + __STDC_CONSTANT_MACROS + ) + +# patch around warnings in third-party files +set_source_files_properties( + ${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c + ${SRC}/crypto_pwhash/argon2/pwhash_argon2id.c + ${SRC}/crypto_pwhash/argon2/argon2-core.c + ${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c + PROPERTIES COMPILE_FLAGS + -Wno-type-limits + ) +set_source_files_properties( + ${SRC}/sodium/utils.c + PROPERTIES COMPILE_FLAGS + -Wno-unused-variable + ) +set_source_files_properties( + ${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c + PROPERTIES COMPILE_FLAGS + -Wno-unknown-pragmas + ) + +# Temporary suppress "fallthrough" warnings until they are fixed in libsodium repo +set_source_files_properties( + ${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c + ${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c + PROPERTIES COMPILE_FLAGS + -Wno-implicit-fallthrough + ) + +set_source_files_properties( + ${SRC}/randombytes/randombytes.c + PROPERTIES COMPILE_FLAGS + -DRANDOMBYTES_DEFAULT_IMPLEMENTATION +) + +target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-function) + +if(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE) + # some libsodium variables are only used for asserts + target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-but-set-variable) +endif() diff --git a/libsodium/Kconfig b/libsodium/Kconfig new file mode 100644 index 0000000..4d500f2 --- /dev/null +++ b/libsodium/Kconfig @@ -0,0 +1,15 @@ +menu "libsodium" + + config LIBSODIUM_USE_MBEDTLS_SHA + bool "Use mbedTLS SHA256 & SHA512 implementations" + default y + depends on !MBEDTLS_HARDWARE_SHA + help + If this option is enabled, libsodium will use thin wrappers + around mbedTLS for SHA256 & SHA512 operations. + + This saves some code size if mbedTLS is also used. However it + is incompatible with hardware SHA acceleration (due to the + way libsodium's API manages SHA state). + +endmenu # libsodium diff --git a/libsodium/LICENSE b/libsodium/LICENSE new file mode 120000 index 0000000..40c3df3 --- /dev/null +++ b/libsodium/LICENSE @@ -0,0 +1 @@ +libsodium/LICENSE \ No newline at end of file diff --git a/libsodium/README.md b/libsodium/README.md new file mode 120000 index 0000000..69dfaf5 --- /dev/null +++ b/libsodium/README.md @@ -0,0 +1 @@ +libsodium/README.markdown \ No newline at end of file diff --git a/libsodium/idf_component.yml b/libsodium/idf_component.yml new file mode 100644 index 0000000..3c15bb9 --- /dev/null +++ b/libsodium/idf_component.yml @@ -0,0 +1,6 @@ + +version: "1.0.18" +description: libsodium port to ESP32 +url: https://github.com/espressif/idf-extra-components/tree/master/libsodium +dependencies: + idf: ">=4.2" \ No newline at end of file diff --git a/libsodium/libsodium b/libsodium/libsodium new file mode 160000 index 0000000..4f5e89f --- /dev/null +++ b/libsodium/libsodium @@ -0,0 +1 @@ +Subproject commit 4f5e89fa84ce1d178a6765b8b46f2b6f91216677 diff --git a/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c new file mode 100644 index 0000000..13b6a39 --- /dev/null +++ b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "crypto_hash_sha256.h" +#include "mbedtls/sha256.h" +#include + +#ifdef MBEDTLS_SHA256_ALT +/* Wrapper only works if the libsodium context structure can be mapped + directly to the mbedTLS context structure. + + See extended comments in crypto_hash_sha512_mbedtls.c +*/ +#error "This wrapper only support standard software mbedTLS SHA" +#endif + +/* Sanity check that all the context fields have identical sizes + (this should be more or less given from the SHA256 algorithm) + + Note that the meaning of the fields is *not* all the same. In libsodium, SHA256 'count' is a 64-bit *bit* count. In + mbedTLS, 'total' is a 2x32-bit *byte* count (count[0] == MSB). + + For this implementation, we don't convert so the libsodium state structure actually holds a binary copy of the + mbedTLS totals. This doesn't matter inside libsodium's documented API, but would matter if any callers try to use + the state's bit count. +*/ +_Static_assert(sizeof(((crypto_hash_sha256_state *)0)->state) == sizeof(((mbedtls_sha256_context *)0)->state), "state mismatch"); +_Static_assert(sizeof(((crypto_hash_sha256_state *)0)->count) == sizeof(((mbedtls_sha256_context *)0)->total), "count mismatch"); +_Static_assert(sizeof(((crypto_hash_sha256_state *)0)->buf) == sizeof(((mbedtls_sha256_context *)0)->buffer), "buf mismatch"); + +/* Inline functions to convert between mbedTLS & libsodium + context structures +*/ + +static void sha256_mbedtls_to_libsodium(crypto_hash_sha256_state *ls_state, const mbedtls_sha256_context *mb_ctx) +{ + memcpy(&ls_state->count, mb_ctx->total, sizeof(ls_state->count)); + memcpy(ls_state->state, mb_ctx->state, sizeof(ls_state->state)); + memcpy(ls_state->buf, mb_ctx->buffer, sizeof(ls_state->buf)); +} + +static void sha256_libsodium_to_mbedtls(mbedtls_sha256_context *mb_ctx, crypto_hash_sha256_state *ls_state) +{ + memcpy(mb_ctx->total, &ls_state->count, sizeof(mb_ctx->total)); + memcpy(mb_ctx->state, ls_state->state, sizeof(mb_ctx->state)); + memcpy(mb_ctx->buffer, ls_state->buf, sizeof(mb_ctx->buffer)); + mb_ctx->is224 = 0; +} + +int +crypto_hash_sha256_init(crypto_hash_sha256_state *state) +{ + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + int ret = mbedtls_sha256_starts_ret(&ctx, 0); + if (ret != 0) { + return ret; + } + sha256_mbedtls_to_libsodium(state, &ctx); + return 0; +} + +int +crypto_hash_sha256_update(crypto_hash_sha256_state *state, + const unsigned char *in, unsigned long long inlen) +{ + mbedtls_sha256_context ctx; + sha256_libsodium_to_mbedtls(&ctx, state); + int ret = mbedtls_sha256_update_ret(&ctx, in, inlen); + if (ret != 0) { + return ret; + } + sha256_mbedtls_to_libsodium(state, &ctx); + return 0; +} + +int +crypto_hash_sha256_final(crypto_hash_sha256_state *state, unsigned char *out) +{ + mbedtls_sha256_context ctx; + sha256_libsodium_to_mbedtls(&ctx, state); + return mbedtls_sha256_finish_ret(&ctx, out); +} + +int +crypto_hash_sha256(unsigned char *out, const unsigned char *in, + unsigned long long inlen) +{ + return mbedtls_sha256_ret(in, inlen, out, 0); +} diff --git a/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c new file mode 100644 index 0000000..d0d7a66 --- /dev/null +++ b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "crypto_hash_sha512.h" +#include "mbedtls/sha512.h" +#include + +#ifdef MBEDTLS_SHA512_ALT +/* Wrapper only works if the libsodium context structure can be mapped + directly to the mbedTLS context structure. + + For ESP32 hardware SHA, the problems are fitting all the data in + the libsodium state structure, and also that libsodium doesn't + have mbedtls_sha512_free() or mbedtls_sha512_clone() so we can't + manage the hardware state in a clean way. +*/ +#error "This wrapper only support standard software mbedTLS SHA" +#endif + +/* Sanity check that all the context fields have identical sizes + (this should be more or less given from the SHA512 algorithm) + + Note that the meaning of the fields is *not* all the same. In libsodium, + SHA512 'count' is a 2xuin64_t *bit* count where count[0] == MSB. In mbedTLS, + SHA512 'total' is a 2xuint64_t *byte* count where count[0] == LSB. + + For this implementation, we don't convert so the libsodium state structure actually holds a binary copy of the + mbedTLS totals. This doesn't matter inside libsodium's documented API, but would matter if any callers try to use + the state's bit count. +*/ +_Static_assert(sizeof(((crypto_hash_sha512_state *)0)->state) == sizeof(((mbedtls_sha512_context *)0)->state), "state mismatch"); +_Static_assert(sizeof(((crypto_hash_sha512_state *)0)->count) == sizeof(((mbedtls_sha512_context *)0)->total), "count mismatch"); +_Static_assert(sizeof(((crypto_hash_sha512_state *)0)->buf) == sizeof(((mbedtls_sha512_context *)0)->buffer), "buf mismatch"); + +/* Inline functions to convert between mbedTLS & libsodium + context structures +*/ + +static void sha512_mbedtls_to_libsodium(crypto_hash_sha512_state *ls_state, const mbedtls_sha512_context *mb_ctx) +{ + memcpy(ls_state->count, mb_ctx->total, sizeof(ls_state->count)); + memcpy(ls_state->state, mb_ctx->state, sizeof(ls_state->state)); + memcpy(ls_state->buf, mb_ctx->buffer, sizeof(ls_state->buf)); +} + +static void sha512_libsodium_to_mbedtls(mbedtls_sha512_context *mb_ctx, crypto_hash_sha512_state *ls_state) +{ + memcpy(mb_ctx->total, ls_state->count, sizeof(mb_ctx->total)); + memcpy(mb_ctx->state, ls_state->state, sizeof(mb_ctx->state)); + memcpy(mb_ctx->buffer, ls_state->buf, sizeof(mb_ctx->buffer)); + mb_ctx->is384 = 0; +} + +int +crypto_hash_sha512_init(crypto_hash_sha512_state *state) +{ + mbedtls_sha512_context ctx; + mbedtls_sha512_init(&ctx); + int ret = mbedtls_sha512_starts_ret(&ctx, 0); + if (ret != 0) { + return ret; + } + sha512_mbedtls_to_libsodium(state, &ctx); + return 0; +} + +int +crypto_hash_sha512_update(crypto_hash_sha512_state *state, + const unsigned char *in, unsigned long long inlen) +{ + mbedtls_sha512_context ctx; + sha512_libsodium_to_mbedtls(&ctx, state); + int ret = mbedtls_sha512_update_ret(&ctx, in, inlen); + if (ret != 0) { + return ret; + } + sha512_mbedtls_to_libsodium(state, &ctx); + return 0; +} + +int +crypto_hash_sha512_final(crypto_hash_sha512_state *state, unsigned char *out) +{ + mbedtls_sha512_context ctx; + sha512_libsodium_to_mbedtls(&ctx, state); + return mbedtls_sha512_finish_ret(&ctx, out); +} + +int +crypto_hash_sha512(unsigned char *out, const unsigned char *in, + unsigned long long inlen) +{ + return mbedtls_sha512_ret(in, inlen, out, 0); +} diff --git a/libsodium/port/randombytes_esp32.c b/libsodium/port/randombytes_esp32.c new file mode 100644 index 0000000..4d98538 --- /dev/null +++ b/libsodium/port/randombytes_esp32.c @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "randombytes_internal.h" +#include "esp_system.h" + +static const char *randombytes_esp32xx_implementation_name(void) +{ + return CONFIG_IDF_TARGET; +} + +/* + Plug the ESP32 hardware RNG into libsodium's custom RNG support, as per + https://download.libsodium.org/doc/advanced/custom_rng.html + + Note that this RNG is selected by default (see randombytes_default.h), so there + is no need to call randombytes_set_implementation(). +*/ +const struct randombytes_implementation randombytes_esp32_implementation = { + .implementation_name = randombytes_esp32xx_implementation_name, + .random = esp_random, + .stir = NULL, + .uniform = NULL, + .buf = esp_fill_random, + .close = NULL, +}; diff --git a/libsodium/port/randombytes_internal.h b/libsodium/port/randombytes_internal.h new file mode 100644 index 0000000..35da42d --- /dev/null +++ b/libsodium/port/randombytes_internal.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +# include "export.h" +# include "randombytes.h" + +SODIUM_EXPORT +extern const struct randombytes_implementation randombytes_esp32_implementation; + +/* Defining RANDOMBYTES_DEFAULT_IMPLEMENTATION here allows us to compile with the ESP32 hardware + implementation as the default. No need to call randombytes_set_implementation(). + + Doing it in the header like this is easier than passing it via a -D argument to gcc. +*/ +#undef RANDOMBYTES_DEFAULT_IMPLEMENTATION +#define RANDOMBYTES_DEFAULT_IMPLEMENTATION &randombytes_esp32_implementation diff --git a/libsodium/port_include/sodium/version.h b/libsodium/port_include/sodium/version.h new file mode 100644 index 0000000..6ca9192 --- /dev/null +++ b/libsodium/port_include/sodium/version.h @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef sodium_version_H +#define sodium_version_H + +#include + +/* IMPORTANT: As we don't use autotools, these version are not automatically + updated if we change submodules. They need to be changed manually. +*/ + +#define SODIUM_VERSION_STRING "1.0.18-idf" + +/* Note: these are not the same as the overall version, see + configure.ac for the relevant macros */ +#define SODIUM_LIBRARY_VERSION_MAJOR 10 +#define SODIUM_LIBRARY_VERSION_MINOR 3 + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +const char *sodium_version_string(void); + +SODIUM_EXPORT +int sodium_library_version_major(void); + +SODIUM_EXPORT +int sodium_library_version_minor(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libsodium/test/CMakeLists.txt b/libsodium/test/CMakeLists.txt new file mode 100644 index 0000000..41de273 --- /dev/null +++ b/libsodium/test/CMakeLists.txt @@ -0,0 +1,36 @@ +if(TESTS_ALL EQUAL 1) + message("not linking libsodium tests, use '-T libsodium' to test it") +else() + get_filename_component(LS_TESTDIR "${CMAKE_CURRENT_LIST_DIR}/../libsodium/test/default" ABSOLUTE) + + set(TEST_CASES "chacha20;aead_chacha20poly1305;box;box2;ed25519_convert;sign;hash") + + foreach(test_case ${TEST_CASES}) + file(GLOB test_case_file "${LS_TESTDIR}/${test_case}.c") + list(APPEND TEST_CASES_FILES ${test_case_file}) + endforeach() + + idf_component_register(SRCS "${TEST_CASES_FILES}" "test_sodium.c" + PRIV_INCLUDE_DIRS "." "${LS_TESTDIR}/../quirks" + PRIV_REQUIRES cmock libsodium) + + # The libsodium test suite is designed to be run each test case as an executable on a desktop computer and uses + # filesytem to write & then compare contents of each file. + # + # For now, use their "BROWSER_TEST" mode with these hacks so that + # multiple test cases can be combined into one ELF file. + # + # Run each test case from test_sodium.c as CASENAME_xmain(). + foreach(test_case_file ${TEST_CASES_FILES}) + get_filename_component(test_case ${test_case_file} NAME_WE) + set_source_files_properties(${test_case_file} + PROPERTIES COMPILE_FLAGS + # This would generate 'warning "main" redefined' warnings at runtime, which are + # silenced here. Only other solution involves patching libsodium's cmptest.h. + "-Dxmain=${test_case}_xmain -Dmain=${test_case}_main -Wp,-w") + endforeach() + + # this seems odd, but it prevents the libsodium test harness from + # trying to write to a file! + add_definitions(-DBROWSER_TESTS) +endif() diff --git a/libsodium/test/test_sodium.c b/libsodium/test/test_sodium.c new file mode 100644 index 0000000..22455dc --- /dev/null +++ b/libsodium/test/test_sodium.c @@ -0,0 +1,124 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "unity.h" +#include "sodium/crypto_hash_sha256.h" +#include "sodium/crypto_hash_sha512.h" + +/* Note: a lot of these libsodium test programs assert() things, but they're not complete unit tests - most expect + output to be compared to the matching .exp file. + + We don't do this automatically yet, maybe once we have more options for + internal filesystem storage. +*/ + +extern int aead_chacha20poly1305_xmain(void); + +TEST_CASE("aead_chacha20poly1305 test vectors", "[libsodium]") +{ + printf("Running aead_chacha20poly1305\n"); + TEST_ASSERT_EQUAL(0, aead_chacha20poly1305_xmain()); +} + +extern int chacha20_xmain(void); + +TEST_CASE("chacha20 test vectors", "[libsodium]") +{ + printf("Running chacha20\n"); + TEST_ASSERT_EQUAL(0, chacha20_xmain()); +} + +extern int box_xmain(void); +extern int box2_xmain(void); + +TEST_CASE("box tests", "[libsodium]") +{ + printf("Running box\n"); + TEST_ASSERT_EQUAL(0, box_xmain()); + + printf("Running box2\n"); + TEST_ASSERT_EQUAL(0, box2_xmain()); +} + +extern int ed25519_convert_xmain(void); + +TEST_CASE("ed25519_convert tests", "[libsodium][timeout=60]") +{ + printf("Running ed25519_convert\n"); + TEST_ASSERT_EQUAL(0, ed25519_convert_xmain() ); +} + +extern int sign_xmain(void); + +TEST_CASE("sign tests", "[libsodium]") +{ + printf("Running sign\n"); + TEST_ASSERT_EQUAL(0, sign_xmain() ); +} + +extern int hash_xmain(void); + +TEST_CASE("hash tests", "[libsodium]") +{ + printf("Running hash\n"); + TEST_ASSERT_EQUAL(0, hash_xmain() ); +} + +TEST_CASE("sha256 sanity check", "[libsodium]") +{ + const uint8_t expected[] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, + 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, + 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, + 0x61, 0xf2, 0x00, 0x15, 0xad, }; + uint8_t calculated[32]; + crypto_hash_sha256_state state; + + const uint8_t *in = (const uint8_t *)"abc"; + const size_t inlen = 3; + + // One-liner version + crypto_hash_sha256(calculated, in, inlen); + TEST_ASSERT_EQUAL(sizeof(calculated), sizeof(expected)); + TEST_ASSERT_EQUAL(sizeof(calculated), crypto_hash_sha256_bytes()); + TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha256_bytes()); + + // Multi-line version + crypto_hash_sha256_init(&state); + crypto_hash_sha256_update(&state, in, inlen - 1); // split into two updates + crypto_hash_sha256_update(&state, in + (inlen -1), 1); + crypto_hash_sha256_final(&state, calculated); + TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha256_bytes()); +} + +TEST_CASE("sha512 sanity check", "[libsodium]") +{ + const uint8_t expected[] = { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, + 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, + 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, + 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, + 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, + 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, + 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, + 0x9f }; + + uint8_t calculated[64]; + crypto_hash_sha512_state state; + + const uint8_t *in = (const uint8_t *)"abc"; + const size_t inlen = 3; + + // One-liner version + crypto_hash_sha512(calculated, in, inlen); + TEST_ASSERT_EQUAL(sizeof(calculated), sizeof(expected)); + TEST_ASSERT_EQUAL(sizeof(calculated), crypto_hash_sha512_bytes()); + TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha512_bytes()); + + // Multi-line version + crypto_hash_sha512_init(&state); + crypto_hash_sha512_update(&state, in, inlen - 1); // split into two updates + crypto_hash_sha512_update(&state, in + (inlen -1), 1); + crypto_hash_sha512_final(&state, calculated); + TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha512_bytes()); +} diff --git a/pid_ctrl/idf_component.yml b/pid_ctrl/idf_component.yml index 01a186b..9c21bb1 100644 --- a/pid_ctrl/idf_component.yml +++ b/pid_ctrl/idf_component.yml @@ -1,4 +1,5 @@ version: "0.1.0" description: Proportional-integral-derivative controller +url: https://github.com/espressif/idf-extra-components/tree/master/pid_ctrl dependencies: idf: ">=4.3" diff --git a/qrcode/idf_component.yml b/qrcode/idf_component.yml index 55d12d1..7f41493 100644 --- a/qrcode/idf_component.yml +++ b/qrcode/idf_component.yml @@ -1,4 +1,5 @@ version: "0.1.0" description: QR Code generator +url: https://github.com/espressif/idf-extra-components/tree/master/qr_code dependencies: idf: ">=4.3"