Drop x25519, use p256 only

This commit is contained in:
cpq committed 2026-10-15 13:36:24 +01:00
1 parent b68da1548b
commit 37f3ed5ba4
87 files changed
+12928 -32874

No files matched your search

+4 -4
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+231 -664
View File
@@ -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
+4 -3
View File
@@ -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
View File
@@ -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",
+3 -3
View File
@@ -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
+18
View File
@@ -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
View File
@@ -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;
+4 -30
View File
@@ -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
View File
@@ -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) {
+1 -1
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+181
View File
@@ -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
View File
@@ -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)
+40
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
-659
View File
@@ -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
-262
View File
@@ -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
-13
View File
@@ -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
View File
@@ -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
View File
@@ -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
-9
View File
@@ -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
-184
View File
@@ -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
View File
@@ -1 +0,0 @@
../Makefile
-22
View File
@@ -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
View File
@@ -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();
}
+4 -5
View File
@@ -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);
+29 -1
View File
@@ -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
+29 -1
View File
@@ -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
+29 -1
View File
@@ -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
+29 -1
View File
@@ -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()));
+29 -1
View File
@@ -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
+29 -1
View File
@@ -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
+2 -2
View File
@@ -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.
+2 -4
View File
@@ -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 $@
+2 -2
View File
@@ -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.
+2 -4
View File
@@ -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 $@
@@ -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
+3 -3
View File
@@ -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)
+2 -4
View File
@@ -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 $@
+3 -3
View File
@@ -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.
+2 -4
View File
@@ -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 $@
+29 -1
View File
@@ -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
+2 -2
View File
@@ -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.
+2 -4
View File
@@ -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 $@
+29 -1
View File
@@ -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);
@@ -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
+2 -2
View File
@@ -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.
+2 -4
View File
@@ -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 $@
+29 -1
View File
@@ -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);
+29 -1
View File
@@ -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()));
+29 -1
View File
@@ -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()));
+29 -1
View File
@@ -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
+29 -1
View File
@@ -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
@@ -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/
+29 -1
View File
@@ -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()));
+29 -1
View File
@@ -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
+29 -1
View File
@@ -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()));
+29 -1
View File
@@ -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()));
+29 -1
View File
@@ -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()));
+29 -1
View File
@@ -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()));