mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-16 10:39:49 +00:00
Drop x25519, use p256 only
This commit is contained in:
1 parent
b68da1548b
commit
37f3ed5ba4
87 files changed
+12928
-32874
No files matched your search
@@ -165,7 +165,7 @@ jobs:
|
||||
- run: |
|
||||
sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
if [[ "${{ matrix.target }}" == *port* ]]; then source ./test/setup_ga_network.sh ; export ENV="-e Tmp=. -e WINEDEBUG=-all -e HOST_IP -e HOST_IPV6 -e HOST_IFC" ; sed -i -e "s/127.0.0.1//" test/mosquitto.conf; cat test/mosquitto.conf; ./test/setup_mqtt_server.sh ; make -C test port_tap_bridge ; test/port_tap_bridge & sleep 2 ; fi
|
||||
make -C test ${{ matrix.target }} IPV6=${{ matrix.ipv6 }} SSL=${{ matrix.ssl }} MULTIREC=NO
|
||||
make -C test ${{ matrix.target }} IPV6=${{ matrix.ipv6 }} SSL=${{ matrix.ssl }}
|
||||
|
||||
miprtxbe:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -180,7 +180,7 @@ jobs:
|
||||
- run: |
|
||||
sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
source ./test/setup_ga_network.sh ; export ENV="-e Tmp=. -e WINEDEBUG=-all -e HOST_IP -e HOST_IPV6 -e HOST_IFC -e RTX" ; sed -i -e "s/127.0.0.1//" test/mosquitto.conf ; ./test/setup_mqtt_server.sh ; make -C test port_tap_bridge ; test/port_tap_bridge & sleep 2
|
||||
make -C test mip_port_s390 MULTIREC=NO
|
||||
make -C test mip_port_s390
|
||||
|
||||
l2:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -354,7 +354,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with: { fetch-depth: 2 }
|
||||
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }} MULTIREC=NO
|
||||
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }}
|
||||
armhf:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -367,7 +367,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with: { fetch-depth: 2 }
|
||||
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }} MULTIREC=NO
|
||||
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }}
|
||||
unamalgamated-mg_prefix:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
|
||||
+5862
-3777
File diff suppressed because it is too large.
Load diff
+231
-664
@@ -1486,10 +1486,28 @@ struct timeval {
|
||||
#define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_TLS_RECORD_SIZE
|
||||
#define MG_TLS_RECORD_SIZE 16384 // Max plaintext per sent TLS record, builtin
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_CHACHA20
|
||||
#define MG_ENABLE_CHACHA20 1 // When set to 0, GCM is used. For MG_TLS_BUILTIN
|
||||
#endif
|
||||
|
||||
// P-256 implementation, for MG_TLS_BUILTIN
|
||||
#define MG_P256_LENNGREN 1 // Cortex-M4/M7/M33 asm, see tls_p256_cortex.c
|
||||
#define MG_P256_BEAR 3 // Portable C, BearSSL, see tls_p256.c
|
||||
|
||||
#ifndef MG_P256
|
||||
#if defined(__GNUC__) && defined(__ARM_ARCH_PROFILE) && \
|
||||
__ARM_ARCH_PROFILE == 'M' && defined(__ARM_FEATURE_DSP) && \
|
||||
!defined(__ARM_BIG_ENDIAN)
|
||||
#define MG_P256 MG_P256_LENNGREN // Cortex-M with DSP: M4, M7, M33, M55, M85
|
||||
#else
|
||||
#define MG_P256 MG_P256_BEAR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_HEALTH
|
||||
#define MG_ENABLE_HEALTH 0
|
||||
#endif
|
||||
@@ -2964,26 +2982,13 @@ void mg_tls_ctx_free(struct mg_mgr *);
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
// Extracts a 32-byte P-256 private scalar from EC PRIVATE KEY or PKCS#8 PRIVATE
|
||||
// KEY input. Accepts PEM or DER. Returns key size, or 0 on error.
|
||||
size_t mg_uecc_parse_private_key(struct mg_str key, uint8_t *buf, size_t len);
|
||||
size_t mg_p256_parse_private_key(struct mg_str key, uint8_t *buf, size_t len);
|
||||
#endif
|
||||
|
||||
// Low-level IO primitives used by TLS layer
|
||||
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2 };
|
||||
long mg_io_send(struct mg_connection *c, const void *buf, size_t len);
|
||||
long mg_io_recv(struct mg_connection *c, void *buf, size_t len);
|
||||
#ifndef TLS_X15519_H
|
||||
#define TLS_X15519_H
|
||||
|
||||
|
||||
|
||||
#define X25519_BYTES 32
|
||||
extern const uint8_t X25519_BASE_POINT[X25519_BYTES];
|
||||
|
||||
int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES],
|
||||
const uint8_t x1[X25519_BYTES], int clamp);
|
||||
|
||||
|
||||
#endif /* TLS_X15519_H */
|
||||
/******************************************************************************
|
||||
*
|
||||
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
|
||||
@@ -3052,665 +3057,227 @@ int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||
#endif /* TLS_AES128_H */
|
||||
|
||||
// End of aes128 PD
|
||||
// P-256 API, mg_p256_*(), used by built-in TLS, JWT and OTA. Implemented by
|
||||
// BearSSL code below (MG_P256=MG_P256_BEAR) or tls_p256_cortex.c (LENNGREN)
|
||||
// BearSSL code: https://bearssl.org commit 7bea48e. Shared bignum and ECDSA
|
||||
// code is always compiled, it is also used by P-384, see tls_p384.c
|
||||
//
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Mongoose changes: br_ / BR_ names are prefixed with mg_ / MG_, as are the
|
||||
// constant-time helpers from inner.h (NOT, MUX, EQ, ...). Structs are not
|
||||
// typedef-ed. ECDSA signing takes the caller's k instead of HMAC-DRBG, k is
|
||||
// computed by mg_p256_sign() (RFC 6979). ECDSA functions take the curve id and
|
||||
// public key directly
|
||||
|
||||
|
||||
|
||||
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_H_
|
||||
#define _UECC_H_
|
||||
|
||||
/* Platform selection options.
|
||||
If MG_UECC_PLATFORM is not defined, the code will try to guess it based on
|
||||
compiler macros. Possible values for MG_UECC_PLATFORM are defined below: */
|
||||
#define mg_uecc_arch_other 0
|
||||
#define mg_uecc_x86 1
|
||||
#define mg_uecc_x86_64 2
|
||||
#define mg_uecc_arm 3
|
||||
#define mg_uecc_arm_thumb 4
|
||||
#define mg_uecc_arm_thumb2 5
|
||||
#define mg_uecc_arm64 6
|
||||
#define mg_uecc_avr 7
|
||||
|
||||
/* If desired, you can define MG_UECC_WORD_SIZE as appropriate for your platform
|
||||
(1, 4, or 8 bytes). If MG_UECC_WORD_SIZE is not explicitly defined then it will
|
||||
be automatically set based on your platform. */
|
||||
|
||||
/* Optimization level; trade speed for code size.
|
||||
Larger values produce code that is faster but larger.
|
||||
Currently supported values are 0 - 4; 0 is unusably slow for most
|
||||
applications. Optimization level 4 currently only has an effect ARM platforms
|
||||
where more than one curve is enabled. */
|
||||
#ifndef MG_UECC_OPTIMIZATION_LEVEL
|
||||
#define MG_UECC_OPTIMIZATION_LEVEL 2
|
||||
#endif
|
||||
#if MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
|
||||
/* MG_UECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a
|
||||
specific function to be used for (scalar) squaring instead of the generic
|
||||
multiplication function. This can make things faster somewhat faster, but
|
||||
increases the code size. */
|
||||
#ifndef MG_UECC_SQUARE_FUNC
|
||||
#define MG_UECC_SQUARE_FUNC 0
|
||||
#endif
|
||||
#define MG_BR_EC_secp256r1 23 // Curve IDs, same as TLS named groups
|
||||
#define MG_BR_EC_secp384r1 24
|
||||
#define MG_BR_MAX_EC_SIZE 384 // Largest supported curve, bits
|
||||
|
||||
/* MG_UECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will
|
||||
switch to native little-endian format for *all* arrays passed in and out of the
|
||||
public API. This includes public and private keys, shared secrets, signatures
|
||||
and message hashes. Using this switch reduces the amount of call stack memory
|
||||
used by uECC, since less intermediate translations are required. Note that this
|
||||
will *only* work on native little-endian processors and it will treat the
|
||||
uint8_t arrays passed into the public API as word arrays, therefore requiring
|
||||
the provided byte arrays to be word aligned on architectures that do not support
|
||||
unaligned accesses. IMPORTANT: Keys and signatures generated with
|
||||
MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures
|
||||
generated with MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same
|
||||
endianness. */
|
||||
#ifndef MG_UECC_VLI_NATIVE_LITTLE_ENDIAN
|
||||
#define MG_UECC_VLI_NATIVE_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
// From BearSSL inc/bearssl_ec.h: an EC implementation
|
||||
struct mg_br_ec_impl {
|
||||
uint32_t supported_curves; // Bit mask of curve IDs
|
||||
const unsigned char *(*generator)(int curve, size_t *len);
|
||||
const unsigned char *(*order)(int curve, size_t *len);
|
||||
size_t (*xoff)(int curve, size_t *len);
|
||||
uint32_t (*mul)(unsigned char *G, size_t Glen, const unsigned char *x,
|
||||
size_t xlen, int curve);
|
||||
size_t (*mulgen)(unsigned char *R, const unsigned char *x, size_t xlen,
|
||||
int curve);
|
||||
uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *y, size_t ylen, int curve);
|
||||
};
|
||||
|
||||
/* Curve support selection. Set to 0 to remove that curve. */
|
||||
#ifndef MG_UECC_SUPPORTS_secp160r1
|
||||
#define MG_UECC_SUPPORTS_secp160r1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp192r1
|
||||
#define MG_UECC_SUPPORTS_secp192r1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp224r1
|
||||
#define MG_UECC_SUPPORTS_secp224r1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp256r1
|
||||
#define MG_UECC_SUPPORTS_secp256r1 1
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp256k1
|
||||
#define MG_UECC_SUPPORTS_secp256k1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp384r1
|
||||
#define MG_UECC_SUPPORTS_secp384r1 1
|
||||
#endif
|
||||
|
||||
/* Specifies whether compressed point format is supported.
|
||||
Set to 0 to disable point compression/decompression functions. */
|
||||
#ifndef MG_UECC_SUPPORT_COMPRESSED_POINT
|
||||
#define MG_UECC_SUPPORT_COMPRESSED_POINT 1
|
||||
#endif
|
||||
|
||||
struct MG_UECC_Curve_t;
|
||||
typedef const struct MG_UECC_Curve_t *MG_UECC_Curve;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MG_UECC_SUPPORTS_secp160r1
|
||||
MG_UECC_Curve mg_uecc_secp160r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp192r1
|
||||
MG_UECC_Curve mg_uecc_secp192r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp224r1
|
||||
MG_UECC_Curve mg_uecc_secp224r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp256r1
|
||||
MG_UECC_Curve mg_uecc_secp256r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp256k1
|
||||
MG_UECC_Curve mg_uecc_secp256k1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp384r1
|
||||
MG_UECC_Curve mg_uecc_secp384r1(void);
|
||||
#endif
|
||||
|
||||
/* MG_UECC_RNG_Function type
|
||||
The RNG function should fill 'size' random bytes into 'dest'. It should return 1
|
||||
if 'dest' was filled with random data, or 0 if the random data could not be
|
||||
generated. The filled-in values should be either truly random, or from a
|
||||
cryptographically-secure PRNG.
|
||||
|
||||
A correctly functioning RNG is required before calling mg_uecc_make_key() or
|
||||
mg_uecc_sign().
|
||||
|
||||
Setting a correctly functioning RNG function improves the resistance to
|
||||
side-channel attacks for mg_uecc_shared_secret() and
|
||||
mg_uecc_sign_deterministic().
|
||||
*/
|
||||
typedef int (*MG_UECC_RNG_Function)(uint8_t *dest, unsigned size);
|
||||
|
||||
// Mongoose: mg_uecc_make_key() and mg_uecc_sign() use mg_random() when no
|
||||
// explicit uECC RNG is installed. If mg_random() cannot provide a strong source,
|
||||
// those operations fail. Deterministic signing works without RNG, but only an
|
||||
// explicit uECC RNG enables its optional side-channel blinding.
|
||||
|
||||
/* mg_uecc_set_rng() function.
|
||||
Set the function that will be used to generate random bytes. The RNG function
|
||||
should return 1 if the random data was generated, or 0 if the random data could
|
||||
not be generated.
|
||||
|
||||
Mongoose: this overrides the default mg_random() fallback used by
|
||||
mg_uecc_make_key() and mg_uecc_sign(). Do not call mg_uecc_set_rng() unless the
|
||||
application must provide its own cryptographic RNG.
|
||||
|
||||
Inputs:
|
||||
rng_function - The function that will be used to generate random bytes.
|
||||
*/
|
||||
void mg_uecc_set_rng(MG_UECC_RNG_Function rng_function);
|
||||
|
||||
/* mg_uecc_get_rng() function.
|
||||
|
||||
Returns the function that will be used to generate random bytes.
|
||||
*/
|
||||
MG_UECC_RNG_Function mg_uecc_get_rng(void);
|
||||
|
||||
/* mg_uecc_curve_private_key_size() function.
|
||||
|
||||
Returns the size of a private key for the curve in bytes.
|
||||
*/
|
||||
int mg_uecc_curve_private_key_size(MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_curve_public_key_size() function.
|
||||
|
||||
Returns the size of a public key for the curve in bytes.
|
||||
*/
|
||||
int mg_uecc_curve_public_key_size(MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_make_key() function.
|
||||
Create a public/private key pair.
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the public key. Must be at least 2 *
|
||||
the curve size (in bytes) long. For example, if the curve is secp256r1,
|
||||
public_key must be 64 bytes long. private_key - Will be filled in with the
|
||||
private key. Must be as long as the curve order; this is typically the same as
|
||||
the curve size, except for secp160r1. For example, if the curve is secp256r1,
|
||||
private_key must be 32 bytes long.
|
||||
|
||||
For secp160r1, private_key must be 21 bytes long! Note that
|
||||
the first byte will almost always be 0 (there is about a 1 in 2^80 chance of it
|
||||
being non-zero).
|
||||
|
||||
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_make_key(uint8_t *public_key, uint8_t *private_key,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_shared_secret() function.
|
||||
Compute a shared secret given your secret key and someone else's public key. If
|
||||
the public key is not from a trusted source and has not been previously
|
||||
verified, you should verify it first using mg_uecc_valid_public_key(). Note: It
|
||||
is recommended that you hash the result of mg_uecc_shared_secret() before using
|
||||
it for symmetric encryption or HMAC.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key of the remote party.
|
||||
private_key - Your private key.
|
||||
|
||||
Outputs:
|
||||
secret - Will be filled in with the shared secret value. Must be the same
|
||||
size as the curve size; for example, if the curve is secp256r1, secret must be
|
||||
32 bytes long.
|
||||
|
||||
Returns 1 if the shared secret was generated successfully, 0 if an error
|
||||
occurred.
|
||||
*/
|
||||
int mg_uecc_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
|
||||
uint8_t *secret, MG_UECC_Curve curve);
|
||||
|
||||
#if MG_UECC_SUPPORT_COMPRESSED_POINT
|
||||
/* mg_uecc_compress() function.
|
||||
Compress a public key.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key to compress.
|
||||
|
||||
Outputs:
|
||||
compressed - Will be filled in with the compressed public key. Must be at
|
||||
least (curve size + 1) bytes long; for example, if the curve is secp256r1,
|
||||
compressed must be 33 bytes long.
|
||||
*/
|
||||
void mg_uecc_compress(const uint8_t *public_key, uint8_t *compressed,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_decompress() function.
|
||||
Decompress a compressed public key.
|
||||
|
||||
Inputs:
|
||||
compressed - The compressed public key.
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the decompressed public key.
|
||||
*/
|
||||
void mg_uecc_decompress(const uint8_t *compressed, uint8_t *public_key,
|
||||
MG_UECC_Curve curve);
|
||||
#endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */
|
||||
|
||||
/* mg_uecc_valid_public_key() function.
|
||||
Check to see if a public key is valid.
|
||||
|
||||
Note that you are not required to check for a valid public key before using any
|
||||
other uECC functions. However, you may wish to avoid spending CPU time computing
|
||||
a shared secret or verifying a signature using an invalid public key.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key to check.
|
||||
|
||||
Returns 1 if the public key is valid, 0 if it is invalid.
|
||||
*/
|
||||
int mg_uecc_valid_public_key(const uint8_t *public_key, MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_compute_public_key() function.
|
||||
Compute the corresponding public key for a private key.
|
||||
|
||||
Inputs:
|
||||
private_key - The private key to compute the public key for
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the corresponding public key
|
||||
|
||||
Returns 1 if the key was computed successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_sign() function.
|
||||
Generate an ECDSA signature for a given hash value.
|
||||
|
||||
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
|
||||
pass it in to this function along with your private key.
|
||||
|
||||
Inputs:
|
||||
private_key - Your private key.
|
||||
message_hash - The hash of the message to sign.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
|
||||
Outputs:
|
||||
signature - Will be filled in with the signature value. Must be at least 2 *
|
||||
curve size long. For example, if the curve is secp256r1, signature must be 64
|
||||
bytes long.
|
||||
|
||||
Returns 1 if the signature generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_sign(const uint8_t *private_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, uint8_t *signature, MG_UECC_Curve curve);
|
||||
|
||||
/* MG_UECC_HashContext structure.
|
||||
This is used to pass in an arbitrary hash function to
|
||||
mg_uecc_sign_deterministic(). The structure will be used for multiple hash
|
||||
computations; each time a new hash is computed, init_hash() will be called,
|
||||
followed by one or more calls to update_hash(), and finally a call to
|
||||
finish_hash() to produce the resulting hash.
|
||||
|
||||
The intention is that you will create a structure that includes
|
||||
MG_UECC_HashContext followed by any hash-specific data. For example:
|
||||
|
||||
typedef struct SHA256_HashContext {
|
||||
MG_UECC_HashContext uECC;
|
||||
SHA256_CTX ctx;
|
||||
} SHA256_HashContext;
|
||||
|
||||
void init_SHA256(MG_UECC_HashContext *base) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Init(&context->ctx);
|
||||
// From BearSSL src/inner.h: constant-time helpers
|
||||
static inline uint32_t MG_BR_NOT(uint32_t ctl) {
|
||||
return ctl ^ 1;
|
||||
}
|
||||
static inline uint32_t MG_BR_MUX(uint32_t ctl, uint32_t x, uint32_t y) {
|
||||
return y ^ (-ctl & (x ^ y));
|
||||
}
|
||||
static inline uint32_t MG_BR_EQ(uint32_t x, uint32_t y) {
|
||||
uint32_t q = x ^ y;
|
||||
return MG_BR_NOT((q | -q) >> 31);
|
||||
}
|
||||
static inline uint32_t MG_BR_NEQ(uint32_t x, uint32_t y) {
|
||||
uint32_t q = x ^ y;
|
||||
return (q | -q) >> 31;
|
||||
}
|
||||
static inline uint32_t MG_BR_GT(uint32_t x, uint32_t y) {
|
||||
uint32_t z = y - x;
|
||||
return (z ^ ((x ^ y) & (x ^ z))) >> 31;
|
||||
}
|
||||
#define MG_BR_GE(x, y) MG_BR_NOT(MG_BR_GT(y, x))
|
||||
#define MG_BR_LT(x, y) MG_BR_GT(y, x)
|
||||
static inline int32_t MG_BR_CMP(uint32_t x, uint32_t y) {
|
||||
return (int32_t) MG_BR_GT(x, y) | -(int32_t) MG_BR_GT(y, x);
|
||||
}
|
||||
static inline uint32_t MG_BR_BIT_LENGTH(uint32_t x) {
|
||||
uint32_t k, c;
|
||||
k = MG_BR_NEQ(x, 0);
|
||||
c = MG_BR_GT(x, 0xFFFF), x = MG_BR_MUX(c, x >> 16, x), k += c << 4;
|
||||
c = MG_BR_GT(x, 0x00FF), x = MG_BR_MUX(c, x >> 8, x), k += c << 3;
|
||||
c = MG_BR_GT(x, 0x000F), x = MG_BR_MUX(c, x >> 4, x), k += c << 2;
|
||||
c = MG_BR_GT(x, 0x0003), x = MG_BR_MUX(c, x >> 2, x), k += c << 1;
|
||||
k += MG_BR_GT(x, 0x0001);
|
||||
return k;
|
||||
}
|
||||
#define MG_BR_MUL31(x, y) ((uint64_t) (x) * (uint64_t) (y))
|
||||
#define MG_BR_MUL31_lo(x, y) \
|
||||
(((uint32_t) (x) * (uint32_t) (y)) & (uint32_t) 0x7FFFFFFF)
|
||||
#define MG_BR_CCOPY mg_br_ccopy
|
||||
void mg_br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len);
|
||||
uint32_t mg_br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r);
|
||||
static inline uint32_t mg_br_rem(uint32_t hi, uint32_t lo, uint32_t d) {
|
||||
uint32_t r;
|
||||
mg_br_divrem(hi, lo, d, &r);
|
||||
return r;
|
||||
}
|
||||
static inline uint32_t mg_br_div(uint32_t hi, uint32_t lo, uint32_t d) {
|
||||
uint32_t r;
|
||||
return mg_br_divrem(hi, lo, d, &r);
|
||||
}
|
||||
static inline void mg_br_enc32be(void *dst, uint32_t x) {
|
||||
unsigned char *buf = (unsigned char *) dst;
|
||||
buf[0] = (unsigned char) (x >> 24), buf[1] = (unsigned char) (x >> 16);
|
||||
buf[2] = (unsigned char) (x >> 8), buf[3] = (unsigned char) x;
|
||||
}
|
||||
static inline void mg_br_i31_zero(uint32_t *x, uint32_t bit_len) {
|
||||
*x++ = bit_len;
|
||||
memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x);
|
||||
}
|
||||
|
||||
void update_SHA256(MG_UECC_HashContext *base,
|
||||
const uint8_t *message,
|
||||
unsigned message_size) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Update(&context->ctx, message, message_size);
|
||||
}
|
||||
|
||||
void finish_SHA256(MG_UECC_HashContext *base, uint8_t *hash_result) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Final(hash_result, &context->ctx);
|
||||
}
|
||||
|
||||
... when signing ...
|
||||
{
|
||||
uint8_t tmp[32 + 32 + 64];
|
||||
SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64,
|
||||
32, tmp}}; mg_uecc_sign_deterministic(key, message_hash, &ctx.uECC, signature);
|
||||
}
|
||||
*/
|
||||
typedef struct MG_UECC_HashContext {
|
||||
void (*init_hash)(const struct MG_UECC_HashContext *context);
|
||||
void (*update_hash)(const struct MG_UECC_HashContext *context,
|
||||
const uint8_t *message, unsigned message_size);
|
||||
void (*finish_hash)(const struct MG_UECC_HashContext *context,
|
||||
uint8_t *hash_result);
|
||||
unsigned
|
||||
block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
|
||||
unsigned
|
||||
result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
|
||||
uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size +
|
||||
block_size) bytes. */
|
||||
} MG_UECC_HashContext;
|
||||
|
||||
/* mg_uecc_sign_deterministic() function.
|
||||
Generate an ECDSA signature for a given hash value, using a deterministic
|
||||
algorithm (see RFC 6979). You do not need to set the RNG using mg_uecc_set_rng()
|
||||
before calling this function; however, if the RNG is defined it will improve
|
||||
resistance to side-channel attacks.
|
||||
|
||||
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
|
||||
pass it to this function along with your private key and a hash context. Note
|
||||
that the message_hash does not need to be computed with the same hash function
|
||||
used by hash_context.
|
||||
|
||||
Inputs:
|
||||
private_key - Your private key.
|
||||
message_hash - The hash of the message to sign.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
hash_context - A hash context to use.
|
||||
|
||||
Outputs:
|
||||
signature - Will be filled in with the signature value.
|
||||
|
||||
Returns 1 if the signature generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_sign_deterministic(const uint8_t *private_key,
|
||||
const uint8_t *message_hash, unsigned hash_size,
|
||||
const MG_UECC_HashContext *hash_context,
|
||||
uint8_t *signature, MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_verify() function.
|
||||
Verify an ECDSA signature.
|
||||
|
||||
Usage: Compute the hash of the signed data using the same hash as the signer and
|
||||
pass it to this function along with the signer's public key and the signature
|
||||
values (r and s).
|
||||
|
||||
Inputs:
|
||||
public_key - The signer's public key.
|
||||
message_hash - The hash of the signed data.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
signature - The signature value.
|
||||
|
||||
Returns 1 if the signature is valid, 0 if it is invalid.
|
||||
*/
|
||||
int mg_uecc_verify(const uint8_t *public_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, const uint8_t *signature,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _UECC_H_ */
|
||||
|
||||
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_TYPES_H_
|
||||
#define _UECC_TYPES_H_
|
||||
|
||||
#ifndef MG_UECC_PLATFORM
|
||||
#if defined(__AVR__) && __AVR__
|
||||
#define MG_UECC_PLATFORM mg_uecc_avr
|
||||
#elif defined(__thumb2__) || \
|
||||
defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm_thumb2
|
||||
#elif defined(__thumb__)
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm_thumb
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm
|
||||
#elif defined(__aarch64__)
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm64
|
||||
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \
|
||||
defined(__I86__)
|
||||
#define MG_UECC_PLATFORM mg_uecc_x86
|
||||
#elif defined(__amd64__) || defined(_M_X64)
|
||||
#define MG_UECC_PLATFORM mg_uecc_x86_64
|
||||
#else
|
||||
#define MG_UECC_PLATFORM mg_uecc_arch_other
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MG_UECC_ARM_USE_UMAAL
|
||||
#if (MG_UECC_PLATFORM == mg_uecc_arm) && (__ARM_ARCH >= 6)
|
||||
#define MG_UECC_ARM_USE_UMAAL 1
|
||||
#elif (MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && (__ARM_ARCH >= 6) && \
|
||||
(!defined(__ARM_ARCH_7M__) || !__ARM_ARCH_7M__)
|
||||
#define MG_UECC_ARM_USE_UMAAL 1
|
||||
#else
|
||||
#define MG_UECC_ARM_USE_UMAAL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MG_UECC_WORD_SIZE
|
||||
#if MG_UECC_PLATFORM == mg_uecc_avr
|
||||
#define MG_UECC_WORD_SIZE 1
|
||||
#elif (MG_UECC_PLATFORM == mg_uecc_x86_64 || MG_UECC_PLATFORM == mg_uecc_arm64)
|
||||
#define MG_UECC_WORD_SIZE 8
|
||||
#else
|
||||
#define MG_UECC_WORD_SIZE 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (MG_UECC_WORD_SIZE != 1) && (MG_UECC_WORD_SIZE != 4) && \
|
||||
(MG_UECC_WORD_SIZE != 8)
|
||||
#error "Unsupported value for MG_UECC_WORD_SIZE"
|
||||
#endif
|
||||
|
||||
#if ((MG_UECC_PLATFORM == mg_uecc_avr) && (MG_UECC_WORD_SIZE != 1))
|
||||
#pragma message("MG_UECC_WORD_SIZE must be 1 for AVR")
|
||||
#undef MG_UECC_WORD_SIZE
|
||||
#define MG_UECC_WORD_SIZE 1
|
||||
#endif
|
||||
|
||||
#if ((MG_UECC_PLATFORM == mg_uecc_arm || \
|
||||
MG_UECC_PLATFORM == mg_uecc_arm_thumb || \
|
||||
MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && \
|
||||
(MG_UECC_WORD_SIZE != 4))
|
||||
#pragma message("MG_UECC_WORD_SIZE must be 4 for ARM")
|
||||
#undef MG_UECC_WORD_SIZE
|
||||
#define MG_UECC_WORD_SIZE 4
|
||||
#endif
|
||||
|
||||
typedef int8_t wordcount_t;
|
||||
typedef int16_t bitcount_t;
|
||||
typedef int8_t cmpresult_t;
|
||||
|
||||
#if (MG_UECC_WORD_SIZE == 1)
|
||||
|
||||
typedef uint8_t mg_uecc_word_t;
|
||||
typedef uint16_t mg_uecc_dword_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x80
|
||||
#define MG_UECC_WORD_BITS 8
|
||||
#define MG_UECC_WORD_BITS_SHIFT 3
|
||||
#define MG_UECC_WORD_BITS_MASK 0x07
|
||||
|
||||
#elif (MG_UECC_WORD_SIZE == 4)
|
||||
|
||||
typedef uint32_t mg_uecc_word_t;
|
||||
typedef uint64_t mg_uecc_dword_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x80000000
|
||||
#define MG_UECC_WORD_BITS 32
|
||||
#define MG_UECC_WORD_BITS_SHIFT 5
|
||||
#define MG_UECC_WORD_BITS_MASK 0x01F
|
||||
|
||||
#elif (MG_UECC_WORD_SIZE == 8)
|
||||
|
||||
typedef uint64_t mg_uecc_word_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x8000000000000000U
|
||||
#define MG_UECC_WORD_BITS 64
|
||||
#define MG_UECC_WORD_BITS_SHIFT 6
|
||||
#define MG_UECC_WORD_BITS_MASK 0x03F
|
||||
|
||||
#endif /* MG_UECC_WORD_SIZE */
|
||||
|
||||
#endif /* _UECC_TYPES_H_ */
|
||||
|
||||
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_VLI_H_
|
||||
#define _UECC_VLI_H_
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
/* Functions for raw large-integer manipulation. These are only available
|
||||
if uECC.c is compiled with MG_UECC_ENABLE_VLI_API defined to 1. */
|
||||
#ifndef MG_UECC_ENABLE_VLI_API
|
||||
#define MG_UECC_ENABLE_VLI_API 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MG_UECC_ENABLE_VLI_API
|
||||
|
||||
void mg_uecc_vli_clear(mg_uecc_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison to zero - secure way to compare long integers */
|
||||
/* Returns 1 if vli == 0, 0 otherwise. */
|
||||
mg_uecc_word_t mg_uecc_vli_isZero(const mg_uecc_word_t *vli,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Returns nonzero if bit 'bit' of vli is set. */
|
||||
mg_uecc_word_t mg_uecc_vli_testBit(const mg_uecc_word_t *vli, bitcount_t bit);
|
||||
|
||||
/* Counts the number of bits required to represent vli. */
|
||||
bitcount_t mg_uecc_vli_numBits(const mg_uecc_word_t *vli,
|
||||
const wordcount_t max_words);
|
||||
|
||||
/* Sets dest = src. */
|
||||
void mg_uecc_vli_set(mg_uecc_word_t *dest, const mg_uecc_word_t *src,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison function - secure way to compare long integers */
|
||||
/* Returns one if left == right, zero otherwise */
|
||||
mg_uecc_word_t mg_uecc_vli_equal(const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison function - secure way to compare long integers */
|
||||
/* Returns sign of left - right, in constant time. */
|
||||
cmpresult_t mg_uecc_vli_cmp(const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, wordcount_t num_words);
|
||||
|
||||
/* Computes vli = vli >> 1. */
|
||||
void mg_uecc_vli_rshift1(mg_uecc_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left + right, returning carry. Can modify in place. */
|
||||
mg_uecc_word_t mg_uecc_vli_add(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = left - right, returning borrow. Can modify in place. */
|
||||
mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = left * right. Result must be 2 * num_words long. */
|
||||
void mg_uecc_vli_mult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left^2. Result must be 2 * num_words long. */
|
||||
void mg_uecc_vli_square(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left + right) % mod.
|
||||
Assumes that left < mod and right < mod, and that result does not overlap
|
||||
mod. */
|
||||
void mg_uecc_vli_modAdd(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left - right) % mod.
|
||||
Assumes that left < mod and right < mod, and that result does not overlap
|
||||
mod. */
|
||||
void mg_uecc_vli_modSub(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = product % mod, where product is 2N words long.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void mg_uecc_vli_mmod(mg_uecc_word_t *result, mg_uecc_word_t *product,
|
||||
const mg_uecc_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/* Calculates result = product (mod curve->p), where product is up to
|
||||
2 * curve->num_words long. */
|
||||
void mg_uecc_vli_mmod_fast(mg_uecc_word_t *result, mg_uecc_word_t *product,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* Computes result = (left * right) % mod.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void mg_uecc_vli_modMult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left * right) % curve->p. */
|
||||
void mg_uecc_vli_modMult_fast(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, MG_UECC_Curve curve);
|
||||
|
||||
/* Computes result = left^2 % mod.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void mg_uecc_vli_modSquare(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left^2 % curve->p. */
|
||||
void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* Computes result = (1 / input) % mod.*/
|
||||
void mg_uecc_vli_modInv(mg_uecc_word_t *result, const mg_uecc_word_t *input,
|
||||
const mg_uecc_word_t *mod, wordcount_t num_words);
|
||||
|
||||
#if MG_UECC_SUPPORT_COMPRESSED_POINT
|
||||
/* Calculates a = sqrt(a) (mod curve->p) */
|
||||
void mg_uecc_vli_mod_sqrt(mg_uecc_word_t *a, MG_UECC_Curve curve);
|
||||
#endif
|
||||
|
||||
/* Converts an integer in uECC native format to big-endian bytes. */
|
||||
void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
|
||||
const mg_uecc_word_t *native);
|
||||
/* Converts big-endian bytes to an integer in uECC native format. */
|
||||
void mg_uecc_vli_bytesToNative(mg_uecc_word_t *native, const uint8_t *bytes,
|
||||
int num_bytes);
|
||||
|
||||
unsigned mg_uecc_curve_num_words(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_bytes(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_bits(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_n_words(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_n_bytes(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_n_bits(MG_UECC_Curve curve);
|
||||
|
||||
const mg_uecc_word_t *mg_uecc_curve_p(MG_UECC_Curve curve);
|
||||
const mg_uecc_word_t *mg_uecc_curve_n(MG_UECC_Curve curve);
|
||||
const mg_uecc_word_t *mg_uecc_curve_G(MG_UECC_Curve curve);
|
||||
const mg_uecc_word_t *mg_uecc_curve_b(MG_UECC_Curve curve);
|
||||
|
||||
int mg_uecc_valid_point(const mg_uecc_word_t *point, MG_UECC_Curve curve);
|
||||
|
||||
/* Multiplies a point by a scalar. Points are represented by the X coordinate
|
||||
followed by the Y coordinate in the same array, both coordinates are
|
||||
curve->num_words long. Note that scalar must be curve->num_n_words long (NOT
|
||||
curve->num_words). */
|
||||
void mg_uecc_point_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point,
|
||||
const mg_uecc_word_t *scalar, MG_UECC_Curve curve);
|
||||
|
||||
/* Generates a random integer in the range 0 < random < top.
|
||||
Both random and top have num_words words. */
|
||||
int mg_uecc_generate_random_int(mg_uecc_word_t *random,
|
||||
const mg_uecc_word_t *top,
|
||||
wordcount_t num_words);
|
||||
|
||||
#endif /* MG_UECC_ENABLE_VLI_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _UECC_VLI_H_ */
|
||||
|
||||
// End of uecc BSD-2
|
||||
// Big integers, "i31" format, see BearSSL src/inner.h
|
||||
uint32_t mg_br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl);
|
||||
uint32_t mg_br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl);
|
||||
uint32_t mg_br_i31_bit_length(uint32_t *x, size_t xlen);
|
||||
uint32_t mg_br_i31_decode_mod(uint32_t *x, const void *src, size_t len,
|
||||
const uint32_t *m);
|
||||
void mg_br_i31_decode(uint32_t *x, const void *src, size_t len);
|
||||
void mg_br_i31_encode(void *dst, size_t len, const uint32_t *x);
|
||||
void mg_br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i);
|
||||
void mg_br_i31_to_monty(uint32_t *x, const uint32_t *m);
|
||||
uint32_t mg_br_i31_iszero(const uint32_t *x);
|
||||
void mg_br_i31_modpow(uint32_t *x, const unsigned char *e, size_t elen,
|
||||
const uint32_t *m, uint32_t m0i, uint32_t *t1,
|
||||
uint32_t *t2);
|
||||
void mg_br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
|
||||
const uint32_t *m, uint32_t m0i);
|
||||
void mg_br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m);
|
||||
uint32_t mg_br_i31_ninv31(uint32_t x);
|
||||
void mg_br_i31_rshift(uint32_t *x, int count);
|
||||
|
||||
// ECDSA, see BearSSL src/ec/ecdsa_i31_*.c. q is an uncompressed point
|
||||
void mg_br_ecdsa_i31_bits2int(uint32_t *x, const void *src, size_t len,
|
||||
uint32_t ebitlen);
|
||||
uint32_t mg_br_ecdsa_i31_vrfy_raw(const struct mg_br_ec_impl *impl, int curve,
|
||||
const void *hash, size_t hash_len,
|
||||
const unsigned char *q, size_t qlen,
|
||||
const void *sig, size_t sig_len);
|
||||
size_t mg_br_ecdsa_i31_sign_raw(const struct mg_br_ec_impl *impl, int curve,
|
||||
const void *hash, size_t hash_len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *k, void *sig);
|
||||
|
||||
// P-256 (secp256r1) API. Keys and signatures are big endian byte strings,
|
||||
// a public key is X || Y, a signature is r || s. Functions return 1 on
|
||||
// success, 0 on failure
|
||||
|
||||
// Generate a random key pair, using mg_random()
|
||||
int mg_p256_make_key(uint8_t public_key[64], uint8_t private_key[32]);
|
||||
|
||||
// Compute public key from a private key. Return 0 if private key is invalid
|
||||
int mg_p256_compute_public_key(const uint8_t private_key[32],
|
||||
uint8_t public_key[64]);
|
||||
|
||||
// ECDH. Validates the peer public key, returns 0 if it is not on the curve
|
||||
int mg_p256_shared_secret(const uint8_t public_key[64],
|
||||
const uint8_t private_key[32], uint8_t secret[32]);
|
||||
|
||||
// ECDSA sign with a deterministic k, RFC 6979 with HMAC-SHA256
|
||||
int mg_p256_sign(const uint8_t private_key[32], const uint8_t *hash,
|
||||
size_t hash_size, uint8_t signature[64]);
|
||||
|
||||
// ECDSA verify. Validates the public key
|
||||
int mg_p256_verify(const uint8_t public_key[64], const uint8_t *hash,
|
||||
size_t hash_size, const uint8_t signature[64]);
|
||||
|
||||
// Internal: ECDSA sign with a given k, 32 bytes big endian, in [1, n-1].
|
||||
// Provided by the selected implementation, used by mg_p256_sign()
|
||||
int mg_p256_sign_with_k(const uint8_t private_key[32], const uint8_t *hash,
|
||||
size_t hash_size, const uint8_t k[32],
|
||||
uint8_t signature[64]);
|
||||
#endif // MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
// P-384 from BearSSL, https://bearssl.org commit 7bea48e
|
||||
// P-384 signature verification, used by built-in TLS for certificates and
|
||||
// CertificateVerify. Shared bignum and ECDSA code is in tls_p256.c
|
||||
//
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Mongoose changes: br_ / BR_ names are prefixed with mg_ / MG_, static
|
||||
// functions with p384_. Trimmed to P-384. Structs are not typedef-ed
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
// Verify ECDSA P-384 signature r || s over hash. Public key is X || Y.
|
||||
// Return 1 on success, 0 on failure
|
||||
int mg_p384_verify(const uint8_t public_key[96], const uint8_t *hash,
|
||||
size_t hash_size, const uint8_t signature[96]);
|
||||
#endif // MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
// portable8439 v1.0.1
|
||||
// Source: https://github.com/DavyLandman/portable8439
|
||||
// Licensed under CC0-1.0
|
||||
@@ -5425,9 +4992,6 @@ void mg_bsd_poll(struct mg_mgr *);
|
||||
#endif
|
||||
|
||||
#if MG_ENABLE_BSD_PROTOTYPES
|
||||
#if defined(FD_SET) || defined(FD_ZERO) || defined(FD_ISSET)
|
||||
#error "Include mongoose.h before system select headers"
|
||||
#endif
|
||||
typedef unsigned int socklen_t;
|
||||
typedef unsigned long nfds_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
@@ -5471,6 +5035,8 @@ struct pollfd { int fd; short events; short revents; };
|
||||
#ifndef FD_SETSIZE
|
||||
#define FD_SETSIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef FD_ZERO
|
||||
#define _NFDBITS ((int) sizeof(__fd_mask) * 8)
|
||||
#define _howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||
typedef struct fd_set {
|
||||
@@ -5487,6 +5053,7 @@ typedef struct fd_set {
|
||||
size_t _n = _howmany(FD_SETSIZE, _NFDBITS); \
|
||||
while (_n > 0) _p->__fds_bits[--_n] = 0; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define h_addr h_addr_list[0]
|
||||
#define AF_INET 2
|
||||
|
||||
@@ -13,9 +13,10 @@ Primary files:
|
||||
- `src/tls_dummy.c`
|
||||
- `src/tls_mbed.c`
|
||||
- `src/tls_openssl.c`
|
||||
- `src/tls_p256_cortex.c`
|
||||
- `src/tls_p256.c`
|
||||
- `src/tls_p384.c`
|
||||
- `src/tls_rsa.c`
|
||||
- `src/tls_uecc.c`
|
||||
- `src/tls_x25519.c`
|
||||
|
||||
Perform a focused security review centered on these files and this security surface.
|
||||
|
||||
@@ -38,6 +39,6 @@ Trace attacker-controlled TLS peer input through normal client and server execut
|
||||
- Verify that wildcard matching is applied only to certificate presented identifiers, not to arbitrary reference identifiers or general DNS glob matching.
|
||||
- Review `mg_match` or other glob/matching helpers if used for certificate identity checks, authorization checks, filesystem paths, routing, or topic matching. Flag cases where glob semantics are broader than the security policy requires.
|
||||
- Check certificate parsing for DER/PEM boundary errors, length overflows, malformed ASN.1, extension parsing mistakes, name constraints, SAN vs CN precedence, embedded NUL, and invalid string type handling.
|
||||
- Review TLS record parsing, handshake transcript handling, key schedule, random generation, ECC/X25519 operations, AES-GCM nonce/tag handling, and error handling for memory safety and authentication failures.
|
||||
- Review TLS record parsing, handshake transcript handling, key schedule, random generation, ECC (P-256, P-384) operations, AES-GCM nonce/tag handling, and error handling for memory safety and authentication failures.
|
||||
- Flag any behavior that silently falls back from verified TLS to unverified TLS or plaintext.
|
||||
- Check that TLS receive/send error paths cannot corrupt connection state, reuse freed buffers, or continue processing unauthenticated plaintext as encrypted data.
|
||||
+26
-20
@@ -3,9 +3,9 @@
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"serialNumber": "urn:uuid:d3f8b1e2-4a7c-4d9e-bf2a-1c3e5f7a9b0d",
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"metadata": {
|
||||
"timestamp": "2026-08-12T00:00:00Z",
|
||||
"timestamp": "2026-10-13T00:00:00Z",
|
||||
"component": {
|
||||
"type": "library",
|
||||
"bom-ref": "mongoose",
|
||||
@@ -34,14 +34,31 @@
|
||||
"components": [
|
||||
{
|
||||
"type": "library",
|
||||
"bom-ref": "micro-ecc",
|
||||
"author": "Kenneth MacKay",
|
||||
"name": "micro-ecc",
|
||||
"description": "ECC point operations on GF(p) curves (secp256r1). Used by Mongoose built-in TLS 1.3 for ECDH key exchange and ECDSA signatures. Source: src/tls_uecc.c, src/tls_uecc.h.",
|
||||
"licenses": [ { "expression": "BSD-2-Clause" } ],
|
||||
"purl": "pkg:github/kmackay/micro-ecc",
|
||||
"bom-ref": "bearssl-ec",
|
||||
"author": "Thomas Pornin",
|
||||
"name": "BearSSL EC (P-256, P-384, ECDSA)",
|
||||
"description": "P-256 (ec_p256_m31) and P-384 (ec_prime_i31) elliptic curve arithmetic, ECDSA sign and verify, and the i31 bignum code they use, derived from BearSSL. Used by Mongoose built-in TLS 1.3 for ECDHE key exchange and ECDSA signatures, by JWT ES256 and by OTA firmware signature verification. Source: src/tls_p256.c, src/tls_p256.h, src/tls_p384.c, src/tls_p384.h.",
|
||||
"licenses": [ { "expression": "MIT" } ],
|
||||
"externalReferences": [
|
||||
{ "type": "vcs", "url": "https://github.com/kmackay/micro-ecc" }
|
||||
{ "type": "website", "url": "https://bearssl.org" }
|
||||
],
|
||||
"properties": [
|
||||
{ "name": "upstream-commit", "value": "7bea48e5e850ab4cafbe68d3765cdaba13a86d6f" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "library",
|
||||
"bom-ref": "p256-cortex-m4",
|
||||
"author": "Emil Lenngren, Shortcut Labs AB",
|
||||
"name": "P256-Cortex-M4",
|
||||
"description": "P-256 ECDH and ECDSA in Cortex-M assembly. Used by Mongoose built-in TLS 1.3 instead of the BearSSL P-256 code on Cortex-M cores with the DSP extension (M4, M7, M33, M55, M85). Source: src/tls_p256_cortex.c.",
|
||||
"licenses": [ { "expression": "MIT" } ],
|
||||
"purl": "pkg:github/Emill/P256-Cortex-M4@ecd3ec2222fc9e18b6b44c86bb7183971a2041fc",
|
||||
"externalReferences": [
|
||||
{ "type": "vcs", "url": "https://github.com/Emill/P256-Cortex-M4" }
|
||||
],
|
||||
"properties": [
|
||||
{ "name": "upstream-commit", "value": "ecd3ec2222fc9e18b6b44c86bb7183971a2041fc" }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -55,17 +72,6 @@
|
||||
{ "type": "website", "url": "https://bearssl.org" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "library",
|
||||
"bom-ref": "strobe-x25519",
|
||||
"author": "Cryptography Research, Inc. / Mike Hamburg",
|
||||
"name": "STROBE x25519 (adapted)",
|
||||
"description": "X25519 Diffie-Hellman function adapted from the STROBE project. Used by Mongoose built-in TLS 1.3 for ECDH key exchange. Source: src/tls_x25519.c.",
|
||||
"licenses": [ { "expression": "MIT" } ],
|
||||
"externalReferences": [
|
||||
{ "type": "website", "url": "https://strobe.sourceforge.io/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "library",
|
||||
"bom-ref": "sha1-reid",
|
||||
|
||||
@@ -60,9 +60,6 @@ void mg_bsd_poll(struct mg_mgr *);
|
||||
#endif
|
||||
|
||||
#if MG_ENABLE_BSD_PROTOTYPES
|
||||
#if defined(FD_SET) || defined(FD_ZERO) || defined(FD_ISSET)
|
||||
#error "Include mongoose.h before system select headers"
|
||||
#endif
|
||||
typedef unsigned int socklen_t;
|
||||
typedef unsigned long nfds_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
@@ -106,6 +103,8 @@ struct pollfd { int fd; short events; short revents; };
|
||||
#ifndef FD_SETSIZE
|
||||
#define FD_SETSIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef FD_ZERO
|
||||
#define _NFDBITS ((int) sizeof(__fd_mask) * 8)
|
||||
#define _howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||
typedef struct fd_set {
|
||||
@@ -122,6 +121,7 @@ typedef struct fd_set {
|
||||
size_t _n = _howmany(FD_SETSIZE, _NFDBITS); \
|
||||
while (_n > 0) _p->__fds_bits[--_n] = 0; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define h_addr h_addr_list[0]
|
||||
#define AF_INET 2
|
||||
|
||||
@@ -223,10 +223,28 @@
|
||||
#define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_TLS_RECORD_SIZE
|
||||
#define MG_TLS_RECORD_SIZE 16384 // Max plaintext per sent TLS record, builtin
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_CHACHA20
|
||||
#define MG_ENABLE_CHACHA20 1 // When set to 0, GCM is used. For MG_TLS_BUILTIN
|
||||
#endif
|
||||
|
||||
// P-256 implementation, for MG_TLS_BUILTIN
|
||||
#define MG_P256_LENNGREN 1 // Cortex-M4/M7/M33 asm, see tls_p256_cortex.c
|
||||
#define MG_P256_BEAR 3 // Portable C, BearSSL, see tls_p256.c
|
||||
|
||||
#ifndef MG_P256
|
||||
#if defined(__GNUC__) && defined(__ARM_ARCH_PROFILE) && \
|
||||
__ARM_ARCH_PROFILE == 'M' && defined(__ARM_FEATURE_DSP) && \
|
||||
!defined(__ARM_BIG_ENDIAN)
|
||||
#define MG_P256 MG_P256_LENNGREN // Cortex-M with DSP: M4, M7, M33, M55, M85
|
||||
#else
|
||||
#define MG_P256 MG_P256_BEAR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_HEALTH
|
||||
#define MG_ENABLE_HEALTH 0
|
||||
#endif
|
||||
+3
-4
@@ -4,7 +4,7 @@
|
||||
#include "ota.h"
|
||||
#ifdef MG_OTA_PUBLIC_KEY
|
||||
#include "sha256.h"
|
||||
#include "tls_uecc.h"
|
||||
#include "tls_p256.h"
|
||||
#endif
|
||||
|
||||
#if MG_OTA != MG_OTA_NONE && MG_OTA != MG_OTA_CUSTOM
|
||||
@@ -76,9 +76,8 @@ bool mg_ota_flash_end(struct mg_flash *flash) {
|
||||
uint8_t hash[32];
|
||||
size_t fw_size = s_size - 68; // strip 64-byte sig + 4-byte magic
|
||||
mg_sha256(hash, (uint8_t *) base, fw_size);
|
||||
ok = mg_uecc_verify(s_pubkey, hash, sizeof(hash),
|
||||
(uint8_t *) base + fw_size,
|
||||
mg_uecc_secp256r1()) == 1;
|
||||
ok = mg_p256_verify(s_pubkey, hash, sizeof(hash),
|
||||
(uint8_t *) base + fw_size) == 1;
|
||||
MG_INFO(("Signature: %s", ok ? "ok" : "fail"));
|
||||
} else {
|
||||
ok = false;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "util.h"
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
#include "tls_uecc.h"
|
||||
#include "tls_p256.h"
|
||||
#endif
|
||||
|
||||
static size_t jwt_split(struct mg_str jwt, struct mg_str *h, struct mg_str *p,
|
||||
@@ -95,39 +95,14 @@ size_t mg_jwt_verify_hs256(struct mg_str jwt, const struct mg_jwt_opts *opts,
|
||||
}
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
typedef struct {
|
||||
MG_UECC_HashContext uECC;
|
||||
mg_sha256_ctx sha256;
|
||||
} jwt_hash_ctx;
|
||||
|
||||
static void jwt_hash_init(const MG_UECC_HashContext *ctx) {
|
||||
jwt_hash_ctx *c = (jwt_hash_ctx *) ctx;
|
||||
mg_sha256_init(&c->sha256);
|
||||
}
|
||||
|
||||
static void jwt_hash_update(const MG_UECC_HashContext *ctx, const uint8_t *msg,
|
||||
unsigned len) {
|
||||
jwt_hash_ctx *c = (jwt_hash_ctx *) ctx;
|
||||
mg_sha256_update(&c->sha256, msg, len);
|
||||
}
|
||||
|
||||
static void jwt_hash_finish(const MG_UECC_HashContext *ctx, uint8_t *hash) {
|
||||
jwt_hash_ctx *c = (jwt_hash_ctx *) ctx;
|
||||
mg_sha256_final(hash, &c->sha256);
|
||||
}
|
||||
|
||||
size_t mg_jwt_sign_es256(const struct mg_jwt_opts *opts, char *buf,
|
||||
size_t len) {
|
||||
uint8_t hash[32], sig[64], tmp[2 * 32 + 64];
|
||||
jwt_hash_ctx ctx = {
|
||||
{jwt_hash_init, jwt_hash_update, jwt_hash_finish, 64, 32, tmp},
|
||||
{{0}, 0, 0, {0}}};
|
||||
uint8_t hash[32], sig[64];
|
||||
size_t n = jwt_header_payload("ES256", opts, buf, len);
|
||||
size_t m;
|
||||
if (n == 0 || n + 1 >= len) return 0;
|
||||
mg_sha256(hash, (uint8_t *) buf, n);
|
||||
if (mg_uecc_sign_deterministic(opts->private_key, hash, sizeof(hash),
|
||||
&ctx.uECC, sig, mg_uecc_secp256r1()) != 1)
|
||||
if (mg_p256_sign(opts->private_key, hash, sizeof(hash), sig) != 1)
|
||||
return 0;
|
||||
buf[n++] = '.';
|
||||
m = mg_base64url_encode(sig, sizeof(sig), buf + n, len - n);
|
||||
@@ -143,8 +118,7 @@ size_t mg_jwt_verify_es256(struct mg_str jwt, const struct mg_jwt_opts *opts,
|
||||
if (mg_base64url_decode(s.buf, s.len, (char *) sig, sizeof(sig)) != 64)
|
||||
return 0;
|
||||
mg_sha256(hash, (uint8_t *) jwt.buf, n);
|
||||
if (mg_uecc_verify(opts->public_key, hash, sizeof(hash), sig,
|
||||
mg_uecc_secp256r1()) != 1)
|
||||
if (mg_p256_verify(opts->public_key, hash, sizeof(hash), sig) != 1)
|
||||
return 0;
|
||||
return mg_base64url_decode(p.buf, p.len, buf, len);
|
||||
}
|
||||
|
||||
+7
-2
@@ -156,9 +156,13 @@ void mg_mdash_init(struct mg_mgr *mgr) {
|
||||
}
|
||||
|
||||
void mg_mdash_poll(struct mg_mgr *mgr) {
|
||||
#if MG_TLS == MG_TLS_NONE
|
||||
(void) mgr, (void) mg_mdash_fn; // mdash needs wss://, nothing to do
|
||||
#else
|
||||
static uint64_t timer = 0;
|
||||
// No RPC handlers means mdash was never set up, or mg_mdash_free() ran
|
||||
if (mg_mdash_conn == NULL && mgr->rpcs != NULL &&
|
||||
// No RPC handlers means mdash was never set up, or mg_mdash_free() ran.
|
||||
// No key means mdash would reject us, so do not connect at all
|
||||
if (mg_mdash_conn == NULL && mgr->rpcs != NULL && MG_MDASH_KEY[0] != '\0' &&
|
||||
mg_timer_expired(&timer, 1000, mg_millis())) {
|
||||
MG_INFO(("Connecting to %s", MG_MDASH_URL));
|
||||
mg_mdash_conn = mg_ws_connect(mgr, MG_MDASH_URL, mg_mdash_fn, NULL,
|
||||
@@ -166,6 +170,7 @@ void mg_mdash_poll(struct mg_mgr *mgr) {
|
||||
"Authorization: Bearer %s\r\n",
|
||||
MG_MDASH_URL, MG_MDASH_KEY);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mg_mdash_free(struct mg_mgr *mgr) {
|
||||
|
||||
@@ -90,7 +90,7 @@ void mg_tls_ctx_free(struct mg_mgr *);
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
// Extracts a 32-byte P-256 private scalar from EC PRIVATE KEY or PKCS#8 PRIVATE
|
||||
// KEY input. Accepts PEM or DER. Returns key size, or 0 on error.
|
||||
size_t mg_uecc_parse_private_key(struct mg_str key, uint8_t *buf, size_t len);
|
||||
size_t mg_p256_parse_private_key(struct mg_str key, uint8_t *buf, size_t len);
|
||||
#endif
|
||||
|
||||
// Low-level IO primitives used by TLS layer
|
||||
|
||||
+192
-171
@@ -6,8 +6,8 @@
|
||||
#include "tls_aes128.h"
|
||||
#include "tls_chacha20.h"
|
||||
#include "tls_rsa.h"
|
||||
#include "tls_uecc.h"
|
||||
#include "tls_x25519.h"
|
||||
#include "tls_p256.h"
|
||||
#include "tls_p384.h"
|
||||
#include "util.h"
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
@@ -61,6 +61,7 @@ enum mg_tls_hs_state {
|
||||
|
||||
// Server state machine:
|
||||
MG_TLS_STATE_SERVER_START, // Wait for ClientHello
|
||||
MG_TLS_STATE_SERVER_RETRY, // Wait for ClientHello after HelloRetry
|
||||
MG_TLS_STATE_SERVER_WAIT_CERT, // Wait for Certificate
|
||||
MG_TLS_STATE_SERVER_WAIT_CV, // Wait for CertificateVerify
|
||||
MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finish
|
||||
@@ -106,9 +107,9 @@ struct tls_data {
|
||||
|
||||
uint8_t random[32]; // client random from ClientHello
|
||||
uint8_t session_id[32]; // client session ID between the handshake states
|
||||
uint8_t x25519_cli[32]; // client X25519 key between the handshake states
|
||||
uint8_t p256_cli[32]; // client P-256 key between the handshake states
|
||||
uint8_t x25519_sec[32]; // ECDHE secret (X25519 or P-256) between the states
|
||||
uint8_t p256_peer[64]; // server: client P-256 public key X || Y
|
||||
uint8_t ecdhe_sec[32]; // P-256 ECDHE shared secret between the states
|
||||
|
||||
bool skip_verification; // do not perform checks on server certificate
|
||||
bool cert_requested; // client received a CertificateRequest
|
||||
@@ -132,6 +133,8 @@ struct tls_data {
|
||||
size_t pubkeysz; // size of the server public key
|
||||
uint8_t sighash[32]; // calculated signature verification hash
|
||||
uint8_t sighash384[48]; // same, SHA-384, for ecdsa_secp384r1_sha384
|
||||
uint64_t hs_start; // mg_millis() when the handshake started
|
||||
uint64_t hs_proc; // ms spent processing handshake messages
|
||||
|
||||
struct tls_enc enc; // actual keys in use at this time
|
||||
struct tls_enc app_keys; // storage during two-way auth handshake
|
||||
@@ -323,7 +326,7 @@ static void mg_tls_derive_secret(const char *label, uint8_t *key, size_t keysz,
|
||||
memmove(hash, secret, hashsz);
|
||||
}
|
||||
|
||||
// at this point we have x25519 shared secret, we can generate a set of derived
|
||||
// at this point we have ECDHE shared secret, we can generate a set of derived
|
||||
// handshake encryption keys
|
||||
static void mg_tls_generate_handshake_keys(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
@@ -344,12 +347,11 @@ static void mg_tls_generate_handshake_keys(struct mg_connection *c) {
|
||||
mg_tls_derive_secret("tls13 derived", early_secret, 32, zeros_sha256_digest,
|
||||
32, pre_extract_secret, 32);
|
||||
mg_hmac_sha256(tls->enc.handshake_secret, pre_extract_secret,
|
||||
sizeof(pre_extract_secret), tls->x25519_sec,
|
||||
sizeof(tls->x25519_sec));
|
||||
sizeof(pre_extract_secret), tls->ecdhe_sec,
|
||||
sizeof(tls->ecdhe_sec));
|
||||
// ECDHE keys and secret are not needed anymore, wipe for forward secrecy
|
||||
mg_bzero(tls->x25519_cli, sizeof(tls->x25519_cli));
|
||||
mg_bzero(tls->p256_cli, sizeof(tls->p256_cli));
|
||||
mg_bzero(tls->x25519_sec, sizeof(tls->x25519_sec));
|
||||
mg_bzero(tls->ecdhe_sec, sizeof(tls->ecdhe_sec));
|
||||
mg_tls_hexdump("hs secret", tls->enc.handshake_secret, 32);
|
||||
|
||||
// mg_sha256_final is not idempotent, need to copy sha256 context to calculate
|
||||
@@ -512,19 +514,20 @@ static bool mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg,
|
||||
|
||||
static void verbose_alert(uint8_t *buf) {
|
||||
uint8_t level = buf[0], desc = buf[1];
|
||||
MG_INFO(("TLS ALERT received: level=%d, desc=%d (%s)", level, desc,
|
||||
desc == 0 ? "close_notify"
|
||||
: desc == 10 ? "unexpected_message"
|
||||
: desc == 20 ? "bad_record_mac"
|
||||
: desc == 21 ? "decryption_failed"
|
||||
: desc == 40 ? "handshake_failure"
|
||||
: desc == 42 ? "bad_certificate"
|
||||
: desc == 43 ? "unsupported_certificate"
|
||||
: desc == 44 ? "certificate_revoked"
|
||||
: desc == 45 ? "certificate_expired"
|
||||
: desc == 46 ? "certificate_unknown"
|
||||
: desc == 48 ? "unknown_ca"
|
||||
: "unknown"));
|
||||
MG_LOG(desc == 0 ? MG_LL_VERBOSE : MG_LL_INFO, // close_notify is normal
|
||||
("TLS ALERT received: level=%d, desc=%d (%s)", level, desc,
|
||||
desc == 0 ? "close_notify"
|
||||
: desc == 10 ? "unexpected_message"
|
||||
: desc == 20 ? "bad_record_mac"
|
||||
: desc == 21 ? "decryption_failed"
|
||||
: desc == 40 ? "handshake_failure"
|
||||
: desc == 42 ? "bad_certificate"
|
||||
: desc == 43 ? "unsupported_certificate"
|
||||
: desc == 44 ? "certificate_revoked"
|
||||
: desc == 45 ? "certificate_expired"
|
||||
: desc == 46 ? "certificate_unknown"
|
||||
: desc == 48 ? "unknown_ca"
|
||||
: "unknown"));
|
||||
}
|
||||
|
||||
// read an encrypted record, decrypt it in place
|
||||
@@ -659,7 +662,8 @@ static void mg_tls_calc_cert_verify_hash(struct mg_connection *c,
|
||||
if (hash384 != NULL) mg_sha384(hash384, sig_content, sizeof(sig_content));
|
||||
}
|
||||
|
||||
// read and parse ClientHello record
|
||||
// read and parse ClientHello record. Return 0 if it has a P-256 key share,
|
||||
// 1 if it does not and HelloRetryRequest must be sent, negative otherwise
|
||||
static int mg_tls_server_recv_hello(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
struct mg_iobuf *rio = &c->rtls;
|
||||
@@ -669,9 +673,13 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) {
|
||||
uint16_t ext_len;
|
||||
uint8_t *ext;
|
||||
uint16_t msgsz;
|
||||
bool have_p256 = false;
|
||||
bool is_retry = tls->state == MG_TLS_STATE_SERVER_RETRY;
|
||||
|
||||
if (!mg_tls_got_record(c)) {
|
||||
return MG_IO_WAIT;
|
||||
for (;;) {
|
||||
if (!mg_tls_got_record(c)) return MG_IO_WAIT;
|
||||
if (!is_retry || rio->buf[0] != MG_TLS_CHANGE_CIPHER) break;
|
||||
mg_tls_drop_record(c); // compatibility mode CCS before 2nd ClientHello
|
||||
}
|
||||
if (rio->buf[0] != MG_TLS_HANDSHAKE || rio->buf[5] != MG_TLS_CLIENT_HELLO) {
|
||||
mg_error(c, "not a client hello packet");
|
||||
@@ -715,16 +723,21 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) {
|
||||
goto fail;
|
||||
for (k = 0; k < key_exchange_len;) {
|
||||
uint16_t m = MG_LOAD_BE16(key_exchange + k + 2);
|
||||
uint16_t group = MG_LOAD_BE16(key_exchange + k);
|
||||
if (((uint32_t) m + k + 4) > key_exchange_len) goto fail;
|
||||
if (m == 32 && key_exchange[k] == 0x00 && key_exchange[k + 1] == 0x1d) {
|
||||
memmove(tls->x25519_cli, key_exchange + k + 4, m);
|
||||
mg_tls_drop_record(c);
|
||||
return 0;
|
||||
// secp256r1, uncompressed point 0x04 || X || Y
|
||||
if (group == 0x0017 && m == 65 && key_exchange[k + 4] == 0x04) {
|
||||
memmove(tls->p256_peer, key_exchange + k + 5, 64);
|
||||
have_p256 = true;
|
||||
}
|
||||
k += (uint16_t) (m + 4);
|
||||
}
|
||||
j += (uint16_t) (n + 4);
|
||||
}
|
||||
if (have_p256 || !is_retry) { // No P-256 share: ask for it, but only once
|
||||
mg_tls_drop_record(c);
|
||||
return have_p256 ? 0 : 1;
|
||||
}
|
||||
fail:
|
||||
mg_error(c, "bad client hello");
|
||||
return -1;
|
||||
@@ -738,58 +751,98 @@ fail:
|
||||
static bool mg_tls_server_send_hello(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
struct mg_iobuf *wio = &tls->send;
|
||||
uint8_t hello[155], pub[65], prv[32], hdr[5] = {0x16, 0x03, 0x03, 0, 0};
|
||||
size_t n = sizeof(hello); // ServerHello length, including 4-byte header
|
||||
|
||||
// clang-format off
|
||||
uint8_t msg_server_hello[122] = {
|
||||
// server hello, tls 1.2
|
||||
0x02, 0x00, 0x00, 0x76, 0x03, 0x03,
|
||||
// random (32 bytes)
|
||||
PLACEHOLDER_32B,
|
||||
// session ID length + session ID (32 bytes)
|
||||
0x20, PLACEHOLDER_32B,
|
||||
#if MG_ENABLE_CHACHA20
|
||||
// TLS_CHACHA20_POLY1305_SHA256 + no compression
|
||||
0x13, 0x03, 0x00,
|
||||
#else
|
||||
// TLS_AES_128_GCM_SHA256 + no compression
|
||||
0x13, 0x01, 0x00,
|
||||
#endif
|
||||
// extensions + keyshare
|
||||
0x00, 0x2e, 0x00, 0x33, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20,
|
||||
// x25519 keyshare
|
||||
PLACEHOLDER_32B,
|
||||
// supported versions (tls1.3 == 0x304)
|
||||
0x00, 0x2b, 0x00, 0x02, 0x03, 0x04};
|
||||
// clang-format on
|
||||
|
||||
// calculate keyshare
|
||||
uint8_t x25519_pub[X25519_BYTES];
|
||||
uint8_t x25519_prv[X25519_BYTES];
|
||||
if (!mg_random(x25519_prv, sizeof(x25519_prv))) mg_error(c, "RNG");
|
||||
if( mg_tls_x25519(x25519_pub, x25519_prv, X25519_BASE_POINT, 1) < 0 || mg_tls_x25519(tls->x25519_sec, x25519_prv, tls->x25519_cli, 1) < 0) {
|
||||
// calculate P-256 keyshare and the shared secret
|
||||
pub[0] = 0x04; // uncompressed point 0x04 || X || Y
|
||||
if (!mg_p256_make_key(pub + 1, prv) ||
|
||||
!mg_p256_shared_secret(tls->p256_peer, prv, tls->ecdhe_sec)) {
|
||||
mg_bzero(prv, sizeof(prv));
|
||||
mg_error(c, "bad key");
|
||||
return false;
|
||||
}
|
||||
mg_tls_hexdump("s x25519 sec", tls->x25519_sec, sizeof(tls->x25519_sec));
|
||||
mg_bzero(prv, sizeof(prv));
|
||||
mg_tls_hexdump("s ecdhe sec", tls->ecdhe_sec, sizeof(tls->ecdhe_sec));
|
||||
|
||||
// fill in the gaps: random + session ID + keyshare
|
||||
memmove(msg_server_hello + 6, tls->random, sizeof(tls->random));
|
||||
memmove(msg_server_hello + 39, tls->session_id, sizeof(tls->session_id));
|
||||
memmove(msg_server_hello + 84, x25519_pub, sizeof(x25519_pub));
|
||||
hello[0] = 0x02; // server hello, tls 1.2
|
||||
MG_STORE_BE24(hello + 1, n - 4);
|
||||
hello[4] = 0x03, hello[5] = 0x03;
|
||||
if (!mg_random(hello + 6, 32)) { // server random, RFC 8446 4.1.3
|
||||
mg_error(c, "RNG");
|
||||
return false;
|
||||
}
|
||||
hello[38] = 0x20; // session ID length + session ID (32 bytes)
|
||||
memmove(hello + 39, tls->session_id, sizeof(tls->session_id));
|
||||
#if MG_ENABLE_CHACHA20
|
||||
hello[71] = 0x13, hello[72] = 0x03; // TLS_CHACHA20_POLY1305_SHA256
|
||||
#else
|
||||
hello[71] = 0x13, hello[72] = 0x01; // TLS_AES_128_GCM_SHA256
|
||||
#endif
|
||||
hello[73] = 0x00; // no compression
|
||||
MG_STORE_BE16(hello + 74, 65 + 14); // extensions length
|
||||
MG_STORE_BE16(hello + 76, 0x0033); // key share
|
||||
MG_STORE_BE16(hello + 78, 65 + 4);
|
||||
MG_STORE_BE16(hello + 80, 0x0017); // secp256r1
|
||||
MG_STORE_BE16(hello + 82, 65);
|
||||
memmove(hello + 84, pub, sizeof(pub));
|
||||
memmove(hello + 149, "\x00\x2b\x00\x02\x03\x04", 6); // tls1.3 == 0x304
|
||||
MG_STORE_BE16(hdr + 3, n);
|
||||
|
||||
// server hello message
|
||||
if (mg_iobuf_add(wio, wio->len, "\x16\x03\x03\x00\x7a", 5) == 0 ||
|
||||
mg_iobuf_add(wio, wio->len, msg_server_hello, sizeof(msg_server_hello)) ==
|
||||
0)
|
||||
if (mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr)) == 0 ||
|
||||
mg_iobuf_add(wio, wio->len, hello, n) == 0)
|
||||
return false;
|
||||
mg_sha256_update(&tls->sha256, msg_server_hello, sizeof(msg_server_hello));
|
||||
mg_sha256_update(&tls->sha256, hello, n);
|
||||
|
||||
// change cipher message
|
||||
if (mg_iobuf_add(wio, wio->len, "\x14\x03\x03\x00\x01\x01", 6) == 0)
|
||||
// change cipher message, unless it was already sent after HelloRetryRequest
|
||||
if (tls->state != MG_TLS_STATE_SERVER_RETRY &&
|
||||
mg_iobuf_add(wio, wio->len, "\x14\x03\x03\x00\x01\x01", 6) == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// HelloRetryRequest random, SHA-256 of "HelloRetryRequest", RFC 8446 4.1.3
|
||||
static const uint8_t hrr_random[32] = {
|
||||
0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c,
|
||||
0x02, 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb,
|
||||
0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c};
|
||||
|
||||
// put HelloRetryRequest record into wio buffer, asking for a P-256 key share.
|
||||
// Replace ClientHello in the transcript with message_hash, RFC 8446 4.4.1
|
||||
static bool mg_tls_server_send_hrr(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
struct mg_iobuf *wio = &tls->send;
|
||||
uint8_t hrr[88], hdr[5] = {0x16, 0x03, 0x03, 0, sizeof(hrr)};
|
||||
uint8_t mh[4 + 32] = {0xfe, 0, 0, 32}; // message_hash(ClientHello1)
|
||||
|
||||
hrr[0] = 0x02; // server hello, tls 1.2
|
||||
MG_STORE_BE24(hrr + 1, sizeof(hrr) - 4);
|
||||
hrr[4] = 0x03, hrr[5] = 0x03;
|
||||
memmove(hrr + 6, hrr_random, sizeof(hrr_random));
|
||||
hrr[38] = 0x20; // session ID length + session ID (32 bytes)
|
||||
memmove(hrr + 39, tls->session_id, sizeof(tls->session_id));
|
||||
#if MG_ENABLE_CHACHA20
|
||||
hrr[71] = 0x13, hrr[72] = 0x03; // TLS_CHACHA20_POLY1305_SHA256
|
||||
#else
|
||||
hrr[71] = 0x13, hrr[72] = 0x01; // TLS_AES_128_GCM_SHA256
|
||||
#endif
|
||||
hrr[73] = 0x00; // no compression
|
||||
// extensions: supported versions tls1.3, key share secp256r1 (group only)
|
||||
memmove(hrr + 74, "\x00\x0c\x00\x2b\x00\x02\x03\x04\x00\x33\x00\x02\x00\x17",
|
||||
14);
|
||||
|
||||
mg_sha256_final(mh + 4, &tls->sha256);
|
||||
mg_sha256_init(&tls->sha256);
|
||||
mg_sha256_update(&tls->sha256, mh, sizeof(mh));
|
||||
mg_sha256_update(&tls->sha256, hrr, sizeof(hrr));
|
||||
|
||||
// HelloRetryRequest message, followed by change cipher message
|
||||
return mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr)) != 0 &&
|
||||
mg_iobuf_add(wio, wio->len, hrr, sizeof(hrr)) != 0 &&
|
||||
mg_iobuf_add(wio, wio->len, "\x14\x03\x03\x00\x01\x01", 6) != 0;
|
||||
}
|
||||
|
||||
static bool mg_tls_server_send_ext(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
// server extensions
|
||||
@@ -799,14 +852,10 @@ static bool mg_tls_server_send_ext(struct mg_connection *c) {
|
||||
}
|
||||
|
||||
// signature algorithms we actually support: ecdsa_secp256r1_sha256,
|
||||
// ecdsa_secp384r1_sha384 (if enabled), rsa_pss_rsae_sha256, rsa_pkcs1_sha256
|
||||
// ecdsa_secp384r1_sha384, rsa_pss_rsae_sha256, rsa_pkcs1_sha256
|
||||
static const uint8_t secp256r1_sig_algs[] = {
|
||||
#if MG_UECC_SUPPORTS_secp384r1
|
||||
0x00, 0x0d, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x03,
|
||||
0x05, 0x03, 0x08, 0x04, 0x04, 0x01};
|
||||
#else
|
||||
0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01};
|
||||
#endif
|
||||
|
||||
static bool mg_tls_server_send_cert_request(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
@@ -878,28 +927,6 @@ static bool mg_tls_send_cert(struct mg_connection *c, bool is_client) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// type adapter between uECC hash context and our sha256 implementation
|
||||
typedef struct SHA256_HashContext {
|
||||
MG_UECC_HashContext uECC;
|
||||
mg_sha256_ctx ctx;
|
||||
} SHA256_HashContext;
|
||||
|
||||
static void init_SHA256(const MG_UECC_HashContext *base) {
|
||||
SHA256_HashContext *c = (SHA256_HashContext *) base;
|
||||
mg_sha256_init(&c->ctx);
|
||||
}
|
||||
|
||||
static void update_SHA256(const MG_UECC_HashContext *base,
|
||||
const uint8_t *message, unsigned message_size) {
|
||||
SHA256_HashContext *c = (SHA256_HashContext *) base;
|
||||
mg_sha256_update(&c->ctx, message, message_size);
|
||||
}
|
||||
static void finish_SHA256(const MG_UECC_HashContext *base,
|
||||
uint8_t *hash_result) {
|
||||
SHA256_HashContext *c = (SHA256_HashContext *) base;
|
||||
mg_sha256_final(hash_result, &c->ctx);
|
||||
}
|
||||
|
||||
static void mg_tls_mgf1(uint8_t *mask, size_t mask_len, const uint8_t *seed,
|
||||
size_t seed_len) {
|
||||
uint32_t counter = 0;
|
||||
@@ -1142,15 +1169,13 @@ static bool mg_tls_send_cert_verify(struct mg_connection *c, bool is_client) {
|
||||
} else {
|
||||
// EC certificate verify packet
|
||||
uint8_t verify[82] = {0x0f, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00};
|
||||
uint8_t tmp[2 * 32 + 64] = {0};
|
||||
struct SHA256_HashContext ctx = {
|
||||
{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp},
|
||||
{{0}, 0, 0, {0}}};
|
||||
size_t sigsz, verifysz = 0;
|
||||
int neg1, neg2;
|
||||
uint8_t sig[64] = {0};
|
||||
mg_uecc_sign_deterministic(tls->ec_key, hash, sizeof(hash), &ctx.uECC, sig,
|
||||
mg_uecc_secp256r1());
|
||||
if (!mg_p256_sign(tls->ec_key, hash, sizeof(hash), sig)) {
|
||||
mg_error(c, "P-256 sign");
|
||||
return false;
|
||||
}
|
||||
|
||||
neg1 = !!(sig[0] & 0x80);
|
||||
neg2 = !!(sig[32] & 0x80);
|
||||
@@ -1213,7 +1238,6 @@ static bool mg_tls_client_send_hello(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
struct mg_iobuf *wio = &tls->send;
|
||||
|
||||
uint8_t x25519_pub[X25519_BYTES];
|
||||
uint8_t p256_pub[64]; // X || Y, sent as an uncompressed point 0x04 || X || Y
|
||||
|
||||
// - "signature algorithms we actually support", see above
|
||||
@@ -1227,11 +1251,11 @@ static bool mg_tls_client_send_hello(struct mg_connection *c) {
|
||||
0xfe, 0x00, 0x00, 0xfe};
|
||||
|
||||
// clang-format off
|
||||
uint8_t msg_client_hello[216] = {
|
||||
uint8_t msg_client_hello[178] = {
|
||||
// TLS Client Hello header reported as TLS1.2 (5)
|
||||
0x16, 0x03, 0x03, 0x00, 0xfe,
|
||||
0x16, 0x03, 0x03, 0x00, 0xd8,
|
||||
// client hello, tls 1.2 (6)
|
||||
0x01, 0x00, 0x00, 0x8c, 0x03, 0x03,
|
||||
0x01, 0x00, 0x00, 0xd4, 0x03, 0x03,
|
||||
// random (32 bytes)
|
||||
PLACEHOLDER_32B,
|
||||
// session ID length + session ID (32 bytes)
|
||||
@@ -1248,17 +1272,15 @@ static bool mg_tls_client_send_hello(struct mg_connection *c) {
|
||||
0x01, 0x00,
|
||||
// extensions + keyshare
|
||||
0x00, 0xfe,
|
||||
// keyshare: x25519
|
||||
0x00, 0x33, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x1d, 0x00, 0x20,
|
||||
PLACEHOLDER_32B,
|
||||
// keyshare: secp256r1, uncompressed point
|
||||
0x00, 0x33, 0x00, 0x47, 0x00, 0x45,
|
||||
0x00, 0x17, 0x00, 0x41, 0x04, PLACEHOLDER_32B, PLACEHOLDER_32B,
|
||||
// supported groups (x25519, secp256r1)
|
||||
0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x17,
|
||||
// supported groups (secp256r1)
|
||||
0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x17,
|
||||
// supported versions (tls1.3 == 0x304)
|
||||
0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04,
|
||||
// session ticket (none)
|
||||
0x00, 0x23, 0x00, 0x00, // 215 bytes till here
|
||||
0x00, 0x23, 0x00, 0x00, // 177 bytes till here
|
||||
};
|
||||
// clang-format on
|
||||
const char *hostname = tls->hostname;
|
||||
@@ -1271,11 +1293,11 @@ static bool mg_tls_client_send_hello(struct mg_connection *c) {
|
||||
|
||||
// patch ClientHello with correct hostname ext length (if any)
|
||||
MG_STORE_BE16(msg_client_hello + 3,
|
||||
hostname_extsz + 254 - 9 - 34 + sig_alg_sz);
|
||||
hostname_extsz + 216 - 9 - 34 + sig_alg_sz);
|
||||
MG_STORE_BE16(msg_client_hello + 7,
|
||||
hostname_extsz + 250 - 9 - 34 + sig_alg_sz);
|
||||
hostname_extsz + 212 - 9 - 34 + sig_alg_sz);
|
||||
MG_STORE_BE16(msg_client_hello + 82,
|
||||
hostname_extsz + 175 - 9 - 34 + sig_alg_sz);
|
||||
hostname_extsz + 137 - 9 - 34 + sig_alg_sz);
|
||||
|
||||
if (hostnamesz > 0) {
|
||||
MG_STORE_BE16(server_name_ext + 2, hostnamesz + 5);
|
||||
@@ -1283,21 +1305,18 @@ static bool mg_tls_client_send_hello(struct mg_connection *c) {
|
||||
MG_STORE_BE16(server_name_ext + 7, hostnamesz);
|
||||
}
|
||||
|
||||
// calculate keyshares
|
||||
if (!mg_random(tls->x25519_cli, sizeof(tls->x25519_cli))) mg_error(c, "RNG");
|
||||
mg_tls_x25519(x25519_pub, tls->x25519_cli, X25519_BASE_POINT, 1);
|
||||
if (!mg_uecc_make_key(p256_pub, tls->p256_cli, mg_uecc_secp256r1())) {
|
||||
// calculate keyshare
|
||||
if (!mg_p256_make_key(p256_pub, tls->p256_cli)) {
|
||||
mg_error(c, "P-256 key");
|
||||
return false; // Do not send uninitialised p256_pub
|
||||
}
|
||||
|
||||
// fill in the gaps: random + session ID + keyshares
|
||||
// fill in the gaps: random + session ID + keyshare
|
||||
if (!mg_random(tls->session_id, sizeof(tls->session_id))) mg_error(c, "RNG");
|
||||
if (!mg_random(tls->random, sizeof(tls->random))) mg_error(c, "RNG");
|
||||
memmove(msg_client_hello + 11, tls->random, sizeof(tls->random));
|
||||
memmove(msg_client_hello + 44, tls->session_id, sizeof(tls->session_id));
|
||||
memmove(msg_client_hello + 94, x25519_pub, sizeof(x25519_pub));
|
||||
memmove(msg_client_hello + 131, p256_pub, sizeof(p256_pub));
|
||||
memmove(msg_client_hello + 95, p256_pub, sizeof(p256_pub));
|
||||
|
||||
// client hello message
|
||||
if (mg_iobuf_add(wio, wio->len, msg_client_hello, sizeof(msg_client_hello)) ==
|
||||
@@ -1370,26 +1389,17 @@ static int mg_tls_client_recv_hello(struct mg_connection *c) {
|
||||
key_exchange_len = MG_LOAD_BE16(ext + j + 6);
|
||||
key_exchange = ext + j + 8;
|
||||
if (key_exchange_len > ext_len2 - 4) goto fail;
|
||||
if (group == 0x001d) { // x25519
|
||||
if (key_exchange_len != 32 ||
|
||||
mg_tls_x25519(tls->x25519_sec, tls->x25519_cli, key_exchange, 1) <
|
||||
0) {
|
||||
mg_error(c, "bad key");
|
||||
return -1;
|
||||
}
|
||||
} else if (group == 0x0017) { // secp256r1, uncompressed point 0x04 || X || Y
|
||||
if (key_exchange_len != 65 || key_exchange[0] != 0x04 ||
|
||||
!mg_uecc_valid_public_key(key_exchange + 1, mg_uecc_secp256r1()) ||
|
||||
!mg_uecc_shared_secret(key_exchange + 1, tls->p256_cli,
|
||||
tls->x25519_sec, mg_uecc_secp256r1())) {
|
||||
mg_error(c, "bad key");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (group != 0x0017) { // secp256r1, uncompressed point 0x04 || X || Y
|
||||
mg_error(c, "bad key exchange group");
|
||||
return -1;
|
||||
}
|
||||
// mg_tls_hexdump("c ecdhe sec", tls->x25519_sec, 32);
|
||||
if (key_exchange_len != 65 || key_exchange[0] != 0x04 ||
|
||||
!mg_p256_shared_secret(key_exchange + 1, tls->p256_cli,
|
||||
tls->ecdhe_sec)) { // Validates the point
|
||||
mg_error(c, "bad key");
|
||||
return -1;
|
||||
}
|
||||
// mg_tls_hexdump("c ecdhe sec", tls->ecdhe_sec, 32);
|
||||
mg_tls_drop_record(c);
|
||||
/* generate handshake keys */
|
||||
mg_tls_generate_handshake_keys(c);
|
||||
@@ -1714,7 +1724,6 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
MG_ERROR(("cert verification error"));
|
||||
return 0;
|
||||
}
|
||||
#if MG_UECC_SUPPORTS_secp256r1
|
||||
if (issuer->pubkey.len == 64) {
|
||||
const uint32_t N = 32;
|
||||
if (a.len > N) a.value += (a.len - N), a.len = N; // padding
|
||||
@@ -1723,13 +1732,9 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
memmove(sig + (N - a.len), a.value, a.len);
|
||||
memset(sig + N, 0, N - b.len);
|
||||
memmove(sig + N + (N - b.len), b.value, b.len);
|
||||
return mg_uecc_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
(unsigned) cert->tbshashsz, sig,
|
||||
mg_uecc_secp256r1());
|
||||
} else
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp384r1
|
||||
if (issuer->pubkey.len == 96) {
|
||||
return mg_p256_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
cert->tbshashsz, sig);
|
||||
} else if (issuer->pubkey.len == 96) {
|
||||
const uint32_t N = 48;
|
||||
if (a.len > N) a.value += (a.len - N), a.len = N; // padding
|
||||
if (b.len > N) b.value += (b.len - N), b.len = N;
|
||||
@@ -1737,12 +1742,9 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
memmove(sig + (N - a.len), a.value, a.len);
|
||||
memset(sig + N, 0, N - b.len);
|
||||
memmove(sig + N + (N - b.len), b.value, b.len);
|
||||
return mg_uecc_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
(unsigned) cert->tbshashsz, sig,
|
||||
mg_uecc_secp384r1());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return mg_p384_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
cert->tbshashsz, sig);
|
||||
} else {
|
||||
MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len));
|
||||
return 0;
|
||||
}
|
||||
@@ -2040,8 +2042,7 @@ static int mg_tls_recv_cert_verify(struct mg_connection *c) {
|
||||
return -1;
|
||||
}
|
||||
MG_VERBOSE(("certificate verification successful (RSA)"));
|
||||
} else if (sigalg == 0x0403 ||
|
||||
(sigalg == 0x0503 && MG_UECC_SUPPORTS_secp384r1)) {
|
||||
} else if (sigalg == 0x0403 || sigalg == 0x0503) {
|
||||
// ecdsa_secp256r1_sha256 or ecdsa_secp384r1_sha384. Extract certificate
|
||||
// signature and verify it using pubkey and sighash
|
||||
bool is384 = sigalg == 0x0503;
|
||||
@@ -2074,15 +2075,12 @@ static int mg_tls_recv_cert_verify(struct mg_connection *c) {
|
||||
memmove(sig + (N - r.len), r.value, r.len);
|
||||
memmove(sig + N + (N - s.len), s.value, s.len);
|
||||
|
||||
#if MG_UECC_SUPPORTS_secp384r1
|
||||
if (is384) {
|
||||
ok = mg_uecc_verify(tls->pubkey, tls->sighash384,
|
||||
sizeof(tls->sighash384), sig, mg_uecc_secp384r1());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ok = mg_uecc_verify(tls->pubkey, tls->sighash, sizeof(tls->sighash),
|
||||
sig, mg_uecc_secp256r1());
|
||||
ok = mg_p384_verify(tls->pubkey, tls->sighash384,
|
||||
sizeof(tls->sighash384), sig);
|
||||
} else {
|
||||
ok = mg_p256_verify(tls->pubkey, tls->sighash, sizeof(tls->sighash),
|
||||
sig);
|
||||
}
|
||||
if (ok != 1) {
|
||||
mg_error(c, "failed to verify EC certificate (certverify)");
|
||||
@@ -2186,16 +2184,23 @@ static bool mg_tls_client_handshake(struct mg_connection *c) {
|
||||
|
||||
static bool mg_tls_server_handshake(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
int r;
|
||||
switch (tls->state) {
|
||||
case MG_TLS_STATE_SERVER_START:
|
||||
if (mg_tls_server_recv_hello(c) < 0) break;
|
||||
case MG_TLS_STATE_SERVER_RETRY:
|
||||
if ((r = mg_tls_server_recv_hello(c)) < 0) break;
|
||||
if (r == 1) { // No P-256 key share, ask for it
|
||||
if (!mg_tls_server_send_hrr(c)) return false;
|
||||
tls->state = MG_TLS_STATE_SERVER_RETRY;
|
||||
break;
|
||||
}
|
||||
if (!mg_tls_server_send_hello(c)) return false;
|
||||
mg_tls_generate_handshake_keys(c);
|
||||
if (!mg_tls_server_send_ext(c)) return false;
|
||||
if (tls->is_twoway && !mg_tls_server_send_cert_request(c)) return false;
|
||||
if (!mg_tls_send_cert(c, false) || !mg_tls_send_cert_verify(c, false) ||
|
||||
!mg_tls_server_send_finish(c))
|
||||
return false;
|
||||
if (!mg_tls_send_cert(c, false)) return false;
|
||||
if (!mg_tls_send_cert_verify(c, false)) return false;
|
||||
if (!mg_tls_server_send_finish(c)) return false;
|
||||
if (tls->is_twoway) {
|
||||
// generate application keys at this point, keep using handshake keys
|
||||
struct tls_enc hs_keys = tls->enc;
|
||||
@@ -2236,14 +2241,25 @@ void mg_tls_handshake(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
long n;
|
||||
bool res;
|
||||
uint64_t t;
|
||||
if (c->is_closing) return; // we don't clear rx buf, so ignore what's left
|
||||
if (tls->is_sntp_pending) return;
|
||||
t = mg_millis();
|
||||
if (c->is_client) {
|
||||
// will clear is_hs when sending last chunk
|
||||
res = mg_tls_client_handshake(c);
|
||||
} else {
|
||||
res = mg_tls_server_handshake(c);
|
||||
}
|
||||
tls->hs_proc += mg_millis() - t;
|
||||
if (res && !c->is_tls_hs) {
|
||||
// CPU: key exchange, signing, certificate verification. Wait: the rest of
|
||||
// the total, waiting for the peer and the network
|
||||
unsigned long total = (unsigned long) (mg_millis() - tls->hs_start);
|
||||
unsigned long cpu = (unsigned long) tls->hs_proc;
|
||||
MG_DEBUG(("%lu TLS handshake done in %lu ms: %lu ms CPU, %lu ms peer wait",
|
||||
c->id, total, cpu, total > cpu ? total - cpu : 0));
|
||||
}
|
||||
if (!res) {
|
||||
mg_error(c, "TLS OOM");
|
||||
return;
|
||||
@@ -2662,7 +2678,7 @@ static int mg_parse_pem_certs(const struct mg_str pem, struct mg_str **ders) {
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t mg_uecc_parse_private_key(struct mg_str key, uint8_t *buf, size_t len) {
|
||||
size_t mg_p256_parse_private_key(struct mg_str key, uint8_t *buf, size_t len) {
|
||||
struct mg_str der = mg_str_n(NULL, 0);
|
||||
size_t n = 0;
|
||||
if (buf == NULL || len < 32) return 0;
|
||||
@@ -2702,6 +2718,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
||||
mg_error(c, "tls oom");
|
||||
return;
|
||||
}
|
||||
tls->hs_start = mg_millis();
|
||||
|
||||
tls->state =
|
||||
c->is_client ? MG_TLS_STATE_CLIENT_START : MG_TLS_STATE_SERVER_START;
|
||||
@@ -2887,11 +2904,15 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
|
||||
long n = MG_IO_WAIT;
|
||||
bool was_throttled = c->is_tls_throttled; // see #3074
|
||||
if (!was_throttled) { // encrypt new data
|
||||
size_t i, rs = MG_TLS_RECORD_SIZE > 16384 ? 16384 : MG_TLS_RECORD_SIZE;
|
||||
if (len > MG_IO_SIZE) len = MG_IO_SIZE;
|
||||
if (len > 16384) len = 16384;
|
||||
if (!mg_tls_encrypt(c, (const uint8_t *) buf, len, MG_TLS_APP_DATA))
|
||||
return 0; // returning 0 means an OOM condition (iobuf couldn't resize),
|
||||
// yet this is so far recoverable, let the caller decide
|
||||
for (i = 0; i < len; i += rs) { // Split into records, send them at once
|
||||
size_t m = len - i < rs ? len - i : rs;
|
||||
if (!mg_tls_encrypt(c, (const uint8_t *) buf + i, m, MG_TLS_APP_DATA))
|
||||
return 0; // returning 0 means an OOM condition (iobuf couldn't
|
||||
// resize), yet this is so far recoverable, let the caller
|
||||
// decide
|
||||
}
|
||||
} // else, resend outstanding encrypted data in tls->send
|
||||
while (tls->send.len > 0 &&
|
||||
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
|
||||
|
||||
+2553
File diff suppressed because it is too large.
Load diff
+181
@@ -0,0 +1,181 @@
|
||||
// P-256 API, mg_p256_*(), used by built-in TLS, JWT and OTA. Implemented by
|
||||
// BearSSL code below (MG_P256=MG_P256_BEAR) or tls_p256_cortex.c (LENNGREN)
|
||||
// BearSSL code: https://bearssl.org commit 7bea48e. Shared bignum and ECDSA
|
||||
// code is always compiled, it is also used by P-384, see tls_p384.c
|
||||
//
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Mongoose changes: br_ / BR_ names are prefixed with mg_ / MG_, as are the
|
||||
// constant-time helpers from inner.h (NOT, MUX, EQ, ...). Structs are not
|
||||
// typedef-ed. ECDSA signing takes the caller's k instead of HMAC-DRBG, k is
|
||||
// computed by mg_p256_sign() (RFC 6979). ECDSA functions take the curve id and
|
||||
// public key directly
|
||||
#pragma once
|
||||
|
||||
#include "arch.h"
|
||||
#include "config.h"
|
||||
#include "str.h"
|
||||
#include "tls.h"
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
|
||||
#define MG_BR_EC_secp256r1 23 // Curve IDs, same as TLS named groups
|
||||
#define MG_BR_EC_secp384r1 24
|
||||
#define MG_BR_MAX_EC_SIZE 384 // Largest supported curve, bits
|
||||
|
||||
// From BearSSL inc/bearssl_ec.h: an EC implementation
|
||||
struct mg_br_ec_impl {
|
||||
uint32_t supported_curves; // Bit mask of curve IDs
|
||||
const unsigned char *(*generator)(int curve, size_t *len);
|
||||
const unsigned char *(*order)(int curve, size_t *len);
|
||||
size_t (*xoff)(int curve, size_t *len);
|
||||
uint32_t (*mul)(unsigned char *G, size_t Glen, const unsigned char *x,
|
||||
size_t xlen, int curve);
|
||||
size_t (*mulgen)(unsigned char *R, const unsigned char *x, size_t xlen,
|
||||
int curve);
|
||||
uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *y, size_t ylen, int curve);
|
||||
};
|
||||
|
||||
// From BearSSL src/inner.h: constant-time helpers
|
||||
static inline uint32_t MG_BR_NOT(uint32_t ctl) {
|
||||
return ctl ^ 1;
|
||||
}
|
||||
static inline uint32_t MG_BR_MUX(uint32_t ctl, uint32_t x, uint32_t y) {
|
||||
return y ^ (-ctl & (x ^ y));
|
||||
}
|
||||
static inline uint32_t MG_BR_EQ(uint32_t x, uint32_t y) {
|
||||
uint32_t q = x ^ y;
|
||||
return MG_BR_NOT((q | -q) >> 31);
|
||||
}
|
||||
static inline uint32_t MG_BR_NEQ(uint32_t x, uint32_t y) {
|
||||
uint32_t q = x ^ y;
|
||||
return (q | -q) >> 31;
|
||||
}
|
||||
static inline uint32_t MG_BR_GT(uint32_t x, uint32_t y) {
|
||||
uint32_t z = y - x;
|
||||
return (z ^ ((x ^ y) & (x ^ z))) >> 31;
|
||||
}
|
||||
#define MG_BR_GE(x, y) MG_BR_NOT(MG_BR_GT(y, x))
|
||||
#define MG_BR_LT(x, y) MG_BR_GT(y, x)
|
||||
static inline int32_t MG_BR_CMP(uint32_t x, uint32_t y) {
|
||||
return (int32_t) MG_BR_GT(x, y) | -(int32_t) MG_BR_GT(y, x);
|
||||
}
|
||||
static inline uint32_t MG_BR_BIT_LENGTH(uint32_t x) {
|
||||
uint32_t k, c;
|
||||
k = MG_BR_NEQ(x, 0);
|
||||
c = MG_BR_GT(x, 0xFFFF), x = MG_BR_MUX(c, x >> 16, x), k += c << 4;
|
||||
c = MG_BR_GT(x, 0x00FF), x = MG_BR_MUX(c, x >> 8, x), k += c << 3;
|
||||
c = MG_BR_GT(x, 0x000F), x = MG_BR_MUX(c, x >> 4, x), k += c << 2;
|
||||
c = MG_BR_GT(x, 0x0003), x = MG_BR_MUX(c, x >> 2, x), k += c << 1;
|
||||
k += MG_BR_GT(x, 0x0001);
|
||||
return k;
|
||||
}
|
||||
#define MG_BR_MUL31(x, y) ((uint64_t) (x) * (uint64_t) (y))
|
||||
#define MG_BR_MUL31_lo(x, y) \
|
||||
(((uint32_t) (x) * (uint32_t) (y)) & (uint32_t) 0x7FFFFFFF)
|
||||
#define MG_BR_CCOPY mg_br_ccopy
|
||||
void mg_br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len);
|
||||
uint32_t mg_br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r);
|
||||
static inline uint32_t mg_br_rem(uint32_t hi, uint32_t lo, uint32_t d) {
|
||||
uint32_t r;
|
||||
mg_br_divrem(hi, lo, d, &r);
|
||||
return r;
|
||||
}
|
||||
static inline uint32_t mg_br_div(uint32_t hi, uint32_t lo, uint32_t d) {
|
||||
uint32_t r;
|
||||
return mg_br_divrem(hi, lo, d, &r);
|
||||
}
|
||||
static inline void mg_br_enc32be(void *dst, uint32_t x) {
|
||||
unsigned char *buf = (unsigned char *) dst;
|
||||
buf[0] = (unsigned char) (x >> 24), buf[1] = (unsigned char) (x >> 16);
|
||||
buf[2] = (unsigned char) (x >> 8), buf[3] = (unsigned char) x;
|
||||
}
|
||||
static inline void mg_br_i31_zero(uint32_t *x, uint32_t bit_len) {
|
||||
*x++ = bit_len;
|
||||
memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x);
|
||||
}
|
||||
|
||||
// Big integers, "i31" format, see BearSSL src/inner.h
|
||||
uint32_t mg_br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl);
|
||||
uint32_t mg_br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl);
|
||||
uint32_t mg_br_i31_bit_length(uint32_t *x, size_t xlen);
|
||||
uint32_t mg_br_i31_decode_mod(uint32_t *x, const void *src, size_t len,
|
||||
const uint32_t *m);
|
||||
void mg_br_i31_decode(uint32_t *x, const void *src, size_t len);
|
||||
void mg_br_i31_encode(void *dst, size_t len, const uint32_t *x);
|
||||
void mg_br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i);
|
||||
void mg_br_i31_to_monty(uint32_t *x, const uint32_t *m);
|
||||
uint32_t mg_br_i31_iszero(const uint32_t *x);
|
||||
void mg_br_i31_modpow(uint32_t *x, const unsigned char *e, size_t elen,
|
||||
const uint32_t *m, uint32_t m0i, uint32_t *t1,
|
||||
uint32_t *t2);
|
||||
void mg_br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
|
||||
const uint32_t *m, uint32_t m0i);
|
||||
void mg_br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m);
|
||||
uint32_t mg_br_i31_ninv31(uint32_t x);
|
||||
void mg_br_i31_rshift(uint32_t *x, int count);
|
||||
|
||||
// ECDSA, see BearSSL src/ec/ecdsa_i31_*.c. q is an uncompressed point
|
||||
void mg_br_ecdsa_i31_bits2int(uint32_t *x, const void *src, size_t len,
|
||||
uint32_t ebitlen);
|
||||
uint32_t mg_br_ecdsa_i31_vrfy_raw(const struct mg_br_ec_impl *impl, int curve,
|
||||
const void *hash, size_t hash_len,
|
||||
const unsigned char *q, size_t qlen,
|
||||
const void *sig, size_t sig_len);
|
||||
size_t mg_br_ecdsa_i31_sign_raw(const struct mg_br_ec_impl *impl, int curve,
|
||||
const void *hash, size_t hash_len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *k, void *sig);
|
||||
|
||||
// P-256 (secp256r1) API. Keys and signatures are big endian byte strings,
|
||||
// a public key is X || Y, a signature is r || s. Functions return 1 on
|
||||
// success, 0 on failure
|
||||
|
||||
// Generate a random key pair, using mg_random()
|
||||
int mg_p256_make_key(uint8_t public_key[64], uint8_t private_key[32]);
|
||||
|
||||
// Compute public key from a private key. Return 0 if private key is invalid
|
||||
int mg_p256_compute_public_key(const uint8_t private_key[32],
|
||||
uint8_t public_key[64]);
|
||||
|
||||
// ECDH. Validates the peer public key, returns 0 if it is not on the curve
|
||||
int mg_p256_shared_secret(const uint8_t public_key[64],
|
||||
const uint8_t private_key[32], uint8_t secret[32]);
|
||||
|
||||
// ECDSA sign with a deterministic k, RFC 6979 with HMAC-SHA256
|
||||
int mg_p256_sign(const uint8_t private_key[32], const uint8_t *hash,
|
||||
size_t hash_size, uint8_t signature[64]);
|
||||
|
||||
// ECDSA verify. Validates the public key
|
||||
int mg_p256_verify(const uint8_t public_key[64], const uint8_t *hash,
|
||||
size_t hash_size, const uint8_t signature[64]);
|
||||
|
||||
// Internal: ECDSA sign with a given k, 32 bytes big endian, in [1, n-1].
|
||||
// Provided by the selected implementation, used by mg_p256_sign()
|
||||
int mg_p256_sign_with_k(const uint8_t private_key[32], const uint8_t *hash,
|
||||
size_t hash_size, const uint8_t k[32],
|
||||
uint8_t signature[64]);
|
||||
#endif // MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
File diff suppressed because it is too large.
Load diff
+834
@@ -0,0 +1,834 @@
|
||||
// P-384 from BearSSL, https://bearssl.org commit 7bea48e
|
||||
// P-384 signature verification, used by built-in TLS for certificates and
|
||||
// CertificateVerify. Shared bignum and ECDSA code is in tls_p256.c
|
||||
//
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Mongoose changes: br_ / BR_ names are prefixed with mg_ / MG_, static
|
||||
// functions with p384_. Trimmed to P-384. Structs are not typedef-ed
|
||||
|
||||
#include "tls_p384.h"
|
||||
#include "tls_p256.h"
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
|
||||
// From BearSSL src/ec/ec_secp384r1.c
|
||||
static const unsigned char P384_N[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
|
||||
0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A,
|
||||
0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73
|
||||
};
|
||||
|
||||
static const unsigned char P384_G[] = {
|
||||
0x04, 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05,
|
||||
0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD,
|
||||
0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B,
|
||||
0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A,
|
||||
0x38, 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29,
|
||||
0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A,
|
||||
0xB7, 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C,
|
||||
0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC,
|
||||
0x29, 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14,
|
||||
0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8,
|
||||
0xC0, 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81,
|
||||
0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E,
|
||||
0x5F
|
||||
};
|
||||
|
||||
|
||||
// From BearSSL src/ec/ec_prime_i31.c
|
||||
/*
|
||||
* Parameters for supported curves (field modulus, and 'b' equation
|
||||
* parameter; both values use the 'i31' format, and 'b' is in Montgomery
|
||||
* representation).
|
||||
*/
|
||||
|
||||
static const uint32_t P384_P[] = {
|
||||
0x0000018C,
|
||||
0x7FFFFFFF, 0x00000001, 0x00000000, 0x7FFFFFF8,
|
||||
0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
|
||||
0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
|
||||
0x00000FFF
|
||||
};
|
||||
|
||||
static const uint32_t P384_R2[] = {
|
||||
0x0000018C,
|
||||
0x00000000, 0x00000080, 0x7FFFFE00, 0x000001FF,
|
||||
0x00000800, 0x00000000, 0x7FFFE000, 0x00001FFF,
|
||||
0x00008000, 0x00008000, 0x00000000, 0x00000000,
|
||||
0x00000000
|
||||
};
|
||||
|
||||
static const uint32_t P384_B[] = {
|
||||
0x0000018C,
|
||||
0x6E666840, 0x070D0392, 0x5D810231, 0x7651D50C,
|
||||
0x17E218D6, 0x1B192002, 0x44EFE441, 0x3A524E2B,
|
||||
0x2719BA5F, 0x41F02209, 0x36C5643E, 0x5813EFFE,
|
||||
0x000008A5
|
||||
};
|
||||
|
||||
struct p384_curve_params {
|
||||
const uint32_t *p;
|
||||
const uint32_t *b;
|
||||
const uint32_t *R2;
|
||||
uint32_t p0i;
|
||||
size_t point_len;
|
||||
};
|
||||
|
||||
static inline const struct p384_curve_params *
|
||||
p384_id_to_curve(int curve)
|
||||
{
|
||||
static const struct p384_curve_params pp = {
|
||||
P384_P, P384_B, P384_R2, 0x00000001, 97
|
||||
};
|
||||
|
||||
(void)curve;
|
||||
return &pp;
|
||||
}
|
||||
|
||||
#define I31_LEN ((MG_BR_MAX_EC_SIZE + 61) / 31)
|
||||
|
||||
/*
|
||||
* Type for a point in Jacobian coordinates:
|
||||
* -- three values, x, y and z, in Montgomery representation
|
||||
* -- affine coordinates are X = x / z^2 and Y = y / z^3
|
||||
* -- for the point at infinity, z = 0
|
||||
*/
|
||||
struct p384_jacobian {
|
||||
uint32_t c[3][I31_LEN];
|
||||
};
|
||||
|
||||
/*
|
||||
* We use a custom interpreter that uses a dozen registers, and
|
||||
* only six operations:
|
||||
* MSET(d, a) copy a into d
|
||||
* MADD(d, a) d = d+a (modular)
|
||||
* MSUB(d, a) d = d-a (modular)
|
||||
* MMUL(d, a, b) d = a*b (Montgomery multiplication)
|
||||
* MINV(d, a, b) invert d modulo p; a and b are used as scratch registers
|
||||
* MTZ(d) clear return value if d = 0
|
||||
* Destination of MMUL (d) must be distinct from operands (a and b).
|
||||
* There is no such constraint for MSUB and MADD.
|
||||
*
|
||||
* Registers include the operand coordinates, and temporaries.
|
||||
*/
|
||||
#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))
|
||||
#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))
|
||||
#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))
|
||||
#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))
|
||||
#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))
|
||||
#define MTZ(d) (0x5000 + ((d) << 8))
|
||||
#define ENDCODE 0
|
||||
|
||||
/*
|
||||
* Registers for the input operands.
|
||||
*/
|
||||
#define P1x 0
|
||||
#define P1y 1
|
||||
#define P1z 2
|
||||
#define P2x 3
|
||||
#define P2y 4
|
||||
#define P2z 5
|
||||
|
||||
/*
|
||||
* Alternate names for the first input operand.
|
||||
*/
|
||||
#define Px 0
|
||||
#define Py 1
|
||||
#define Pz 2
|
||||
|
||||
/*
|
||||
* Temporaries.
|
||||
*/
|
||||
#define t1 6
|
||||
#define t2 7
|
||||
#define t3 8
|
||||
#define t4 9
|
||||
#define t5 10
|
||||
#define t6 11
|
||||
#define t7 12
|
||||
|
||||
/*
|
||||
* Extra scratch registers available when there is no second operand (e.g.
|
||||
* for "double" and "affine").
|
||||
*/
|
||||
#define t8 3
|
||||
#define t9 4
|
||||
#define t10 5
|
||||
|
||||
/*
|
||||
* Doubling formulas are:
|
||||
*
|
||||
* s = 4*x*y^2
|
||||
* m = 3*(x + z^2)*(x - z^2)
|
||||
* x' = m^2 - 2*s
|
||||
* y' = m*(s - x') - 8*y^4
|
||||
* z' = 2*y*z
|
||||
*
|
||||
* If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
|
||||
* should. This case should not happen anyway, because our curves have
|
||||
* prime order, and thus do not contain any point of order 2.
|
||||
*
|
||||
* If P is infinity (z = 0), then again the formulas yield infinity,
|
||||
* which is correct. Thus, this code works for all points.
|
||||
*
|
||||
* Cost: 8 multiplications
|
||||
*/
|
||||
static const uint16_t p384_code_double[] = {
|
||||
/*
|
||||
* Compute z^2 (in t1).
|
||||
*/
|
||||
MMUL(t1, Pz, Pz),
|
||||
|
||||
/*
|
||||
* Compute x-z^2 (in t2) and then x+z^2 (in t1).
|
||||
*/
|
||||
MSET(t2, Px),
|
||||
MSUB(t2, t1),
|
||||
MADD(t1, Px),
|
||||
|
||||
/*
|
||||
* Compute m = 3*(x+z^2)*(x-z^2) (in t1).
|
||||
*/
|
||||
MMUL(t3, t1, t2),
|
||||
MSET(t1, t3),
|
||||
MADD(t1, t3),
|
||||
MADD(t1, t3),
|
||||
|
||||
/*
|
||||
* Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
|
||||
*/
|
||||
MMUL(t3, Py, Py),
|
||||
MADD(t3, t3),
|
||||
MMUL(t2, Px, t3),
|
||||
MADD(t2, t2),
|
||||
|
||||
/*
|
||||
* Compute x' = m^2 - 2*s.
|
||||
*/
|
||||
MMUL(Px, t1, t1),
|
||||
MSUB(Px, t2),
|
||||
MSUB(Px, t2),
|
||||
|
||||
/*
|
||||
* Compute z' = 2*y*z.
|
||||
*/
|
||||
MMUL(t4, Py, Pz),
|
||||
MSET(Pz, t4),
|
||||
MADD(Pz, t4),
|
||||
|
||||
/*
|
||||
* Compute y' = m*(s - x') - 8*y^4. Note that we already have
|
||||
* 2*y^2 in t3.
|
||||
*/
|
||||
MSUB(t2, Px),
|
||||
MMUL(Py, t1, t2),
|
||||
MMUL(t4, t3, t3),
|
||||
MSUB(Py, t4),
|
||||
MSUB(Py, t4),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
/*
|
||||
* Addtions formulas are:
|
||||
*
|
||||
* u1 = x1 * z2^2
|
||||
* u2 = x2 * z1^2
|
||||
* s1 = y1 * z2^3
|
||||
* s2 = y2 * z1^3
|
||||
* h = u2 - u1
|
||||
* r = s2 - s1
|
||||
* x3 = r^2 - h^3 - 2 * u1 * h^2
|
||||
* y3 = r * (u1 * h^2 - x3) - s1 * h^3
|
||||
* z3 = h * z1 * z2
|
||||
*
|
||||
* If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
|
||||
* z3 == 0, so the result is correct.
|
||||
* If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
|
||||
* not correct.
|
||||
* h == 0 only if u1 == u2; this happens in two cases:
|
||||
* -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
|
||||
* -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
|
||||
*
|
||||
* Thus, the following situations are not handled correctly:
|
||||
* -- P1 = 0 and P2 != 0
|
||||
* -- P1 != 0 and P2 = 0
|
||||
* -- P1 = P2
|
||||
* All other cases are properly computed. However, even in "incorrect"
|
||||
* situations, the three coordinates still are properly formed field
|
||||
* elements.
|
||||
*
|
||||
* The returned flag is cleared if r == 0. This happens in the following
|
||||
* cases:
|
||||
* -- Both points are on the same horizontal line (same Y coordinate).
|
||||
* -- Both points are infinity.
|
||||
* -- One point is infinity and the other is on line Y = 0.
|
||||
* The third case cannot happen with our curves (there is no valid point
|
||||
* on line Y = 0 since that would be a point of order 2). If the two
|
||||
* source points are non-infinity, then remains only the case where the
|
||||
* two points are on the same horizontal line.
|
||||
*
|
||||
* This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
|
||||
* P2 != 0:
|
||||
* -- If the returned value is not the point at infinity, then it was properly
|
||||
* computed.
|
||||
* -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
|
||||
* is indeed the point at infinity.
|
||||
* -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
|
||||
* use the 'double' code.
|
||||
*
|
||||
* Cost: 16 multiplications
|
||||
*/
|
||||
static const uint16_t p384_code_add[] = {
|
||||
/*
|
||||
* Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
|
||||
*/
|
||||
MMUL(t3, P2z, P2z),
|
||||
MMUL(t1, P1x, t3),
|
||||
MMUL(t4, P2z, t3),
|
||||
MMUL(t3, P1y, t4),
|
||||
|
||||
/*
|
||||
* Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
|
||||
*/
|
||||
MMUL(t4, P1z, P1z),
|
||||
MMUL(t2, P2x, t4),
|
||||
MMUL(t5, P1z, t4),
|
||||
MMUL(t4, P2y, t5),
|
||||
|
||||
/*
|
||||
* Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
|
||||
*/
|
||||
MSUB(t2, t1),
|
||||
MSUB(t4, t3),
|
||||
|
||||
/*
|
||||
* Report cases where r = 0 through the returned flag.
|
||||
*/
|
||||
MTZ(t4),
|
||||
|
||||
/*
|
||||
* Compute u1*h^2 (in t6) and h^3 (in t5).
|
||||
*/
|
||||
MMUL(t7, t2, t2),
|
||||
MMUL(t6, t1, t7),
|
||||
MMUL(t5, t7, t2),
|
||||
|
||||
/*
|
||||
* Compute x3 = r^2 - h^3 - 2*u1*h^2.
|
||||
* t1 and t7 can be used as scratch registers.
|
||||
*/
|
||||
MMUL(P1x, t4, t4),
|
||||
MSUB(P1x, t5),
|
||||
MSUB(P1x, t6),
|
||||
MSUB(P1x, t6),
|
||||
|
||||
/*
|
||||
* Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
|
||||
*/
|
||||
MSUB(t6, P1x),
|
||||
MMUL(P1y, t4, t6),
|
||||
MMUL(t1, t5, t3),
|
||||
MSUB(P1y, t1),
|
||||
|
||||
/*
|
||||
* Compute z3 = h*z1*z2.
|
||||
*/
|
||||
MMUL(t1, P1z, P2z),
|
||||
MMUL(P1z, t1, t2),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
/*
|
||||
* Check that the point is on the curve. This code snippet assumes the
|
||||
* following conventions:
|
||||
* -- Coordinates x and y have been freshly decoded in P1 (but not
|
||||
* converted to Montgomery coordinates yet).
|
||||
* -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
|
||||
*/
|
||||
static const uint16_t p384_code_check[] = {
|
||||
|
||||
/* Convert x and y to Montgomery representation. */
|
||||
MMUL(t1, P1x, P2x),
|
||||
MMUL(t2, P1y, P2x),
|
||||
MSET(P1x, t1),
|
||||
MSET(P1y, t2),
|
||||
|
||||
/* Compute x^3 in t1. */
|
||||
MMUL(t2, P1x, P1x),
|
||||
MMUL(t1, P1x, t2),
|
||||
|
||||
/* Subtract 3*x from t1. */
|
||||
MSUB(t1, P1x),
|
||||
MSUB(t1, P1x),
|
||||
MSUB(t1, P1x),
|
||||
|
||||
/* Add b. */
|
||||
MADD(t1, P2y),
|
||||
|
||||
/* Compute y^2 in t2. */
|
||||
MMUL(t2, P1y, P1y),
|
||||
|
||||
/* Compare y^2 with x^3 - 3*x + b; they must match. */
|
||||
MSUB(t1, t2),
|
||||
MTZ(t1),
|
||||
|
||||
/* Set z to 1 (in Montgomery representation). */
|
||||
MMUL(P1z, P2x, P2z),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
/*
|
||||
* Conversion back to affine coordinates. This code snippet assumes that
|
||||
* the z coordinate of P2 is set to 1 (not in Montgomery representation).
|
||||
*/
|
||||
static const uint16_t p384_code_affine[] = {
|
||||
|
||||
/* Save z*R in t1. */
|
||||
MSET(t1, P1z),
|
||||
|
||||
/* Compute z^3 in t2. */
|
||||
MMUL(t2, P1z, P1z),
|
||||
MMUL(t3, P1z, t2),
|
||||
MMUL(t2, t3, P2z),
|
||||
|
||||
/* Invert to (1/z^3) in t2. */
|
||||
MINV(t2, t3, t4),
|
||||
|
||||
/* Compute y. */
|
||||
MSET(t3, P1y),
|
||||
MMUL(P1y, t2, t3),
|
||||
|
||||
/* Compute (1/z^2) in t3. */
|
||||
MMUL(t3, t2, t1),
|
||||
|
||||
/* Compute x. */
|
||||
MSET(t2, P1x),
|
||||
MMUL(P1x, t2, t3),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
p384_run_code(struct p384_jacobian *P1, const struct p384_jacobian *P2,
|
||||
const struct p384_curve_params *cc, const uint16_t *code)
|
||||
{
|
||||
uint32_t r;
|
||||
uint32_t t[13][I31_LEN];
|
||||
size_t u;
|
||||
|
||||
r = 1;
|
||||
|
||||
/*
|
||||
* Copy the two operands in the dedicated registers.
|
||||
*/
|
||||
memcpy(t[P1x], P1->c, 3 * I31_LEN * sizeof(uint32_t));
|
||||
memcpy(t[P2x], P2->c, 3 * I31_LEN * sizeof(uint32_t));
|
||||
|
||||
/*
|
||||
* Run formulas.
|
||||
*/
|
||||
for (u = 0;; u ++) {
|
||||
unsigned op, d, a, b;
|
||||
|
||||
op = code[u];
|
||||
if (op == 0) {
|
||||
break;
|
||||
}
|
||||
d = (op >> 8) & 0x0F;
|
||||
a = (op >> 4) & 0x0F;
|
||||
b = op & 0x0F;
|
||||
op >>= 12;
|
||||
switch (op) {
|
||||
uint32_t ctl;
|
||||
size_t plen;
|
||||
unsigned char tp[(MG_BR_MAX_EC_SIZE + 7) >> 3];
|
||||
|
||||
case 0:
|
||||
memcpy(t[d], t[a], I31_LEN * sizeof(uint32_t));
|
||||
break;
|
||||
case 1:
|
||||
ctl = mg_br_i31_add(t[d], t[a], 1);
|
||||
ctl |= MG_BR_NOT(mg_br_i31_sub(t[d], cc->p, 0));
|
||||
mg_br_i31_sub(t[d], cc->p, ctl);
|
||||
break;
|
||||
case 2:
|
||||
mg_br_i31_add(t[d], cc->p, mg_br_i31_sub(t[d], t[a], 1));
|
||||
break;
|
||||
case 3:
|
||||
mg_br_i31_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
|
||||
break;
|
||||
case 4:
|
||||
plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3;
|
||||
mg_br_i31_encode(tp, plen, cc->p);
|
||||
tp[plen - 1] -= 2;
|
||||
mg_br_i31_modpow(t[d], tp, plen,
|
||||
cc->p, cc->p0i, t[a], t[b]);
|
||||
break;
|
||||
default:
|
||||
r &= ~mg_br_i31_iszero(t[d]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy back result.
|
||||
*/
|
||||
memcpy(P1->c, t[P1x], 3 * I31_LEN * sizeof(uint32_t));
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
p384_set_one(uint32_t *x, const uint32_t *p)
|
||||
{
|
||||
size_t plen;
|
||||
|
||||
plen = (p[0] + 63) >> 5;
|
||||
memset(x, 0, plen * sizeof *x);
|
||||
x[0] = p[0];
|
||||
x[1] = 0x00000001;
|
||||
}
|
||||
|
||||
static void
|
||||
p384_point_zero(struct p384_jacobian *P, const struct p384_curve_params *cc)
|
||||
{
|
||||
memset(P, 0, sizeof *P);
|
||||
P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0];
|
||||
}
|
||||
|
||||
static inline void
|
||||
p384_point_double(struct p384_jacobian *P, const struct p384_curve_params *cc)
|
||||
{
|
||||
p384_run_code(P, P, cc, p384_code_double);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
p384_point_add(struct p384_jacobian *P1, const struct p384_jacobian *P2, const struct p384_curve_params *cc)
|
||||
{
|
||||
return p384_run_code(P1, P2, cc, p384_code_add);
|
||||
}
|
||||
|
||||
static void
|
||||
p384_point_mul(struct p384_jacobian *P, const unsigned char *x, size_t xlen,
|
||||
const struct p384_curve_params *cc)
|
||||
{
|
||||
/*
|
||||
* We do a simple double-and-add ladder with a 2-bit window
|
||||
* to make only one add every two doublings. We thus first
|
||||
* precompute 2P and 3P in some local buffers.
|
||||
*
|
||||
* We always perform two doublings and one addition; the
|
||||
* addition is with P, 2P and 3P and is done in a temporary
|
||||
* array.
|
||||
*
|
||||
* The addition code cannot handle cases where one of the
|
||||
* operands is infinity, which is the case at the start of the
|
||||
* ladder. We therefore need to maintain a flag that controls
|
||||
* this situation.
|
||||
*/
|
||||
uint32_t qz;
|
||||
struct p384_jacobian P2, P3, Q, T, U;
|
||||
|
||||
memcpy(&P2, P, sizeof P2);
|
||||
p384_point_double(&P2, cc);
|
||||
memcpy(&P3, P, sizeof P3);
|
||||
p384_point_add(&P3, &P2, cc);
|
||||
|
||||
p384_point_zero(&Q, cc);
|
||||
qz = 1;
|
||||
while (xlen -- > 0) {
|
||||
int k;
|
||||
|
||||
for (k = 6; k >= 0; k -= 2) {
|
||||
uint32_t bits;
|
||||
uint32_t bnz;
|
||||
|
||||
p384_point_double(&Q, cc);
|
||||
p384_point_double(&Q, cc);
|
||||
memcpy(&T, P, sizeof T);
|
||||
memcpy(&U, &Q, sizeof U);
|
||||
bits = (*x >> k) & (uint32_t)3;
|
||||
bnz = MG_BR_NEQ(bits, 0);
|
||||
MG_BR_CCOPY(MG_BR_EQ(bits, 2), &T, &P2, sizeof T);
|
||||
MG_BR_CCOPY(MG_BR_EQ(bits, 3), &T, &P3, sizeof T);
|
||||
p384_point_add(&U, &T, cc);
|
||||
MG_BR_CCOPY(bnz & qz, &Q, &T, sizeof Q);
|
||||
MG_BR_CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
|
||||
qz &= ~bnz;
|
||||
}
|
||||
x ++;
|
||||
}
|
||||
memcpy(P, &Q, sizeof Q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode point into Jacobian coordinates. This function does not support
|
||||
* the point at infinity. If the point is invalid then this returns 0, but
|
||||
* the coordinates are still set to properly formed field elements.
|
||||
*/
|
||||
static uint32_t
|
||||
p384_point_decode(struct p384_jacobian *P, const void *src, size_t len, const struct p384_curve_params *cc)
|
||||
{
|
||||
/*
|
||||
* Points must use uncompressed format:
|
||||
* -- first byte is 0x04;
|
||||
* -- coordinates X and Y use unsigned big-endian, with the same
|
||||
* length as the field modulus.
|
||||
*
|
||||
* We don't support hybrid format (uncompressed, but first byte
|
||||
* has value 0x06 or 0x07, depending on the least significant bit
|
||||
* of Y) because it is rather useless, and explicitly forbidden
|
||||
* by PKIX (RFC 5480, section 2.2).
|
||||
*
|
||||
* We don't support compressed format either, because it is not
|
||||
* much used in practice (there are or were patent-related
|
||||
* concerns about point compression, which explains the lack of
|
||||
* generalised support). Also, point compression support would
|
||||
* need a bit more code.
|
||||
*/
|
||||
const unsigned char *buf;
|
||||
size_t plen, zlen;
|
||||
uint32_t r;
|
||||
struct p384_jacobian Q;
|
||||
|
||||
buf = (const unsigned char *)src;
|
||||
p384_point_zero(P, cc);
|
||||
plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3;
|
||||
if (len != 1 + (plen << 1)) {
|
||||
return 0;
|
||||
}
|
||||
r = mg_br_i31_decode_mod(P->c[0], buf + 1, plen, cc->p);
|
||||
r &= mg_br_i31_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);
|
||||
|
||||
/*
|
||||
* Check first byte.
|
||||
*/
|
||||
r &= MG_BR_EQ(buf[0], 0x04);
|
||||
/* obsolete
|
||||
r &= MG_BR_EQ(buf[0], 0x04) | (MG_BR_EQ(buf[0] & 0xFE, 0x06)
|
||||
& ~(uint32_t)(buf[0] ^ buf[plen << 1]));
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convert coordinates and check that the point is valid.
|
||||
*/
|
||||
zlen = ((cc->p[0] + 63) >> 5) * sizeof(uint32_t);
|
||||
memcpy(Q.c[0], cc->R2, zlen);
|
||||
memcpy(Q.c[1], cc->b, zlen);
|
||||
p384_set_one(Q.c[2], cc->p);
|
||||
r &= ~p384_run_code(P, &Q, cc, p384_code_check);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode a point. This method assumes that the point is correct and is
|
||||
* not the point at infinity. Encoded size is always 1+2*plen, where
|
||||
* plen is the field modulus length, in bytes.
|
||||
*/
|
||||
static void
|
||||
p384_point_encode(void *dst, const struct p384_jacobian *P, const struct p384_curve_params *cc)
|
||||
{
|
||||
unsigned char *buf;
|
||||
uint32_t xbl;
|
||||
size_t plen;
|
||||
struct p384_jacobian Q, T;
|
||||
|
||||
buf = (unsigned char *)dst;
|
||||
xbl = cc->p[0];
|
||||
xbl -= (xbl >> 5);
|
||||
plen = (xbl + 7) >> 3;
|
||||
buf[0] = 0x04;
|
||||
memcpy(&Q, P, sizeof *P);
|
||||
p384_set_one(T.c[2], cc->p);
|
||||
p384_run_code(&Q, &T, cc, p384_code_affine);
|
||||
mg_br_i31_encode(buf + 1, plen, Q.c[0]);
|
||||
mg_br_i31_encode(buf + 1 + plen, plen, Q.c[1]);
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
p384_api_generator(int curve, size_t *len)
|
||||
{
|
||||
(void)curve;
|
||||
*len = sizeof P384_G;
|
||||
return P384_G;
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
p384_api_order(int curve, size_t *len)
|
||||
{
|
||||
(void)curve;
|
||||
*len = sizeof P384_N;
|
||||
return P384_N;
|
||||
}
|
||||
|
||||
static size_t
|
||||
p384_api_xoff(int curve, size_t *len)
|
||||
{
|
||||
p384_api_generator(curve, len);
|
||||
*len >>= 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
p384_api_mul(unsigned char *G, size_t Glen,
|
||||
const unsigned char *x, size_t xlen, int curve)
|
||||
{
|
||||
uint32_t r;
|
||||
const struct p384_curve_params *cc;
|
||||
struct p384_jacobian P;
|
||||
|
||||
cc = p384_id_to_curve(curve);
|
||||
if (Glen != cc->point_len) {
|
||||
return 0;
|
||||
}
|
||||
r = p384_point_decode(&P, G, Glen, cc);
|
||||
p384_point_mul(&P, x, xlen, cc);
|
||||
p384_point_encode(G, &P, cc);
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
p384_api_mulgen(unsigned char *R,
|
||||
const unsigned char *x, size_t xlen, int curve)
|
||||
{
|
||||
const unsigned char *G;
|
||||
size_t Glen;
|
||||
|
||||
G = p384_api_generator(curve, &Glen);
|
||||
memcpy(R, G, Glen);
|
||||
p384_api_mul(R, Glen, x, xlen, curve);
|
||||
return Glen;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
p384_api_muladd(unsigned char *A, const unsigned char *B, size_t len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *y, size_t ylen, int curve)
|
||||
{
|
||||
uint32_t r, t, z;
|
||||
const struct p384_curve_params *cc;
|
||||
struct p384_jacobian P, Q;
|
||||
|
||||
/*
|
||||
* TODO: see about merging the two ladders. Right now, we do
|
||||
* two independent point multiplications, which is a bit
|
||||
* wasteful of CPU resources (but yields short code).
|
||||
*/
|
||||
|
||||
cc = p384_id_to_curve(curve);
|
||||
if (len != cc->point_len) {
|
||||
return 0;
|
||||
}
|
||||
r = p384_point_decode(&P, A, len, cc);
|
||||
if (B == NULL) {
|
||||
size_t Glen;
|
||||
|
||||
B = p384_api_generator(curve, &Glen);
|
||||
}
|
||||
r &= p384_point_decode(&Q, B, len, cc);
|
||||
p384_point_mul(&P, x, xlen, cc);
|
||||
p384_point_mul(&Q, y, ylen, cc);
|
||||
|
||||
/*
|
||||
* We want to compute P+Q. Since the base points A and B are distinct
|
||||
* from infinity, and the multipliers are non-zero and lower than the
|
||||
* curve order, then we know that P and Q are non-infinity. This
|
||||
* leaves two special situations to test for:
|
||||
* -- If P = Q then we must use p384_point_double().
|
||||
* -- If P+Q = 0 then we must report an error.
|
||||
*/
|
||||
t = p384_point_add(&P, &Q, cc);
|
||||
p384_point_double(&Q, cc);
|
||||
z = mg_br_i31_iszero(P.c[2]);
|
||||
|
||||
/*
|
||||
* If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
|
||||
* have the following:
|
||||
*
|
||||
* z = 0, t = 0 return P (normal addition)
|
||||
* z = 0, t = 1 return P (normal addition)
|
||||
* z = 1, t = 0 return Q (a 'double' case)
|
||||
* z = 1, t = 1 report an error (P+Q = 0)
|
||||
*/
|
||||
MG_BR_CCOPY(z & ~t, &P, &Q, sizeof Q);
|
||||
p384_point_encode(A, &P, cc);
|
||||
r &= ~(z & t);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct mg_br_ec_impl mg_br_ec_prime_i31 = {
|
||||
(uint32_t)1 << MG_BR_EC_secp384r1,
|
||||
&p384_api_generator,
|
||||
&p384_api_order,
|
||||
&p384_api_xoff,
|
||||
&p384_api_mul,
|
||||
&p384_api_mulgen,
|
||||
&p384_api_muladd
|
||||
};
|
||||
|
||||
// See tls_p384.h
|
||||
int mg_p384_verify(const uint8_t public_key[96], const uint8_t *hash,
|
||||
size_t hash_size, const uint8_t signature[96]) {
|
||||
unsigned char q[97];
|
||||
q[0] = 0x04;
|
||||
memcpy(q + 1, public_key, 96);
|
||||
return mg_br_ecdsa_i31_vrfy_raw(&mg_br_ec_prime_i31, MG_BR_EC_secp384r1, hash,
|
||||
hash_size, q, sizeof(q), signature, 96) == 1;
|
||||
}
|
||||
|
||||
// Undefine local macros, mongoose.c is one translation unit
|
||||
#undef I31_LEN
|
||||
#undef MSET
|
||||
#undef MADD
|
||||
#undef MSUB
|
||||
#undef MMUL
|
||||
#undef MINV
|
||||
#undef MTZ
|
||||
#undef ENDCODE
|
||||
#undef P1x
|
||||
#undef P1y
|
||||
#undef P1z
|
||||
#undef P2x
|
||||
#undef P2y
|
||||
#undef P2z
|
||||
#undef Px
|
||||
#undef Py
|
||||
#undef Pz
|
||||
#undef t1
|
||||
#undef t2
|
||||
#undef t3
|
||||
#undef t4
|
||||
#undef t5
|
||||
#undef t6
|
||||
#undef t7
|
||||
#undef t8
|
||||
#undef t9
|
||||
#undef t10
|
||||
#endif // MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
@@ -0,0 +1,40 @@
|
||||
// P-384 from BearSSL, https://bearssl.org commit 7bea48e
|
||||
// P-384 signature verification, used by built-in TLS for certificates and
|
||||
// CertificateVerify. Shared bignum and ECDSA code is in tls_p256.c
|
||||
//
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Mongoose changes: br_ / BR_ names are prefixed with mg_ / MG_, static
|
||||
// functions with p384_. Trimmed to P-384. Structs are not typedef-ed
|
||||
#pragma once
|
||||
|
||||
#include "arch.h"
|
||||
#include "config.h"
|
||||
#include "tls.h"
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
// Verify ECDSA P-384 signature r || s over hash. Public key is X || Y.
|
||||
// Return 1 on success, 0 on failure
|
||||
int mg_p384_verify(const uint8_t public_key[96], const uint8_t *hash,
|
||||
size_t hash_size, const uint8_t signature[96]);
|
||||
#endif // MG_TLS == MG_TLS_BUILTIN || defined(MG_OTA_PUBLIC_KEY)
|
||||
-3304
File diff suppressed because it is too large.
Load diff
-659
@@ -1,659 +0,0 @@
|
||||
#pragma once
|
||||
#include "arch.h"
|
||||
|
||||
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_H_
|
||||
#define _UECC_H_
|
||||
|
||||
/* Platform selection options.
|
||||
If MG_UECC_PLATFORM is not defined, the code will try to guess it based on
|
||||
compiler macros. Possible values for MG_UECC_PLATFORM are defined below: */
|
||||
#define mg_uecc_arch_other 0
|
||||
#define mg_uecc_x86 1
|
||||
#define mg_uecc_x86_64 2
|
||||
#define mg_uecc_arm 3
|
||||
#define mg_uecc_arm_thumb 4
|
||||
#define mg_uecc_arm_thumb2 5
|
||||
#define mg_uecc_arm64 6
|
||||
#define mg_uecc_avr 7
|
||||
|
||||
/* If desired, you can define MG_UECC_WORD_SIZE as appropriate for your platform
|
||||
(1, 4, or 8 bytes). If MG_UECC_WORD_SIZE is not explicitly defined then it will
|
||||
be automatically set based on your platform. */
|
||||
|
||||
/* Optimization level; trade speed for code size.
|
||||
Larger values produce code that is faster but larger.
|
||||
Currently supported values are 0 - 4; 0 is unusably slow for most
|
||||
applications. Optimization level 4 currently only has an effect ARM platforms
|
||||
where more than one curve is enabled. */
|
||||
#ifndef MG_UECC_OPTIMIZATION_LEVEL
|
||||
#define MG_UECC_OPTIMIZATION_LEVEL 2
|
||||
#endif
|
||||
|
||||
/* MG_UECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a
|
||||
specific function to be used for (scalar) squaring instead of the generic
|
||||
multiplication function. This can make things faster somewhat faster, but
|
||||
increases the code size. */
|
||||
#ifndef MG_UECC_SQUARE_FUNC
|
||||
#define MG_UECC_SQUARE_FUNC 0
|
||||
#endif
|
||||
|
||||
/* MG_UECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will
|
||||
switch to native little-endian format for *all* arrays passed in and out of the
|
||||
public API. This includes public and private keys, shared secrets, signatures
|
||||
and message hashes. Using this switch reduces the amount of call stack memory
|
||||
used by uECC, since less intermediate translations are required. Note that this
|
||||
will *only* work on native little-endian processors and it will treat the
|
||||
uint8_t arrays passed into the public API as word arrays, therefore requiring
|
||||
the provided byte arrays to be word aligned on architectures that do not support
|
||||
unaligned accesses. IMPORTANT: Keys and signatures generated with
|
||||
MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures
|
||||
generated with MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same
|
||||
endianness. */
|
||||
#ifndef MG_UECC_VLI_NATIVE_LITTLE_ENDIAN
|
||||
#define MG_UECC_VLI_NATIVE_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/* Curve support selection. Set to 0 to remove that curve. */
|
||||
#ifndef MG_UECC_SUPPORTS_secp160r1
|
||||
#define MG_UECC_SUPPORTS_secp160r1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp192r1
|
||||
#define MG_UECC_SUPPORTS_secp192r1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp224r1
|
||||
#define MG_UECC_SUPPORTS_secp224r1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp256r1
|
||||
#define MG_UECC_SUPPORTS_secp256r1 1
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp256k1
|
||||
#define MG_UECC_SUPPORTS_secp256k1 0
|
||||
#endif
|
||||
#ifndef MG_UECC_SUPPORTS_secp384r1
|
||||
#define MG_UECC_SUPPORTS_secp384r1 1
|
||||
#endif
|
||||
|
||||
/* Specifies whether compressed point format is supported.
|
||||
Set to 0 to disable point compression/decompression functions. */
|
||||
#ifndef MG_UECC_SUPPORT_COMPRESSED_POINT
|
||||
#define MG_UECC_SUPPORT_COMPRESSED_POINT 1
|
||||
#endif
|
||||
|
||||
struct MG_UECC_Curve_t;
|
||||
typedef const struct MG_UECC_Curve_t *MG_UECC_Curve;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MG_UECC_SUPPORTS_secp160r1
|
||||
MG_UECC_Curve mg_uecc_secp160r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp192r1
|
||||
MG_UECC_Curve mg_uecc_secp192r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp224r1
|
||||
MG_UECC_Curve mg_uecc_secp224r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp256r1
|
||||
MG_UECC_Curve mg_uecc_secp256r1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp256k1
|
||||
MG_UECC_Curve mg_uecc_secp256k1(void);
|
||||
#endif
|
||||
#if MG_UECC_SUPPORTS_secp384r1
|
||||
MG_UECC_Curve mg_uecc_secp384r1(void);
|
||||
#endif
|
||||
|
||||
/* MG_UECC_RNG_Function type
|
||||
The RNG function should fill 'size' random bytes into 'dest'. It should return 1
|
||||
if 'dest' was filled with random data, or 0 if the random data could not be
|
||||
generated. The filled-in values should be either truly random, or from a
|
||||
cryptographically-secure PRNG.
|
||||
|
||||
A correctly functioning RNG is required before calling mg_uecc_make_key() or
|
||||
mg_uecc_sign().
|
||||
|
||||
Setting a correctly functioning RNG function improves the resistance to
|
||||
side-channel attacks for mg_uecc_shared_secret() and
|
||||
mg_uecc_sign_deterministic().
|
||||
*/
|
||||
typedef int (*MG_UECC_RNG_Function)(uint8_t *dest, unsigned size);
|
||||
|
||||
// Mongoose: mg_uecc_make_key() and mg_uecc_sign() use mg_random() when no
|
||||
// explicit uECC RNG is installed. If mg_random() cannot provide a strong source,
|
||||
// those operations fail. Deterministic signing works without RNG, but only an
|
||||
// explicit uECC RNG enables its optional side-channel blinding.
|
||||
|
||||
/* mg_uecc_set_rng() function.
|
||||
Set the function that will be used to generate random bytes. The RNG function
|
||||
should return 1 if the random data was generated, or 0 if the random data could
|
||||
not be generated.
|
||||
|
||||
Mongoose: this overrides the default mg_random() fallback used by
|
||||
mg_uecc_make_key() and mg_uecc_sign(). Do not call mg_uecc_set_rng() unless the
|
||||
application must provide its own cryptographic RNG.
|
||||
|
||||
Inputs:
|
||||
rng_function - The function that will be used to generate random bytes.
|
||||
*/
|
||||
void mg_uecc_set_rng(MG_UECC_RNG_Function rng_function);
|
||||
|
||||
/* mg_uecc_get_rng() function.
|
||||
|
||||
Returns the function that will be used to generate random bytes.
|
||||
*/
|
||||
MG_UECC_RNG_Function mg_uecc_get_rng(void);
|
||||
|
||||
/* mg_uecc_curve_private_key_size() function.
|
||||
|
||||
Returns the size of a private key for the curve in bytes.
|
||||
*/
|
||||
int mg_uecc_curve_private_key_size(MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_curve_public_key_size() function.
|
||||
|
||||
Returns the size of a public key for the curve in bytes.
|
||||
*/
|
||||
int mg_uecc_curve_public_key_size(MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_make_key() function.
|
||||
Create a public/private key pair.
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the public key. Must be at least 2 *
|
||||
the curve size (in bytes) long. For example, if the curve is secp256r1,
|
||||
public_key must be 64 bytes long. private_key - Will be filled in with the
|
||||
private key. Must be as long as the curve order; this is typically the same as
|
||||
the curve size, except for secp160r1. For example, if the curve is secp256r1,
|
||||
private_key must be 32 bytes long.
|
||||
|
||||
For secp160r1, private_key must be 21 bytes long! Note that
|
||||
the first byte will almost always be 0 (there is about a 1 in 2^80 chance of it
|
||||
being non-zero).
|
||||
|
||||
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_make_key(uint8_t *public_key, uint8_t *private_key,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_shared_secret() function.
|
||||
Compute a shared secret given your secret key and someone else's public key. If
|
||||
the public key is not from a trusted source and has not been previously
|
||||
verified, you should verify it first using mg_uecc_valid_public_key(). Note: It
|
||||
is recommended that you hash the result of mg_uecc_shared_secret() before using
|
||||
it for symmetric encryption or HMAC.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key of the remote party.
|
||||
private_key - Your private key.
|
||||
|
||||
Outputs:
|
||||
secret - Will be filled in with the shared secret value. Must be the same
|
||||
size as the curve size; for example, if the curve is secp256r1, secret must be
|
||||
32 bytes long.
|
||||
|
||||
Returns 1 if the shared secret was generated successfully, 0 if an error
|
||||
occurred.
|
||||
*/
|
||||
int mg_uecc_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
|
||||
uint8_t *secret, MG_UECC_Curve curve);
|
||||
|
||||
#if MG_UECC_SUPPORT_COMPRESSED_POINT
|
||||
/* mg_uecc_compress() function.
|
||||
Compress a public key.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key to compress.
|
||||
|
||||
Outputs:
|
||||
compressed - Will be filled in with the compressed public key. Must be at
|
||||
least (curve size + 1) bytes long; for example, if the curve is secp256r1,
|
||||
compressed must be 33 bytes long.
|
||||
*/
|
||||
void mg_uecc_compress(const uint8_t *public_key, uint8_t *compressed,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_decompress() function.
|
||||
Decompress a compressed public key.
|
||||
|
||||
Inputs:
|
||||
compressed - The compressed public key.
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the decompressed public key.
|
||||
*/
|
||||
void mg_uecc_decompress(const uint8_t *compressed, uint8_t *public_key,
|
||||
MG_UECC_Curve curve);
|
||||
#endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */
|
||||
|
||||
/* mg_uecc_valid_public_key() function.
|
||||
Check to see if a public key is valid.
|
||||
|
||||
Note that you are not required to check for a valid public key before using any
|
||||
other uECC functions. However, you may wish to avoid spending CPU time computing
|
||||
a shared secret or verifying a signature using an invalid public key.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key to check.
|
||||
|
||||
Returns 1 if the public key is valid, 0 if it is invalid.
|
||||
*/
|
||||
int mg_uecc_valid_public_key(const uint8_t *public_key, MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_compute_public_key() function.
|
||||
Compute the corresponding public key for a private key.
|
||||
|
||||
Inputs:
|
||||
private_key - The private key to compute the public key for
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the corresponding public key
|
||||
|
||||
Returns 1 if the key was computed successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_sign() function.
|
||||
Generate an ECDSA signature for a given hash value.
|
||||
|
||||
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
|
||||
pass it in to this function along with your private key.
|
||||
|
||||
Inputs:
|
||||
private_key - Your private key.
|
||||
message_hash - The hash of the message to sign.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
|
||||
Outputs:
|
||||
signature - Will be filled in with the signature value. Must be at least 2 *
|
||||
curve size long. For example, if the curve is secp256r1, signature must be 64
|
||||
bytes long.
|
||||
|
||||
Returns 1 if the signature generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_sign(const uint8_t *private_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, uint8_t *signature, MG_UECC_Curve curve);
|
||||
|
||||
/* MG_UECC_HashContext structure.
|
||||
This is used to pass in an arbitrary hash function to
|
||||
mg_uecc_sign_deterministic(). The structure will be used for multiple hash
|
||||
computations; each time a new hash is computed, init_hash() will be called,
|
||||
followed by one or more calls to update_hash(), and finally a call to
|
||||
finish_hash() to produce the resulting hash.
|
||||
|
||||
The intention is that you will create a structure that includes
|
||||
MG_UECC_HashContext followed by any hash-specific data. For example:
|
||||
|
||||
typedef struct SHA256_HashContext {
|
||||
MG_UECC_HashContext uECC;
|
||||
SHA256_CTX ctx;
|
||||
} SHA256_HashContext;
|
||||
|
||||
void init_SHA256(MG_UECC_HashContext *base) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Init(&context->ctx);
|
||||
}
|
||||
|
||||
void update_SHA256(MG_UECC_HashContext *base,
|
||||
const uint8_t *message,
|
||||
unsigned message_size) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Update(&context->ctx, message, message_size);
|
||||
}
|
||||
|
||||
void finish_SHA256(MG_UECC_HashContext *base, uint8_t *hash_result) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Final(hash_result, &context->ctx);
|
||||
}
|
||||
|
||||
... when signing ...
|
||||
{
|
||||
uint8_t tmp[32 + 32 + 64];
|
||||
SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64,
|
||||
32, tmp}}; mg_uecc_sign_deterministic(key, message_hash, &ctx.uECC, signature);
|
||||
}
|
||||
*/
|
||||
typedef struct MG_UECC_HashContext {
|
||||
void (*init_hash)(const struct MG_UECC_HashContext *context);
|
||||
void (*update_hash)(const struct MG_UECC_HashContext *context,
|
||||
const uint8_t *message, unsigned message_size);
|
||||
void (*finish_hash)(const struct MG_UECC_HashContext *context,
|
||||
uint8_t *hash_result);
|
||||
unsigned
|
||||
block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
|
||||
unsigned
|
||||
result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
|
||||
uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size +
|
||||
block_size) bytes. */
|
||||
} MG_UECC_HashContext;
|
||||
|
||||
/* mg_uecc_sign_deterministic() function.
|
||||
Generate an ECDSA signature for a given hash value, using a deterministic
|
||||
algorithm (see RFC 6979). You do not need to set the RNG using mg_uecc_set_rng()
|
||||
before calling this function; however, if the RNG is defined it will improve
|
||||
resistance to side-channel attacks.
|
||||
|
||||
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
|
||||
pass it to this function along with your private key and a hash context. Note
|
||||
that the message_hash does not need to be computed with the same hash function
|
||||
used by hash_context.
|
||||
|
||||
Inputs:
|
||||
private_key - Your private key.
|
||||
message_hash - The hash of the message to sign.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
hash_context - A hash context to use.
|
||||
|
||||
Outputs:
|
||||
signature - Will be filled in with the signature value.
|
||||
|
||||
Returns 1 if the signature generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int mg_uecc_sign_deterministic(const uint8_t *private_key,
|
||||
const uint8_t *message_hash, unsigned hash_size,
|
||||
const MG_UECC_HashContext *hash_context,
|
||||
uint8_t *signature, MG_UECC_Curve curve);
|
||||
|
||||
/* mg_uecc_verify() function.
|
||||
Verify an ECDSA signature.
|
||||
|
||||
Usage: Compute the hash of the signed data using the same hash as the signer and
|
||||
pass it to this function along with the signer's public key and the signature
|
||||
values (r and s).
|
||||
|
||||
Inputs:
|
||||
public_key - The signer's public key.
|
||||
message_hash - The hash of the signed data.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
signature - The signature value.
|
||||
|
||||
Returns 1 if the signature is valid, 0 if it is invalid.
|
||||
*/
|
||||
int mg_uecc_verify(const uint8_t *public_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, const uint8_t *signature,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _UECC_H_ */
|
||||
|
||||
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_TYPES_H_
|
||||
#define _UECC_TYPES_H_
|
||||
|
||||
#ifndef MG_UECC_PLATFORM
|
||||
#if defined(__AVR__) && __AVR__
|
||||
#define MG_UECC_PLATFORM mg_uecc_avr
|
||||
#elif defined(__thumb2__) || \
|
||||
defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm_thumb2
|
||||
#elif defined(__thumb__)
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm_thumb
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm
|
||||
#elif defined(__aarch64__)
|
||||
#define MG_UECC_PLATFORM mg_uecc_arm64
|
||||
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \
|
||||
defined(__I86__)
|
||||
#define MG_UECC_PLATFORM mg_uecc_x86
|
||||
#elif defined(__amd64__) || defined(_M_X64)
|
||||
#define MG_UECC_PLATFORM mg_uecc_x86_64
|
||||
#else
|
||||
#define MG_UECC_PLATFORM mg_uecc_arch_other
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MG_UECC_ARM_USE_UMAAL
|
||||
#if (MG_UECC_PLATFORM == mg_uecc_arm) && (__ARM_ARCH >= 6)
|
||||
#define MG_UECC_ARM_USE_UMAAL 1
|
||||
#elif (MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && (__ARM_ARCH >= 6) && \
|
||||
(!defined(__ARM_ARCH_7M__) || !__ARM_ARCH_7M__)
|
||||
#define MG_UECC_ARM_USE_UMAAL 1
|
||||
#else
|
||||
#define MG_UECC_ARM_USE_UMAAL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MG_UECC_WORD_SIZE
|
||||
#if MG_UECC_PLATFORM == mg_uecc_avr
|
||||
#define MG_UECC_WORD_SIZE 1
|
||||
#elif (MG_UECC_PLATFORM == mg_uecc_x86_64 || MG_UECC_PLATFORM == mg_uecc_arm64)
|
||||
#define MG_UECC_WORD_SIZE 8
|
||||
#else
|
||||
#define MG_UECC_WORD_SIZE 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (MG_UECC_WORD_SIZE != 1) && (MG_UECC_WORD_SIZE != 4) && \
|
||||
(MG_UECC_WORD_SIZE != 8)
|
||||
#error "Unsupported value for MG_UECC_WORD_SIZE"
|
||||
#endif
|
||||
|
||||
#if ((MG_UECC_PLATFORM == mg_uecc_avr) && (MG_UECC_WORD_SIZE != 1))
|
||||
#pragma message("MG_UECC_WORD_SIZE must be 1 for AVR")
|
||||
#undef MG_UECC_WORD_SIZE
|
||||
#define MG_UECC_WORD_SIZE 1
|
||||
#endif
|
||||
|
||||
#if ((MG_UECC_PLATFORM == mg_uecc_arm || \
|
||||
MG_UECC_PLATFORM == mg_uecc_arm_thumb || \
|
||||
MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && \
|
||||
(MG_UECC_WORD_SIZE != 4))
|
||||
#pragma message("MG_UECC_WORD_SIZE must be 4 for ARM")
|
||||
#undef MG_UECC_WORD_SIZE
|
||||
#define MG_UECC_WORD_SIZE 4
|
||||
#endif
|
||||
|
||||
typedef int8_t wordcount_t;
|
||||
typedef int16_t bitcount_t;
|
||||
typedef int8_t cmpresult_t;
|
||||
|
||||
#if (MG_UECC_WORD_SIZE == 1)
|
||||
|
||||
typedef uint8_t mg_uecc_word_t;
|
||||
typedef uint16_t mg_uecc_dword_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x80
|
||||
#define MG_UECC_WORD_BITS 8
|
||||
#define MG_UECC_WORD_BITS_SHIFT 3
|
||||
#define MG_UECC_WORD_BITS_MASK 0x07
|
||||
|
||||
#elif (MG_UECC_WORD_SIZE == 4)
|
||||
|
||||
typedef uint32_t mg_uecc_word_t;
|
||||
typedef uint64_t mg_uecc_dword_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x80000000
|
||||
#define MG_UECC_WORD_BITS 32
|
||||
#define MG_UECC_WORD_BITS_SHIFT 5
|
||||
#define MG_UECC_WORD_BITS_MASK 0x01F
|
||||
|
||||
#elif (MG_UECC_WORD_SIZE == 8)
|
||||
|
||||
typedef uint64_t mg_uecc_word_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x8000000000000000U
|
||||
#define MG_UECC_WORD_BITS 64
|
||||
#define MG_UECC_WORD_BITS_SHIFT 6
|
||||
#define MG_UECC_WORD_BITS_MASK 0x03F
|
||||
|
||||
#endif /* MG_UECC_WORD_SIZE */
|
||||
|
||||
#endif /* _UECC_TYPES_H_ */
|
||||
|
||||
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_VLI_H_
|
||||
#define _UECC_VLI_H_
|
||||
|
||||
// #include "types.h"
|
||||
// #include "uECC.h"
|
||||
|
||||
/* Functions for raw large-integer manipulation. These are only available
|
||||
if uECC.c is compiled with MG_UECC_ENABLE_VLI_API defined to 1. */
|
||||
#ifndef MG_UECC_ENABLE_VLI_API
|
||||
#define MG_UECC_ENABLE_VLI_API 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MG_UECC_ENABLE_VLI_API
|
||||
|
||||
void mg_uecc_vli_clear(mg_uecc_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison to zero - secure way to compare long integers */
|
||||
/* Returns 1 if vli == 0, 0 otherwise. */
|
||||
mg_uecc_word_t mg_uecc_vli_isZero(const mg_uecc_word_t *vli,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Returns nonzero if bit 'bit' of vli is set. */
|
||||
mg_uecc_word_t mg_uecc_vli_testBit(const mg_uecc_word_t *vli, bitcount_t bit);
|
||||
|
||||
/* Counts the number of bits required to represent vli. */
|
||||
bitcount_t mg_uecc_vli_numBits(const mg_uecc_word_t *vli,
|
||||
const wordcount_t max_words);
|
||||
|
||||
/* Sets dest = src. */
|
||||
void mg_uecc_vli_set(mg_uecc_word_t *dest, const mg_uecc_word_t *src,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison function - secure way to compare long integers */
|
||||
/* Returns one if left == right, zero otherwise */
|
||||
mg_uecc_word_t mg_uecc_vli_equal(const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison function - secure way to compare long integers */
|
||||
/* Returns sign of left - right, in constant time. */
|
||||
cmpresult_t mg_uecc_vli_cmp(const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, wordcount_t num_words);
|
||||
|
||||
/* Computes vli = vli >> 1. */
|
||||
void mg_uecc_vli_rshift1(mg_uecc_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left + right, returning carry. Can modify in place. */
|
||||
mg_uecc_word_t mg_uecc_vli_add(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = left - right, returning borrow. Can modify in place. */
|
||||
mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = left * right. Result must be 2 * num_words long. */
|
||||
void mg_uecc_vli_mult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left^2. Result must be 2 * num_words long. */
|
||||
void mg_uecc_vli_square(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left + right) % mod.
|
||||
Assumes that left < mod and right < mod, and that result does not overlap
|
||||
mod. */
|
||||
void mg_uecc_vli_modAdd(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left - right) % mod.
|
||||
Assumes that left < mod and right < mod, and that result does not overlap
|
||||
mod. */
|
||||
void mg_uecc_vli_modSub(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = product % mod, where product is 2N words long.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void mg_uecc_vli_mmod(mg_uecc_word_t *result, mg_uecc_word_t *product,
|
||||
const mg_uecc_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/* Calculates result = product (mod curve->p), where product is up to
|
||||
2 * curve->num_words long. */
|
||||
void mg_uecc_vli_mmod_fast(mg_uecc_word_t *result, mg_uecc_word_t *product,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* Computes result = (left * right) % mod.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void mg_uecc_vli_modMult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left * right) % curve->p. */
|
||||
void mg_uecc_vli_modMult_fast(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *right, MG_UECC_Curve curve);
|
||||
|
||||
/* Computes result = left^2 % mod.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void mg_uecc_vli_modSquare(mg_uecc_word_t *result, const mg_uecc_word_t *left,
|
||||
const mg_uecc_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left^2 % curve->p. */
|
||||
void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result,
|
||||
const mg_uecc_word_t *left,
|
||||
MG_UECC_Curve curve);
|
||||
|
||||
/* Computes result = (1 / input) % mod.*/
|
||||
void mg_uecc_vli_modInv(mg_uecc_word_t *result, const mg_uecc_word_t *input,
|
||||
const mg_uecc_word_t *mod, wordcount_t num_words);
|
||||
|
||||
#if MG_UECC_SUPPORT_COMPRESSED_POINT
|
||||
/* Calculates a = sqrt(a) (mod curve->p) */
|
||||
void mg_uecc_vli_mod_sqrt(mg_uecc_word_t *a, MG_UECC_Curve curve);
|
||||
#endif
|
||||
|
||||
/* Converts an integer in uECC native format to big-endian bytes. */
|
||||
void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
|
||||
const mg_uecc_word_t *native);
|
||||
/* Converts big-endian bytes to an integer in uECC native format. */
|
||||
void mg_uecc_vli_bytesToNative(mg_uecc_word_t *native, const uint8_t *bytes,
|
||||
int num_bytes);
|
||||
|
||||
unsigned mg_uecc_curve_num_words(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_bytes(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_bits(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_n_words(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_n_bytes(MG_UECC_Curve curve);
|
||||
unsigned mg_uecc_curve_num_n_bits(MG_UECC_Curve curve);
|
||||
|
||||
const mg_uecc_word_t *mg_uecc_curve_p(MG_UECC_Curve curve);
|
||||
const mg_uecc_word_t *mg_uecc_curve_n(MG_UECC_Curve curve);
|
||||
const mg_uecc_word_t *mg_uecc_curve_G(MG_UECC_Curve curve);
|
||||
const mg_uecc_word_t *mg_uecc_curve_b(MG_UECC_Curve curve);
|
||||
|
||||
int mg_uecc_valid_point(const mg_uecc_word_t *point, MG_UECC_Curve curve);
|
||||
|
||||
/* Multiplies a point by a scalar. Points are represented by the X coordinate
|
||||
followed by the Y coordinate in the same array, both coordinates are
|
||||
curve->num_words long. Note that scalar must be curve->num_n_words long (NOT
|
||||
curve->num_words). */
|
||||
void mg_uecc_point_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point,
|
||||
const mg_uecc_word_t *scalar, MG_UECC_Curve curve);
|
||||
|
||||
/* Generates a random integer in the range 0 < random < top.
|
||||
Both random and top have num_words words. */
|
||||
int mg_uecc_generate_random_int(mg_uecc_word_t *random,
|
||||
const mg_uecc_word_t *top,
|
||||
wordcount_t num_words);
|
||||
|
||||
#endif /* MG_UECC_ENABLE_VLI_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _UECC_VLI_H_ */
|
||||
|
||||
// End of uecc BSD-2
|
||||
@@ -1,262 +0,0 @@
|
||||
/**
|
||||
* Adapted from STROBE: https://strobe.sourceforge.io/
|
||||
* Copyright (c) 2015-2016 Cryptography Research, Inc.
|
||||
* Author: Mike Hamburg
|
||||
* License: MIT License
|
||||
*/
|
||||
#include "tls.h"
|
||||
#include "tls_x25519.h"
|
||||
#include "util.h"
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
|
||||
const uint8_t X25519_BASE_POINT[X25519_BYTES] = {9};
|
||||
|
||||
#define X25519_WBITS 32
|
||||
|
||||
typedef uint32_t limb_t;
|
||||
typedef uint64_t dlimb_t;
|
||||
typedef int64_t sdlimb_t;
|
||||
|
||||
#define NLIMBS (256 / X25519_WBITS)
|
||||
typedef limb_t mg_fe[NLIMBS];
|
||||
|
||||
static limb_t umaal(limb_t *carry, limb_t acc, limb_t mand, limb_t mier) {
|
||||
dlimb_t tmp = (dlimb_t) mand * mier + acc + *carry;
|
||||
*carry = (limb_t) (tmp >> X25519_WBITS);
|
||||
return (limb_t) tmp;
|
||||
}
|
||||
|
||||
// These functions are implemented in terms of umaal on ARM
|
||||
static limb_t adc(limb_t *carry, limb_t acc, limb_t mand) {
|
||||
dlimb_t total = (dlimb_t) *carry + acc + mand;
|
||||
*carry = (limb_t) (total >> X25519_WBITS);
|
||||
return (limb_t) total;
|
||||
}
|
||||
|
||||
static limb_t adc0(limb_t *carry, limb_t acc) {
|
||||
dlimb_t total = (dlimb_t) *carry + acc;
|
||||
*carry = (limb_t) (total >> X25519_WBITS);
|
||||
return (limb_t) total;
|
||||
}
|
||||
|
||||
// - Precondition: carry is small.
|
||||
// - Invariant: result of propagate is < 2^255 + 1 word
|
||||
// - In particular, always less than 2p.
|
||||
// - Also, output x >= min(x,19)
|
||||
static void propagate(mg_fe x, limb_t over) {
|
||||
unsigned i;
|
||||
limb_t carry;
|
||||
over = x[NLIMBS - 1] >> (X25519_WBITS - 1) | over << 1;
|
||||
x[NLIMBS - 1] &= ~((limb_t) 1 << (X25519_WBITS - 1));
|
||||
|
||||
carry = over * 19;
|
||||
for (i = 0; i < NLIMBS; i++) {
|
||||
x[i] = adc0(&carry, x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void add(mg_fe out, const mg_fe a, const mg_fe b) {
|
||||
unsigned i;
|
||||
limb_t carry = 0;
|
||||
for (i = 0; i < NLIMBS; i++) {
|
||||
out[i] = adc(&carry, a[i], b[i]);
|
||||
}
|
||||
propagate(out, carry);
|
||||
}
|
||||
|
||||
static void sub(mg_fe out, const mg_fe a, const mg_fe b) {
|
||||
unsigned i;
|
||||
sdlimb_t carry = -38;
|
||||
for (i = 0; i < NLIMBS; i++) {
|
||||
carry = carry + a[i] - b[i];
|
||||
out[i] = (limb_t) carry;
|
||||
carry >>= X25519_WBITS;
|
||||
}
|
||||
propagate(out, (limb_t) (1 + carry));
|
||||
}
|
||||
|
||||
// `b` can contain less than 8 limbs, thus we use `limb_t *` instead of `mg_fe`
|
||||
// to avoid build warnings
|
||||
static void mul(mg_fe out, const mg_fe a, const limb_t *b, unsigned nb) {
|
||||
limb_t accum[2 * NLIMBS] = {0};
|
||||
unsigned i, j;
|
||||
|
||||
limb_t carry2;
|
||||
for (i = 0; i < nb; i++) {
|
||||
limb_t mand = b[i];
|
||||
carry2 = 0;
|
||||
for (j = 0; j < NLIMBS; j++) {
|
||||
limb_t tmp; // "a" may be misaligned
|
||||
memcpy(&tmp, &a[j], sizeof(tmp)); // So make an aligned copy
|
||||
accum[i + j] = umaal(&carry2, accum[i + j], mand, tmp);
|
||||
}
|
||||
accum[i + j] = carry2;
|
||||
}
|
||||
|
||||
carry2 = 0;
|
||||
for (j = 0; j < NLIMBS; j++) {
|
||||
out[j] = umaal(&carry2, accum[j], 38, accum[j + NLIMBS]);
|
||||
}
|
||||
propagate(out, carry2);
|
||||
}
|
||||
|
||||
static void sqr(mg_fe out, const mg_fe a) {
|
||||
mul(out, a, a, NLIMBS);
|
||||
}
|
||||
static void mul1(mg_fe out, const mg_fe a) {
|
||||
mul(out, a, out, NLIMBS);
|
||||
}
|
||||
static void sqr1(mg_fe a) {
|
||||
mul1(a, a);
|
||||
}
|
||||
|
||||
static void condswap(limb_t a[2 * NLIMBS], limb_t b[2 * NLIMBS],
|
||||
limb_t doswap) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 2 * NLIMBS; i++) {
|
||||
limb_t xor_ab = (a[i] ^ b[i]) & doswap;
|
||||
a[i] ^= xor_ab;
|
||||
b[i] ^= xor_ab;
|
||||
}
|
||||
}
|
||||
|
||||
// Canonicalize a field element x, reducing it to the least residue which is
|
||||
// congruent to it mod 2^255-19
|
||||
// - Precondition: x < 2^255 + 1 word
|
||||
static limb_t canon(mg_fe x) {
|
||||
// First, add 19.
|
||||
unsigned i;
|
||||
limb_t carry0 = 19;
|
||||
limb_t res;
|
||||
sdlimb_t carry;
|
||||
for (i = 0; i < NLIMBS; i++) {
|
||||
x[i] = adc0(&carry0, x[i]);
|
||||
}
|
||||
propagate(x, carry0);
|
||||
|
||||
// Here, 19 <= x2 < 2^255
|
||||
// - This is because we added 19, so before propagate it can't be less
|
||||
// than 19. After propagate, it still can't be less than 19, because if
|
||||
// propagate does anything it adds 19.
|
||||
// - We know that the high bit must be clear, because either the input was ~
|
||||
// 2^255 + one word + 19 (in which case it propagates to at most 2 words) or
|
||||
// it was < 2^255. So now, if we subtract 19, we will get back to something in
|
||||
// [0,2^255-19).
|
||||
carry = -19;
|
||||
res = 0;
|
||||
for (i = 0; i < NLIMBS; i++) {
|
||||
carry += x[i];
|
||||
res |= x[i] = (limb_t) carry;
|
||||
carry >>= X25519_WBITS;
|
||||
}
|
||||
return (limb_t) (((dlimb_t) res - 1) >> X25519_WBITS);
|
||||
}
|
||||
|
||||
static const limb_t a24[1] = {121665};
|
||||
|
||||
static void ladder_part1(mg_fe xs[5]) {
|
||||
limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4];
|
||||
add(t1, x2, z2); // t1 = A
|
||||
sub(z2, x2, z2); // z2 = B
|
||||
add(x2, x3, z3); // x2 = C
|
||||
sub(z3, x3, z3); // z3 = D
|
||||
mul1(z3, t1); // z3 = DA
|
||||
mul1(x2, z2); // x3 = BC
|
||||
add(x3, z3, x2); // x3 = DA+CB
|
||||
sub(z3, z3, x2); // z3 = DA-CB
|
||||
sqr1(t1); // t1 = AA
|
||||
sqr1(z2); // z2 = BB
|
||||
sub(x2, t1, z2); // x2 = E = AA-BB
|
||||
mul(z2, x2, a24, sizeof(a24) / sizeof(a24[0])); // z2 = E*a24
|
||||
add(z2, z2, t1); // z2 = E*a24 + AA
|
||||
}
|
||||
|
||||
static void ladder_part2(mg_fe xs[5], const mg_fe x1) {
|
||||
limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4];
|
||||
sqr1(z3); // z3 = (DA-CB)^2
|
||||
mul1(z3, x1); // z3 = x1 * (DA-CB)^2
|
||||
sqr1(x3); // x3 = (DA+CB)^2
|
||||
mul1(z2, x2); // z2 = AA*(E*a24+AA)
|
||||
sub(x2, t1, x2); // x2 = BB again
|
||||
mul1(x2, t1); // x2 = AA*BB
|
||||
}
|
||||
|
||||
static void x25519_core(mg_fe xs[5], const uint8_t scalar[X25519_BYTES],
|
||||
const uint8_t *x1, int clamp) {
|
||||
int i;
|
||||
mg_fe x1_limbs;
|
||||
limb_t swap = 0;
|
||||
limb_t *x2 = xs[0], *x3 = xs[2], *z3 = xs[3];
|
||||
memset(xs, 0, 4 * sizeof(mg_fe));
|
||||
x2[0] = z3[0] = 1;
|
||||
for (i = 0; i < NLIMBS; i++) {
|
||||
x3[i] = x1_limbs[i] =
|
||||
MG_U32(x1[i * 4 + 3], x1[i * 4 + 2], x1[i * 4 + 1], x1[i * 4]);
|
||||
}
|
||||
|
||||
for (i = 255; i >= 0; i--) {
|
||||
uint8_t bytei = scalar[i / 8];
|
||||
limb_t doswap;
|
||||
if (clamp) {
|
||||
if (i / 8 == 0) {
|
||||
bytei &= (uint8_t) ~7U;
|
||||
} else if (i / 8 == X25519_BYTES - 1) {
|
||||
bytei &= 0x7F;
|
||||
bytei |= 0x40;
|
||||
}
|
||||
}
|
||||
doswap = 0 - (limb_t) ((bytei >> (i % 8)) & 1);
|
||||
condswap(x2, x3, swap ^ doswap);
|
||||
swap = doswap;
|
||||
|
||||
ladder_part1(xs);
|
||||
ladder_part2(xs, (const limb_t *) x1_limbs);
|
||||
}
|
||||
condswap(x2, x3, swap);
|
||||
}
|
||||
|
||||
int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES],
|
||||
const uint8_t x1[X25519_BYTES], int clamp) {
|
||||
int i, ret;
|
||||
mg_fe xs[5], out_limbs;
|
||||
limb_t *x2, *z2, *z3, *prev;
|
||||
static const struct {
|
||||
uint8_t a, c, n;
|
||||
} steps[13] = {{2, 1, 1}, {2, 1, 1}, {4, 2, 3}, {2, 4, 6}, {3, 1, 1},
|
||||
{3, 2, 12}, {4, 3, 25}, {2, 3, 25}, {2, 4, 50}, {3, 2, 125},
|
||||
{3, 1, 2}, {3, 1, 2}, {3, 1, 1}};
|
||||
x25519_core(xs, scalar, x1, clamp);
|
||||
|
||||
// Precomputed inversion chain
|
||||
x2 = xs[0];
|
||||
z2 = xs[1];
|
||||
z3 = xs[3];
|
||||
|
||||
prev = z2;
|
||||
for (i = 0; i < 13; i++) {
|
||||
int j;
|
||||
limb_t *a = xs[steps[i].a];
|
||||
for (j = steps[i].n; j > 0; j--) {
|
||||
sqr(a, prev);
|
||||
prev = a;
|
||||
}
|
||||
mul1(a, xs[steps[i].c]);
|
||||
}
|
||||
|
||||
// Here prev = z3
|
||||
// x2 /= z2
|
||||
mul(out_limbs, x2, z3, NLIMBS);
|
||||
ret = (int) canon(out_limbs);
|
||||
if (!clamp) ret = 0;
|
||||
for (i = 0; i < NLIMBS; i++) {
|
||||
uint32_t n = out_limbs[i];
|
||||
out[i * 4] = (uint8_t) (n & 0xff);
|
||||
out[i * 4 + 1] = (uint8_t) ((n >> 8) & 0xff);
|
||||
out[i * 4 + 2] = (uint8_t) ((n >> 16) & 0xff);
|
||||
out[i * 4 + 3] = (uint8_t) ((n >> 24) & 0xff);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,13 +0,0 @@
|
||||
#ifndef TLS_X15519_H
|
||||
#define TLS_X15519_H
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
#define X25519_BYTES 32
|
||||
extern const uint8_t X25519_BASE_POINT[X25519_BYTES];
|
||||
|
||||
int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES],
|
||||
const uint8_t x1[X25519_BYTES], int clamp);
|
||||
|
||||
|
||||
#endif /* TLS_X15519_H */
|
||||
+6
-16
@@ -78,19 +78,10 @@ LDFLAGS += -L$(WOLFSSL)/lib -lwolfssl
|
||||
endif
|
||||
|
||||
ifeq "$(SSL)" "BUILTIN"
|
||||
DEFS += -DMG_TLS=MG_TLS_BUILTIN
|
||||
# Small TLS records: several records per TCP segment, tests record handling
|
||||
DEFS += -DMG_TLS=MG_TLS_BUILTIN -DMG_TLS_RECORD_SIZE=256
|
||||
endif
|
||||
|
||||
tls_multirec/server: FORCE
|
||||
ifneq "$(SSL)" ""
|
||||
ifeq "$(MULTIREC)" ""
|
||||
$(MAKE) -C tls_multirec CC=gcc
|
||||
endif
|
||||
endif
|
||||
true
|
||||
|
||||
FORCE:
|
||||
true
|
||||
|
||||
|
||||
all:
|
||||
@@ -109,13 +100,13 @@ mongoose.c: Makefile $(wildcard ../src/*.c) $(wildcard ../src/drivers/*.c)
|
||||
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
||||
|
||||
mongoose.h: $(HDRS) Makefile
|
||||
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/os_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/lfs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/modbus.h src/json.h src/jwt.h src/rpc.h src/dash.h src/ota.h src/health.h src/mdash.h src/flash.h src/wifi.h src/l2.h src/net_builtin.h src/bsd.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/os_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/lfs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_aes128.h src/tls_p256.h src/tls_p384.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/modbus.h src/json.h src/jwt.h src/rpc.h src/dash.h src/ota.h src/health.h src/mdash.h src/flash.h src/wifi.h src/l2.h src/net_builtin.h src/bsd.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||
|
||||
# Check that all external (exported) symbols have "mg_" prefix
|
||||
mg_prefix: mongoose.c mongoose.h
|
||||
$(CC) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T ' | grep -v 'mg_' ; test $$? = 1
|
||||
|
||||
test: Makefile mongoose.h $(SRCS) tls_multirec/server
|
||||
test: Makefile mongoose.h $(SRCS)
|
||||
$(CC) $(SRCS) $(CFLAGS) $(LDFLAGS) -o unit_test
|
||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./unit_test
|
||||
|
||||
@@ -265,7 +256,6 @@ packed_fs.c: Makefile data/ssi.h fuzz.c data/a.txt data/range.txt data/ca.pem ce
|
||||
|
||||
clean: clean_tutorials clean_tutorials_embedded
|
||||
rm -rf $(PROG) *.exe *.o *.dSYM *_test ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* packed_fs.c pack
|
||||
$(MAKE) -C tls_multirec $@
|
||||
$(MAKE) -C ../resources/I-CUBE-Mongoose $@
|
||||
#find tutorials -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C
|
||||
|
||||
@@ -289,7 +279,7 @@ atcmd_test: atcmd_test.c mongoose.c mongoose.h Makefile
|
||||
$(CC) atcmd_test.c $(CFLAGS) $(LDFLAGS) -o $@
|
||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||
|
||||
mip_tap_test: mip_x_test.c mip_tap_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_multirec/server
|
||||
mip_tap_test: mip_x_test.c mip_tap_test.c mongoose.c mongoose.h packed_fs.c Makefile
|
||||
$(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
|
||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||
|
||||
@@ -302,7 +292,7 @@ port_tap_bridge: port_tap_bridge.c
|
||||
cc port_tap_bridge.c -o $@
|
||||
|
||||
# requires port_tap_bridge to be running
|
||||
mip_port_test: mip_x_test.c mip_port_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_multirec/server
|
||||
mip_port_test: mip_x_test.c mip_port_test.c mongoose.c mongoose.h packed_fs.c Makefile
|
||||
$(CC) mip_port_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
|
||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||
|
||||
|
||||
+3
-5
@@ -480,8 +480,7 @@ static void test_http_server(struct mg_mgr *mgr) {
|
||||
}
|
||||
|
||||
static void test_tls(struct mg_mgr *mgr) {
|
||||
#if MG_TLS
|
||||
char *url;
|
||||
#if MG_TLS && 0 // TODO(cpq): restore multi-record TLS test
|
||||
char buf[FETCH_BUF_SIZE]; // make sure it can hold Makefile
|
||||
mg_mem_files = mg_packed_files; // Use generated packed filesystem
|
||||
struct mg_str data = mg_unpacked("/Makefile");
|
||||
@@ -496,7 +495,8 @@ static void test_tls(struct mg_mgr *mgr) {
|
||||
// - Fire patched server, test multiple TLS records per TCP segment handling
|
||||
// skip other TLS stacks to avoid "bad client hello", we are 1.3 only
|
||||
if (access("tls_multirec/server", X_OK) == 0) {
|
||||
url = mg_mprintf("https://%s:8443", host_ip);
|
||||
char url[256];
|
||||
mg_snrintf(url, sizeof(url), "https://%s:8443", host_ip);
|
||||
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
|
||||
sleep(1);
|
||||
// fetch() needs to loop enough times in order to process all TLS records;
|
||||
@@ -504,7 +504,6 @@ static void test_tls(struct mg_mgr *mgr) {
|
||||
ASSERT(fetch(mgr, buf, url, "GET /thefile HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
|
||||
ASSERT(system("killall tls_multirec/server") == 0);
|
||||
free(url);
|
||||
} else {
|
||||
printf("SKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT\n");
|
||||
}
|
||||
@@ -512,7 +511,6 @@ static void test_tls(struct mg_mgr *mgr) {
|
||||
printf("SKIPPED TLS MULTIPLE RECORDS TEST, not a known TLS 1.3 stack\n");
|
||||
(void) cmpbody("", "");
|
||||
(void) mgr;
|
||||
(void) url; // these three: NO SIMPLE TLS TEST
|
||||
(void) buf;
|
||||
(void) data;
|
||||
#endif
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
CFLAGS = -g -I. # This is a known version, no need to check
|
||||
CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -DMG_ENABLE_IPV6=1
|
||||
CFLAGS_EXTRA ?= -DMG_TLS=MG_TLS_BUILTIN
|
||||
|
||||
server: main.c patched_mongoose.c mongoose.h Makefile
|
||||
$(CC) main.c patched_mongoose.c $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
|
||||
|
||||
clean:
|
||||
rm -rf server *.exe *.o *.dSYM
|
||||
@@ -1,184 +0,0 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include <signal.h>
|
||||
#include "mongoose.h"
|
||||
|
||||
static int s_debug_level = MG_LL_INFO;
|
||||
static const char *s_root_dir = ".";
|
||||
static const char *s_addr1 = "http://0.0.0.0:8000";
|
||||
static const char *s_addr2 = "https://0.0.0.0:8443";
|
||||
static const char *s_enable_hexdump = "no";
|
||||
static const char *s_ssi_pattern = "#.html";
|
||||
static const char *s_upload_dir = NULL; // File uploads disabled by default
|
||||
|
||||
// Self signed certificates, see
|
||||
// https://github.com/cesanta/mongoose/blob/master/test/certs/generate.sh
|
||||
#ifdef TLS_TWOWAY
|
||||
static const char *s_tls_ca =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n"
|
||||
"b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n"
|
||||
"TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n"
|
||||
"fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n"
|
||||
"epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n"
|
||||
"us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
#endif
|
||||
static const char *s_tls_cert =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIBMTCB2aADAgECAgkAluqkgeuV/zUwCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwI\n"
|
||||
"TW9uZ29vc2UwHhcNMjQwNTA3MTQzNzM2WhcNMzQwNTA1MTQzNzM2WjARMQ8wDQYD\n"
|
||||
"VQQDDAZzZXJ2ZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASo3oEiG+BuTt5y\n"
|
||||
"ZRyfwNr0C+SP+4M0RG2pYkb2v+ivbpfi72NHkmXiF/kbHXtgmSrn/PeTqiA8M+mg\n"
|
||||
"BhYjDX+zoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAw\n"
|
||||
"RAIgTXW9MITQSwzqbNTxUUdt9DcB+8pPUTbWZpiXcA26GMYCIBiYw+DSFMLHmkHF\n"
|
||||
"+5U3NXW3gVCLN9ntD5DAx8LTG8sB\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
static const char *s_tls_key =
|
||||
"-----BEGIN EC PRIVATE KEY-----\n"
|
||||
"MHcCAQEEIAVdo8UAScxG7jiuNY2UZESNX/KPH8qJ0u0gOMMsAzYWoAoGCCqGSM49\n"
|
||||
"AwEHoUQDQgAEqN6BIhvgbk7ecmUcn8Da9Avkj/uDNERtqWJG9r/or26X4u9jR5Jl\n"
|
||||
"4hf5Gx17YJkq5/z3k6ogPDPpoAYWIw1/sw==\n"
|
||||
"-----END EC PRIVATE KEY-----\n";
|
||||
|
||||
// Handle interrupts, like Ctrl-C
|
||||
static int s_signo;
|
||||
static void signal_handler(int signo) {
|
||||
s_signo = signo;
|
||||
}
|
||||
|
||||
// Event handler for the listening connection.
|
||||
// Simply serve static files from `s_root_dir`
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_ACCEPT && c->fn_data != NULL) {
|
||||
struct mg_tls_opts opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
#ifdef TLS_TWOWAY
|
||||
opts.ca = mg_str(s_tls_ca);
|
||||
#endif
|
||||
opts.cert = mg_str(s_tls_cert);
|
||||
opts.key = mg_str(s_tls_key);
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
|
||||
if (mg_match(hm->uri, mg_str("/upload"), NULL)) {
|
||||
// Serve file upload
|
||||
if (s_upload_dir == NULL) {
|
||||
mg_http_reply(c, 403, "", "Denied: file upload directory not set\n");
|
||||
} else {
|
||||
struct mg_http_part part;
|
||||
size_t pos = 0, total_bytes = 0, num_files = 0;
|
||||
while ((pos = mg_http_next_multipart(hm->body, pos, &part)) > 0) {
|
||||
char path[MG_PATH_MAX];
|
||||
MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
|
||||
part.name.len, part.name.buf, part.filename.len,
|
||||
part.filename.buf, part.body.len));
|
||||
mg_snprintf(path, sizeof(path), "%s/%.*s", s_upload_dir,
|
||||
part.filename.len, part.filename.buf);
|
||||
if (mg_path_is_sane(mg_str(path))) {
|
||||
mg_file_write(&mg_fs_posix, path, part.body.buf, part.body.len);
|
||||
total_bytes += part.body.len;
|
||||
num_files++;
|
||||
} else {
|
||||
MG_ERROR(("Rejecting dangerous path %s", path));
|
||||
}
|
||||
}
|
||||
mg_http_reply(c, 200, "", "Uploaded %lu files, %lu bytes\n", num_files,
|
||||
total_bytes);
|
||||
}
|
||||
} else {
|
||||
// Serve web root directory
|
||||
struct mg_http_serve_opts opts = {0};
|
||||
opts.root_dir = s_root_dir;
|
||||
opts.ssi_pattern = s_ssi_pattern;
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
|
||||
// Log request
|
||||
MG_INFO(("%.*s %.*s %lu -> %.*s %lu", hm->method.len, hm->method.buf,
|
||||
hm->uri.len, hm->uri.buf, hm->body.len, 3, c->send.buf + 9,
|
||||
c->send.len));
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(const char *prog) {
|
||||
fprintf(stderr,
|
||||
"Mongoose v.%s\n"
|
||||
"Usage: %s OPTIONS\n"
|
||||
" -H yes|no - enable traffic hexdump, default: '%s'\n"
|
||||
" -S PAT - SSI filename pattern, default: '%s'\n"
|
||||
" -d DIR - directory to serve, default: '%s'\n"
|
||||
" -l ADDR - listening address, default: '%s'\n"
|
||||
" -u DIR - file upload directory, default: unset\n"
|
||||
" -v LEVEL - debug level, from 0 to 4, default: %d\n",
|
||||
MG_VERSION, prog, s_enable_hexdump, s_ssi_pattern, s_root_dir,
|
||||
s_addr1, s_debug_level);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char path[MG_PATH_MAX] = ".";
|
||||
struct mg_mgr mgr;
|
||||
struct mg_connection *c;
|
||||
int i;
|
||||
|
||||
// Parse command-line flags
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-d") == 0) {
|
||||
s_root_dir = argv[++i];
|
||||
} else if (strcmp(argv[i], "-H") == 0) {
|
||||
s_enable_hexdump = argv[++i];
|
||||
} else if (strcmp(argv[i], "-S") == 0) {
|
||||
s_ssi_pattern = argv[++i];
|
||||
} else if (strcmp(argv[i], "-l") == 0) {
|
||||
s_addr1 = argv[++i];
|
||||
} else if (strcmp(argv[i], "-l2") == 0) {
|
||||
s_addr2 = argv[++i];
|
||||
} else if (strcmp(argv[i], "-u") == 0) {
|
||||
s_upload_dir = argv[++i];
|
||||
} else if (strcmp(argv[i], "-v") == 0) {
|
||||
s_debug_level = atoi(argv[++i]);
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Root directory must not contain double dots. Make it absolute
|
||||
// Do the conversion only if the root dir spec does not contain overrides
|
||||
if (strchr(s_root_dir, ',') == NULL) {
|
||||
realpath(s_root_dir, path);
|
||||
s_root_dir = path;
|
||||
}
|
||||
|
||||
// Initialise stuff
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
mg_log_set(s_debug_level);
|
||||
mg_mgr_init(&mgr);
|
||||
if ((c = mg_http_listen(&mgr, s_addr1, cb, NULL)) == NULL) {
|
||||
MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
|
||||
s_addr1));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ((c = mg_http_listen(&mgr, s_addr2, cb, (void *) 1)) == NULL) {
|
||||
MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
|
||||
s_addr2));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;
|
||||
|
||||
// Start infinite event loop
|
||||
MG_INFO(("Mongoose version : v%s", MG_VERSION));
|
||||
MG_INFO(("HTTP listener : %s", s_addr1));
|
||||
MG_INFO(("HTTPS listener : %s", s_addr2));
|
||||
MG_INFO(("Web root : [%s]", s_root_dir));
|
||||
MG_INFO(("Upload dir : [%s]", s_upload_dir ? s_upload_dir : "unset"));
|
||||
while (s_signo == 0) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
MG_INFO(("Exiting on signal %d", s_signo));
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1 +0,0 @@
|
||||
../Makefile
|
||||
@@ -1,22 +0,0 @@
|
||||
diff --git a/mongoose.c b/mongoose.c
|
||||
index 44539e81..b3f1c83a 100644
|
||||
--- a/mongoose.c
|
||||
+++ b/mongoose.c
|
||||
@@ -11300,9 +11300,16 @@ void mg_tls_free(struct mg_connection *c) {
|
||||
long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
long n = MG_IO_WAIT;
|
||||
+ size_t maxsize = 256, encrypted = 0;
|
||||
if (len > MG_IO_SIZE) len = MG_IO_SIZE;
|
||||
if (len > 16384) len = 16384;
|
||||
- mg_tls_encrypt(c, (const uint8_t *) buf, len, MG_TLS_APP_DATA);
|
||||
+ while (encrypted < len) {
|
||||
+ const uint8_t *chunk = (const uint8_t *) buf + encrypted;
|
||||
+ size_t chunksize = len - encrypted;
|
||||
+ if (chunksize > maxsize) chunksize = maxsize;
|
||||
+ mg_tls_encrypt(c, chunk, chunksize, MG_TLS_APP_DATA);
|
||||
+ encrypted += chunksize;
|
||||
+ }
|
||||
while (tls->send.len > 0 &&
|
||||
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
|
||||
mg_iobuf_del(&tls->send, 0, (size_t) n);
|
||||
+43
-40
@@ -925,6 +925,10 @@ static void fcb(struct mg_connection *c, int ev, void *ev_data) {
|
||||
}
|
||||
}
|
||||
|
||||
// Max number of mg_mgr_poll() calls fetch() waits for a response. Large
|
||||
// transfers over builtin TLS with small records (MG_TLS_RECORD_SIZE) need more
|
||||
static int s_fetch_polls = 100;
|
||||
|
||||
static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
||||
const char *fmt, ...) {
|
||||
struct fetch_data fd = {buf, 0, 0};
|
||||
@@ -953,7 +957,7 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
||||
mg_vprintf(c, fmt, &ap);
|
||||
va_end(ap);
|
||||
buf[0] = '\0';
|
||||
for (i = 0; i < 100 && buf[0] == '\0'; i++) mg_mgr_poll(mgr, 1);
|
||||
for (i = 0; i < s_fetch_polls && buf[0] == '\0'; i++) mg_mgr_poll(mgr, 1);
|
||||
if (!fd.closed) c->is_closing = 1;
|
||||
mg_mgr_poll(mgr, 1);
|
||||
return fd.code;
|
||||
@@ -1522,7 +1526,6 @@ static void test_http_404(void) {
|
||||
}
|
||||
|
||||
static void test_tls(void) {
|
||||
// return;
|
||||
#if MG_TLS
|
||||
struct mg_mgr mgr;
|
||||
struct mg_connection *c;
|
||||
@@ -1545,6 +1548,7 @@ static void test_tls(void) {
|
||||
// POST a large file, several MSS but less than max TLS record length
|
||||
// make sure we drain TLS buffers and read all, #2619
|
||||
ASSERT(data.len > 3100 && data.len < 16384); // pick another file on failure
|
||||
s_fetch_polls = 5000; // Many small TLS records, one is decrypted per poll
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"POST /body HTTP/1.0\n"
|
||||
"Content-Length: %lu\n\n"
|
||||
@@ -1561,29 +1565,7 @@ static void test_tls(void) {
|
||||
"%s",
|
||||
bd.len, bd.buf) == 200);
|
||||
ASSERT(cmpbody(buf, bd.buf) == 0);
|
||||
#if MG_TLS == MG_TLS_BUILTIN && defined(__linux__) && \
|
||||
MG_ENABLE_CHACHA20 // skip for non-CHACHA tests
|
||||
// fire patched server, test multiple TLS records per TCP segment handling
|
||||
// skip other TLS stacks to avoid "bad client hello", we are 1.3 only
|
||||
if (access("tls_multirec/server", X_OK) == 0) {
|
||||
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
|
||||
sleep(1);
|
||||
// fetch() needs to loop enough times in order to process all TLS records;
|
||||
// otherwise it will end with 200 and shorter file contents
|
||||
ASSERT(fetch(&mgr, buf, "https://localhost:8443",
|
||||
"GET /thefile HTTP/1.0\n\n") == 200);
|
||||
data = mg_unpacked("/Makefile");
|
||||
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
|
||||
ASSERT(system("killall tls_multirec/server") == 0);
|
||||
} else {
|
||||
printf("\nSKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT\n");
|
||||
}
|
||||
#else
|
||||
printf(
|
||||
"\n Skipping multiple TLS records per TCP segment handling test, server "
|
||||
"is 1.3 only; re-enable when other stacks can be easily configured for "
|
||||
"1.3\n");
|
||||
#endif
|
||||
s_fetch_polls = 100;
|
||||
|
||||
// Repeat the simplest test with two-way authentication
|
||||
opts.ca = mg_unpacked("/certs/ca.crt"); // configure the server for two-way
|
||||
@@ -3394,7 +3376,7 @@ static void test_http_chunked_case(mg_event_handler_t s, mg_event_handler_t c,
|
||||
struct mg_mgr mgr;
|
||||
uint32_t i, crc = 0, expected_crc = mg_crc32(0, expected, strlen(expected));
|
||||
struct mg_connection *conn;
|
||||
static uint16_t port = 32344; // To prevent bind errors on Windows
|
||||
static uint16_t port = 32344; // To prevent bind errors on Windows
|
||||
mg_snprintf(url, sizeof(url), "http://127.0.0.1:%d", port++);
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, url, s, NULL);
|
||||
@@ -4424,18 +4406,39 @@ static void test_split(void) {
|
||||
ASSERT(mg_strcmp(b, mg_str("")) == 0);
|
||||
}
|
||||
|
||||
static void test_x25519(void) {
|
||||
// RFC 6979 A.2.5: P-256, SHA-256, message "sample"
|
||||
static void test_p256(void) {
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
uint8_t key[X25519_BYTES];
|
||||
uint8_t buf[X25519_BYTES];
|
||||
char tmp[100];
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(key); i++) key[i] = (uint8_t) i;
|
||||
for (i = 0; i < sizeof(buf); i++) buf[i] = 0;
|
||||
mg_tls_x25519(buf, key, X25519_BASE_POINT, 1);
|
||||
mg_snprintf(tmp, sizeof(tmp), "%M", mg_print_hex, sizeof(buf), buf);
|
||||
MG_INFO(("%s", tmp));
|
||||
ASSERT(mg_strcmp(mg_str("8f40c5adb6"), mg_str_n(tmp, 10)) == 0);
|
||||
static const uint8_t x[32] = {
|
||||
0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21,
|
||||
0x57, 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8,
|
||||
0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21};
|
||||
static const uint8_t ux[8] = {0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31};
|
||||
static const uint8_t uy[8] = {0x79, 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99};
|
||||
static const uint8_t rs[64] = {
|
||||
0xef, 0xd4, 0x8b, 0x2a, 0xac, 0xb6, 0xa8, 0xfd, 0x11, 0x40, 0xdd, 0x9c,
|
||||
0xd4, 0x5e, 0x81, 0xd6, 0x9d, 0x2c, 0x87, 0x7b, 0x56, 0xaa, 0xf9, 0x91,
|
||||
0xc3, 0x4d, 0x0e, 0xa8, 0x4e, 0xaf, 0x37, 0x16, 0xf7, 0xcb, 0x1c, 0x94,
|
||||
0x2d, 0x65, 0x7c, 0x41, 0xd4, 0x36, 0xc7, 0xa1, 0xb6, 0xe2, 0x9f, 0x65,
|
||||
0xf3, 0xe9, 0x00, 0xdb, 0xb9, 0xaf, 0xf4, 0x06, 0x4d, 0xc4, 0xab, 0x2f,
|
||||
0x84, 0x3a, 0xcd, 0xa8};
|
||||
uint8_t pub[64], hash[32], sig[64], prv2[32], pub2[64], sec1[32], sec2[32];
|
||||
mg_sha256(hash, (uint8_t *) "sample", 6);
|
||||
ASSERT(mg_p256_compute_public_key(x, pub) == 1);
|
||||
ASSERT(memcmp(pub, ux, sizeof(ux)) == 0);
|
||||
ASSERT(memcmp(pub + 32, uy, sizeof(uy)) == 0);
|
||||
ASSERT(mg_p256_sign(x, hash, sizeof(hash), sig) == 1);
|
||||
ASSERT(memcmp(sig, rs, sizeof(rs)) == 0);
|
||||
ASSERT(mg_p256_verify(pub, hash, sizeof(hash), sig) == 1);
|
||||
sig[10] ^= 1;
|
||||
ASSERT(mg_p256_verify(pub, hash, sizeof(hash), sig) == 0);
|
||||
// ECDH: both sides compute the same secret
|
||||
ASSERT(mg_p256_make_key(pub2, prv2) == 1);
|
||||
ASSERT(mg_p256_shared_secret(pub2, x, sec1) == 1);
|
||||
ASSERT(mg_p256_shared_secret(pub, prv2, sec2) == 1);
|
||||
ASSERT(memcmp(sec1, sec2, sizeof(sec1)) == 0);
|
||||
pub2[63] ^= 1; // Not on the curve anymore
|
||||
ASSERT(mg_p256_shared_secret(pub2, x, sec1) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4658,8 +4661,8 @@ static void test_jwt(void) {
|
||||
opts.kid = mg_str("ec-key-1");
|
||||
opts.private_key = key;
|
||||
opts.public_key = pub;
|
||||
ASSERT(mg_uecc_parse_private_key(mg_str(key_pem), key, sizeof(key)) == 32);
|
||||
ASSERT(mg_uecc_compute_public_key(key, pub, mg_uecc_secp256r1()) == 1);
|
||||
ASSERT(mg_p256_parse_private_key(mg_str(key_pem), key, sizeof(key)) == 32);
|
||||
ASSERT(mg_p256_compute_public_key(key, pub) == 1);
|
||||
n = mg_jwt_sign_es256(&opts, jwt, sizeof(jwt));
|
||||
ASSERT(n > 0 && n + 1 < sizeof(jwt));
|
||||
jwt[n] = '\0';
|
||||
@@ -4681,7 +4684,7 @@ static void test_crypto(void) {
|
||||
test_sha1();
|
||||
test_sha256();
|
||||
test_sha384();
|
||||
test_x25519();
|
||||
test_p256();
|
||||
test_rsa();
|
||||
test_jwt();
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ static size_t verify_es256(struct mg_str token, char *claims, size_t len) {
|
||||
struct mg_jwt_opts opts = {.public_key = pub};
|
||||
// This keeps the example self-contained. A real verifier would usually keep
|
||||
// only the issuer public key, selected by kid, not the signing private key.
|
||||
if (mg_uecc_parse_private_key(mg_str(s_ec_private_key), key, sizeof(key)) !=
|
||||
if (mg_p256_parse_private_key(mg_str(s_ec_private_key), key, sizeof(key)) !=
|
||||
32 ||
|
||||
mg_uecc_compute_public_key(key, pub, mg_uecc_secp256r1()) != 1) {
|
||||
mg_p256_compute_public_key(key, pub) != 1) {
|
||||
return 0;
|
||||
}
|
||||
return mg_jwt_verify_es256(token, &opts, claims, len);
|
||||
@@ -65,10 +65,9 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||
.private_key = key};
|
||||
size_t keysz, n;
|
||||
keysz =
|
||||
mg_uecc_parse_private_key(mg_str(s_ec_private_key), key, sizeof(key));
|
||||
mg_p256_parse_private_key(mg_str(s_ec_private_key), key, sizeof(key));
|
||||
// ES256 uses a raw 64-byte r || s signature. mg_jwt_sign_es256() signs it
|
||||
// deterministically; applications can also hash the signing input and
|
||||
// call mg_uecc_sign() directly if they need random-nonce ECDSA.
|
||||
// deterministically (RFC 6979), see mg_p256_sign()
|
||||
mg_snprintf(claims, CLAIMS_LEN, "{%m:%m,%m:%m}", MG_ESC("sub"),
|
||||
MG_ESC("admin"), MG_ESC("scope"), MG_ESC("dash:read"));
|
||||
opts.claims = mg_str(claims);
|
||||
|
||||
@@ -37,8 +37,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -70,6 +97,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_ENABLE_DRIVER_NETC 1
|
||||
#define MG_OTA MG_OTA_RT1180
|
||||
|
||||
@@ -61,8 +61,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -97,6 +124,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_ENABLE_DRIVER_MCXE 1
|
||||
|
||||
@@ -69,8 +69,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -105,6 +132,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
#define MG_OTA MG_OTA_MCXN
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
|
||||
@@ -37,8 +37,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -33,8 +33,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -64,6 +91,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
#define MG_OTA MG_OTA_RT1060
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
|
||||
@@ -37,8 +37,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -70,6 +97,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_ENABLE_DRIVER_IMXRT11 1
|
||||
|
||||
@@ -7,8 +7,8 @@ include(pico_sdk_import.cmake)
|
||||
project(firmware)
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(firmware main.c wifi.c mongoose/mongoose.c)
|
||||
target_include_directories(firmware PRIVATE mongoose)
|
||||
add_executable(firmware main.c wifi.c ../../../mongoose.c)
|
||||
target_include_directories(firmware PRIVATE ../../.. ./)
|
||||
|
||||
target_link_libraries(firmware hardware_pio pico_stdlib pico_rand hardware_flash pico_bootrom)
|
||||
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
|
||||
|
||||
@@ -14,13 +14,11 @@ endif
|
||||
|
||||
all build example: build/firmware.uf2
|
||||
|
||||
build/firmware.uf2: pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h
|
||||
build/firmware.uf2: pico_sdk_import.cmake
|
||||
|
||||
pico_sdk_import.cmake: $(SDK_PATH)
|
||||
cp $(SDK_PATH)/external/$@ $@
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../$(notdir $@) $@
|
||||
|
||||
build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile
|
||||
$(MKBUILD)
|
||||
@@ -30,7 +28,7 @@ flash: build/firmware.uf2
|
||||
picotool load $< -f
|
||||
|
||||
clean:
|
||||
$(RM) build pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h $(SDK_PATH)
|
||||
$(RM) build pico_sdk_import.cmake $(SDK_PATH)
|
||||
|
||||
$(SDK_PATH):
|
||||
git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@
|
||||
|
||||
File renamed without changes.
@@ -7,8 +7,8 @@ include(pico_sdk_import.cmake)
|
||||
project(firmware)
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(firmware main.c driver_rp2040_rmii.c mongoose/mongoose.c)
|
||||
target_include_directories(firmware PRIVATE . mongoose)
|
||||
add_executable(firmware main.c driver_rp2040_rmii.c ../../../mongoose.c)
|
||||
target_include_directories(firmware PRIVATE ../../.. ./)
|
||||
|
||||
target_link_libraries(firmware hardware_pio hardware_dma pico_stdlib pico_rand)
|
||||
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
|
||||
|
||||
@@ -14,13 +14,11 @@ endif
|
||||
|
||||
all build example: build/firmware.uf2
|
||||
|
||||
build/firmware.uf2: pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h
|
||||
build/firmware.uf2: pico_sdk_import.cmake
|
||||
|
||||
pico_sdk_import.cmake: $(SDK_PATH)
|
||||
cp $(SDK_PATH)/external/$@ $@
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../$(notdir $@) $@
|
||||
|
||||
build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile
|
||||
$(MKBUILD)
|
||||
@@ -30,7 +28,7 @@ flash: build/firmware.uf2
|
||||
picotool load $< -f
|
||||
|
||||
clean:
|
||||
$(RM) build pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h $(SDK_PATH)
|
||||
$(RM) build pico_sdk_import.cmake $(SDK_PATH)
|
||||
|
||||
$(SDK_PATH):
|
||||
git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@
|
||||
|
||||
File renamed without changes.
@@ -7,12 +7,13 @@ pico_sdk_init()
|
||||
add_executable(firmware
|
||||
main.c
|
||||
usb_descriptors.c
|
||||
mongoose.c
|
||||
../../../mongoose.c
|
||||
net.c
|
||||
pico-sdk/lib/tinyusb/lib/networking/rndis_reports.c)
|
||||
|
||||
target_include_directories(firmware PUBLIC
|
||||
.
|
||||
../../..
|
||||
./
|
||||
pico-sdk/lib/tinyusb/lib/networking)
|
||||
|
||||
target_link_libraries(firmware pico_stdlib pico_rand hardware_spi tinyusb_device)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../../mongoose.c
|
||||
@@ -1 +0,0 @@
|
||||
../../../mongoose.h
|
||||
@@ -11,12 +11,12 @@ add_executable(firmware
|
||||
main.c
|
||||
msc_disk.c
|
||||
usb_descriptors.c
|
||||
mongoose/mongoose.c
|
||||
../../../mongoose.c
|
||||
pico-sdk/lib/tinyusb/lib/networking/rndis_reports.c)
|
||||
|
||||
target_include_directories(firmware PRIVATE
|
||||
.
|
||||
mongoose
|
||||
../../..
|
||||
./
|
||||
pico-sdk/lib/tinyusb/lib/networking)
|
||||
|
||||
target_link_libraries(firmware pico_stdlib pico_rand hardware_spi tinyusb_device)
|
||||
|
||||
@@ -14,13 +14,11 @@ endif
|
||||
|
||||
all build example: build/firmware.uf2
|
||||
|
||||
build/firmware.uf2: pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h
|
||||
build/firmware.uf2: pico_sdk_import.cmake
|
||||
|
||||
pico_sdk_import.cmake: $(SDK_PATH)
|
||||
cp $(SDK_PATH)/external/$@ $@
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../$(notdir $@) $@
|
||||
|
||||
build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile
|
||||
$(MKBUILD)
|
||||
@@ -30,7 +28,7 @@ flash: build/firmware.uf2
|
||||
picotool load $< -f
|
||||
|
||||
clean:
|
||||
$(RM) build pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h $(SDK_PATH)
|
||||
$(RM) build pico_sdk_import.cmake $(SDK_PATH)
|
||||
|
||||
$(SDK_PATH):
|
||||
git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@
|
||||
|
||||
File renamed without changes.
@@ -1,14 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
# If you will set board type here, do it BEFORE including the SDK
|
||||
set(PICO_BOARD pico_w)
|
||||
set(PICO_BOARD pico2_w)
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(firmware)
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(firmware main.c wifi.c mongoose/mongoose.c)
|
||||
target_include_directories(firmware PRIVATE mongoose)
|
||||
add_executable(firmware main.c wifi.c ../../../mongoose.c)
|
||||
target_include_directories(firmware PRIVATE ../../.. ./)
|
||||
|
||||
target_link_libraries(firmware pico_stdlib hardware_spi pico_rand pico_cyw43_driver pico_cyw43_arch_none hardware_flash pico_bootrom)
|
||||
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
|
||||
|
||||
@@ -14,13 +14,11 @@ endif
|
||||
|
||||
all build example: build/firmware.uf2
|
||||
|
||||
build/firmware.uf2: pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h
|
||||
build/firmware.uf2: pico_sdk_import.cmake
|
||||
|
||||
pico_sdk_import.cmake: $(SDK_PATH)
|
||||
cp $(SDK_PATH)/external/$@ $@
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../$(notdir $@) $@
|
||||
|
||||
build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile
|
||||
$(MKBUILD)
|
||||
@@ -30,7 +28,7 @@ flash: build/firmware.uf2
|
||||
picotool load $< -f
|
||||
|
||||
clean:
|
||||
$(RM) build pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h $(SDK_PATH)
|
||||
$(RM) build pico_sdk_import.cmake $(SDK_PATH)
|
||||
|
||||
$(SDK_PATH):
|
||||
git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@
|
||||
|
||||
@@ -11,8 +11,35 @@ static void blink_task(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
uint64_t tick = to_ms_since_boot(get_absolute_time());
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
@@ -34,6 +61,7 @@ static void run_mongoose(void) {
|
||||
mg_log_set_fn(log_fn, NULL);
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 1);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// Build options: https://mongoose.ws/docs/getting-started/build-options/
|
||||
#define MG_ARCH MG_ARCH_PICOSDK
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
#define MG_OTA MG_OTA_PICOSDK
|
||||
#define MG_IO_SIZE 2048
|
||||
|
||||
@@ -7,8 +7,8 @@ include(pico_sdk_import.cmake)
|
||||
project(firmware)
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(firmware main.c mongoose/mongoose.c)
|
||||
target_include_directories(firmware PRIVATE mongoose)
|
||||
add_executable(firmware main.c ../../../mongoose.c)
|
||||
target_include_directories(firmware PRIVATE ../../.. ./)
|
||||
|
||||
target_link_libraries(firmware pico_stdlib hardware_spi pico_rand hardware_flash pico_bootrom)
|
||||
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
|
||||
|
||||
@@ -14,13 +14,11 @@ endif
|
||||
|
||||
all build example: build/firmware.uf2
|
||||
|
||||
build/firmware.uf2: pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h
|
||||
build/firmware.uf2: pico_sdk_import.cmake
|
||||
|
||||
pico_sdk_import.cmake: $(SDK_PATH)
|
||||
cp $(SDK_PATH)/external/$@ $@
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../$(notdir $@) $@
|
||||
|
||||
build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile
|
||||
$(MKBUILD)
|
||||
@@ -30,7 +28,7 @@ flash: build/firmware.uf2
|
||||
picotool load $< -f
|
||||
|
||||
clean:
|
||||
$(RM) build pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h $(SDK_PATH)
|
||||
$(RM) build pico_sdk_import.cmake $(SDK_PATH)
|
||||
|
||||
$(SDK_PATH):
|
||||
git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@
|
||||
|
||||
@@ -54,8 +54,35 @@ static void blink_task(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
uint64_t tick = to_ms_since_boot(get_absolute_time());
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
@@ -86,6 +113,7 @@ static void run_mongoose(void) {
|
||||
MG_INFO(("Driver: W5500, MAC: %M", mg_print_mac, mif.mac));
|
||||
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 1);
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
|
||||
// Build options: https://mongoose.ws/docs/getting-started/build-options/
|
||||
#define MG_ARCH MG_ARCH_PICOSDK
|
||||
#define MG_TLS MG_TLS_BUILTIN
|
||||
#define MG_OTA MG_OTA_PICOSDK
|
||||
#define MG_IO_SIZE 2048
|
||||
|
||||
@@ -6,8 +6,8 @@ include(pico_sdk_import.cmake)
|
||||
project(firmware)
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(firmware main.c mongoose/mongoose.c)
|
||||
target_include_directories(firmware PRIVATE mongoose)
|
||||
add_executable(firmware main.c ../../../mongoose.c)
|
||||
target_include_directories(firmware PRIVATE ../../.. ./)
|
||||
|
||||
target_link_libraries(firmware pico_stdlib hardware_pio pico_rand hardware_flash pico_bootrom)
|
||||
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
|
||||
|
||||
@@ -14,13 +14,11 @@ endif
|
||||
|
||||
all build example: build/firmware.uf2
|
||||
|
||||
build/firmware.uf2: pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h
|
||||
build/firmware.uf2: pico_sdk_import.cmake
|
||||
|
||||
pico_sdk_import.cmake: $(SDK_PATH)
|
||||
cp $(SDK_PATH)/external/$@ $@
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../$(notdir $@) $@
|
||||
|
||||
build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile
|
||||
$(MKBUILD)
|
||||
@@ -30,7 +28,7 @@ flash: build/firmware.uf2
|
||||
picotool load $< -f
|
||||
|
||||
clean:
|
||||
$(RM) build pico_sdk_import.cmake mongoose/mongoose.c mongoose/mongoose.h $(SDK_PATH)
|
||||
$(RM) build pico_sdk_import.cmake $(SDK_PATH)
|
||||
|
||||
$(SDK_PATH):
|
||||
git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@
|
||||
|
||||
@@ -167,8 +167,35 @@ static void blink_task(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
uint64_t tick = to_ms_since_boot(get_absolute_time());
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
@@ -191,6 +218,7 @@ static void run_mongoose(void) {
|
||||
mg_log_set_fn(log_fn, NULL);
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 1);
|
||||
|
||||
File renamed without changes.
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -4,7 +4,7 @@ MEMORY {
|
||||
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 640k
|
||||
}
|
||||
_estack = ORIGIN(sram) + LENGTH(sram); /* End of RAM. stack points here */
|
||||
_sstack = _estack - 4098;
|
||||
_sstack = _estack - 16384; /* Stack limit, MSPLIM. TLS needs > 4 KB */
|
||||
|
||||
SECTIONS {
|
||||
.vectors : { KEEP(*(.isr_vector)) } > flash
|
||||
|
||||
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -80,6 +107,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -38,3 +38,5 @@
|
||||
mac[4] = MGUID[1] & 255; \
|
||||
mac[5] = MGUID[2] & 255; \
|
||||
} while (0)
|
||||
|
||||
#define MG_ENABLE_HEALTH 1
|
||||
@@ -1,23 +1,21 @@
|
||||
# Copyright (c) 2026 Cesanta Software Limited
|
||||
# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/
|
||||
|
||||
MGDIR = ../../../..
|
||||
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
|
||||
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
|
||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include -Imongoose
|
||||
CFLAGS += -I. -I$(MGDIR) -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include
|
||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
|
||||
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||
|
||||
SOURCES = main.c hal.c echo.c
|
||||
SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h723xx.s
|
||||
SOURCES += mongoose/mongoose.c
|
||||
SOURCES += $(MGDIR)/mongoose.c
|
||||
|
||||
all build example: firmware.bin
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../../mongoose.[ch] mongoose/
|
||||
|
||||
firmware.elf: cmsis_core cmsis_h7 hal.h link.ld Makefile $(SOURCES) mongoose/mongoose.h
|
||||
firmware.elf: cmsis_core cmsis_h7 hal.h link.ld Makefile $(SOURCES) $(MGDIR)/mongoose.h mongoose_config.h
|
||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
|
||||
|
||||
firmware.bin: firmware.elf
|
||||
@@ -35,4 +33,4 @@ cmsis_h7:
|
||||
git clone -q -c advice.detachedHead=false --depth 1 -b v1.10.6 https://github.com/STMicroelectronics/cmsis_device_h7 $@
|
||||
|
||||
clean:
|
||||
rm -rf firmware.* cmsis_* mongoose/mongoose.*
|
||||
rm -rf firmware.* cmsis_*
|
||||
@@ -114,3 +114,21 @@ void echo_poll(void) {
|
||||
p = &c->next;
|
||||
}
|
||||
}
|
||||
|
||||
// On desktop, build with -DMAIN flag to include main().
|
||||
// On embedded system, run this code in your main() function
|
||||
#ifdef MAIN
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
echo_init(1234);
|
||||
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 1);
|
||||
echo_poll();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
../../../../mongoose.c
|
||||
@@ -1 +0,0 @@
|
||||
../../../../mongoose.h
|
||||
File renamed without changes.
@@ -1,16 +1,17 @@
|
||||
# Copyright (c) 2026 Cesanta Software Limited
|
||||
# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/
|
||||
|
||||
MGDIR = ../../../..
|
||||
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
|
||||
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
|
||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include -Imongoose
|
||||
CFLAGS += -I. -I$(MGDIR) -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include
|
||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
|
||||
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections
|
||||
|
||||
SOURCES = main.c hal.c
|
||||
SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h723xx.s
|
||||
SOURCES += mongoose/mongoose.c
|
||||
SOURCES += $(MGDIR)/mongoose.c
|
||||
|
||||
# FreeRTOS. H7 has a Cortex-M7 r1p0 core, FreeRTOS recommends using CM4F port for non-r0p1 CM7 micros
|
||||
SOURCES += FreeRTOS-Kernel/tasks.c FreeRTOS-Kernel/list.c FreeRTOS-Kernel/queue.c
|
||||
@@ -21,10 +22,7 @@ CFLAGS += -IFreeRTOS-Kernel/portable/GCC/ARM_CM4F -Wno-conversion
|
||||
|
||||
all build example: firmware.bin
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../../mongoose.[ch] mongoose/
|
||||
|
||||
firmware.elf: cmsis_core cmsis_h7 FreeRTOS-Kernel hal.h link.ld Makefile $(SOURCES) mongoose/mongoose.h
|
||||
firmware.elf: cmsis_core cmsis_h7 FreeRTOS-Kernel hal.h link.ld Makefile $(SOURCES) $(MGDIR)/mongoose.h mongoose_config.h
|
||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
|
||||
|
||||
firmware.bin: firmware.elf
|
||||
@@ -49,7 +47,7 @@ FreeRTOS-Kernel:
|
||||
git clone --depth 1 -b V11.3.0 https://github.com/FreeRTOS/FreeRTOS-Kernel $@
|
||||
|
||||
clean:
|
||||
rm -rf firmware.* cmsis_* mongoose/mongoose.* FreeRTOS-Kernel
|
||||
rm -rf firmware.* cmsis_* FreeRTOS-Kernel
|
||||
|
||||
|
||||
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
|
||||
|
||||
File renamed without changes.
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -4,7 +4,7 @@ MEMORY {
|
||||
sram (rwx) : ORIGIN = 0x34000000, LENGTH = 2048K
|
||||
}
|
||||
_estack = ORIGIN(sram) + LENGTH(sram);
|
||||
_sstack = _estack - 4096;
|
||||
_sstack = _estack - 16384; /* Stack limit, MSPLIM. TLS needs > 4 KB */
|
||||
|
||||
SECTIONS {
|
||||
.vectors : { KEEP(*(.isr_vector)) } > flash
|
||||
|
||||
@@ -36,8 +36,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -32,8 +32,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -66,6 +93,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -74,6 +101,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
@@ -40,8 +40,35 @@ bool mg_random(void *buf, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
|
||||
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
|
||||
#define TLS_CERT \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
|
||||
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
|
||||
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
|
||||
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
|
||||
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
|
||||
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
|
||||
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
|
||||
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
|
||||
"BCjX++LI\n" \
|
||||
"-----END CERTIFICATE-----\n"
|
||||
|
||||
#define TLS_KEY \
|
||||
"-----BEGIN EC PRIVATE KEY-----\n" \
|
||||
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
|
||||
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
|
||||
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
|
||||
"-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
|
||||
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
|
||||
.key = mg_str(TLS_KEY)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
|
||||
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
|
||||
@@ -73,6 +100,7 @@ int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
Reference in new issue
Block a user