mirror of https://github.com/arendst/Tasmota.git
Refactored TLS based on BearSSL - cleaned
This commit is contained in:
parent
09dcb93489
commit
006462f17e
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_H__
|
||||
#define BR_BEARSSL_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** \mainpage BearSSL API
|
||||
*
|
||||
* # API Layout
|
||||
*
|
||||
* The functions and structures defined by the BearSSL API are located
|
||||
* in various header files:
|
||||
*
|
||||
* | Header file | Elements |
|
||||
* | :-------------- | :------------------------------------------------ |
|
||||
* | bearssl_hash.h | Hash functions |
|
||||
* | bearssl_hmac.h | HMAC |
|
||||
* | bearssl_kdf.h | Key Derivation Functions |
|
||||
* | bearssl_rand.h | Pseudorandom byte generators |
|
||||
* | bearssl_prf.h | PRF implementations (for SSL/TLS) |
|
||||
* | bearssl_block.h | Symmetric encryption |
|
||||
* | bearssl_aead.h | AEAD algorithms (combined encryption + MAC) |
|
||||
* | bearssl_rsa.h | RSA encryption and signatures |
|
||||
* | bearssl_ec.h | Elliptic curves support (including ECDSA) |
|
||||
* | bearssl_ssl.h | SSL/TLS engine interface |
|
||||
* | bearssl_x509.h | X.509 certificate decoding and validation |
|
||||
* | bearssl_pem.h | Base64/PEM decoding support functions |
|
||||
*
|
||||
* Applications using BearSSL are supposed to simply include `bearssl.h`
|
||||
* as follows:
|
||||
*
|
||||
* #include <bearssl.h>
|
||||
*
|
||||
* The `bearssl.h` file itself includes all the other header files. It is
|
||||
* possible to include specific header files, but it has no practical
|
||||
* advantage for the application. The API is separated into separate
|
||||
* header files only for documentation convenience.
|
||||
*
|
||||
*
|
||||
* # Conventions
|
||||
*
|
||||
* ## MUST and SHALL
|
||||
*
|
||||
* In all descriptions, the usual "MUST", "SHALL", "MAY",... terminology
|
||||
* is used. Failure to meet requirements expressed with a "MUST" or
|
||||
* "SHALL" implies undefined behaviour, which means that segmentation
|
||||
* faults, buffer overflows, and other similar adverse events, may occur.
|
||||
*
|
||||
* In general, BearSSL is not very forgiving of programming errors, and
|
||||
* does not include much failsafes or error reporting when the problem
|
||||
* does not arise from external transient conditions, and can be fixed
|
||||
* only in the application code. This is done so in order to make the
|
||||
* total code footprint lighter.
|
||||
*
|
||||
*
|
||||
* ## `NULL` values
|
||||
*
|
||||
* Function parameters with a pointer type shall not be `NULL` unless
|
||||
* explicitly authorised by the documentation. As an exception, when
|
||||
* the pointer aims at a sequence of bytes and is accompanied with
|
||||
* a length parameter, and the length is zero (meaning that there is
|
||||
* no byte at all to retrieve), then the pointer may be `NULL` even if
|
||||
* not explicitly allowed.
|
||||
*
|
||||
*
|
||||
* ## Memory Allocation
|
||||
*
|
||||
* BearSSL does not perform dynamic memory allocation. This implies that
|
||||
* for any functionality that requires a non-transient state, the caller
|
||||
* is responsible for allocating the relevant context structure. Such
|
||||
* allocation can be done in any appropriate area, including static data
|
||||
* segments, the heap, and the stack, provided that proper alignment is
|
||||
* respected. The header files define these context structures
|
||||
* (including size and contents), so the C compiler should handle
|
||||
* alignment automatically.
|
||||
*
|
||||
* Since there is no dynamic resource allocation, there is also nothing to
|
||||
* release. When the calling code is done with a BearSSL feature, it
|
||||
* may simple release the context structures it allocated itself, with
|
||||
* no "close function" to call. If the context structures were allocated
|
||||
* on the stack (as local variables), then even that release operation is
|
||||
* implicit.
|
||||
*
|
||||
*
|
||||
* ## Structure Contents
|
||||
*
|
||||
* Except when explicitly indicated, structure contents are opaque: they
|
||||
* are included in the header files so that calling code may know the
|
||||
* structure sizes and alignment requirements, but callers SHALL NOT
|
||||
* access individual fields directly. For fields that are supposed to
|
||||
* be read from or written to, the API defines accessor functions (the
|
||||
* simplest of these accessor functions are defined as `static inline`
|
||||
* functions, and the C compiler will optimise them away).
|
||||
*
|
||||
*
|
||||
* # API Usage
|
||||
*
|
||||
* BearSSL usage for running a SSL/TLS client or server is described
|
||||
* on the [BearSSL Web site](https://www.bearssl.org/api1.html). The
|
||||
* BearSSL source archive also comes with sample code.
|
||||
*/
|
||||
|
||||
#include "bearssl_hash.h"
|
||||
#include "bearssl_hmac.h"
|
||||
#include "bearssl_kdf.h"
|
||||
#include "bearssl_rand.h"
|
||||
#include "bearssl_prf.h"
|
||||
#include "bearssl_block.h"
|
||||
#include "bearssl_aead.h"
|
||||
#include "bearssl_rsa.h"
|
||||
#include "bearssl_ec.h"
|
||||
#include "bearssl_ssl.h"
|
||||
#include "bearssl_x509.h"
|
||||
#include "bearssl_pem.h"
|
||||
|
||||
/** \brief Type for a configuration option.
|
||||
*
|
||||
* A "configuration option" is a value that is selected when the BearSSL
|
||||
* library itself is compiled. Most options are boolean; their value is
|
||||
* then either 1 (option is enabled) or 0 (option is disabled). Some
|
||||
* values have other integer values. Option names correspond to macro
|
||||
* names. Some of the options can be explicitly set in the internal
|
||||
* `"config.h"` file.
|
||||
*/
|
||||
typedef struct {
|
||||
/** \brief Configurable option name. */
|
||||
const char *name;
|
||||
/** \brief Configurable option value. */
|
||||
long value;
|
||||
} br_config_option;
|
||||
|
||||
/** \brief Get configuration report.
|
||||
*
|
||||
* This function returns compiled configuration options, each as a
|
||||
* 'long' value. Names match internal macro names, in particular those
|
||||
* that can be set in the `"config.h"` inner file. For boolean options,
|
||||
* the numerical value is 1 if enabled, 0 if disabled. For maximum
|
||||
* key sizes, values are expressed in bits.
|
||||
*
|
||||
* The returned array is terminated by an entry whose `name` is `NULL`.
|
||||
*
|
||||
* \return the configuration report.
|
||||
*/
|
||||
const br_config_option *br_get_config(void);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,967 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_EC_H__
|
||||
#define BR_BEARSSL_EC_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_rand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_ec.h
|
||||
*
|
||||
* # Elliptic Curves
|
||||
*
|
||||
* This file documents the EC implementations provided with BearSSL, and
|
||||
* ECDSA.
|
||||
*
|
||||
* ## Elliptic Curve API
|
||||
*
|
||||
* Only "named curves" are supported. Each EC implementation supports
|
||||
* one or several named curves, identified by symbolic identifiers.
|
||||
* These identifiers are small integers, that correspond to the values
|
||||
* registered by the
|
||||
* [IANA](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8).
|
||||
*
|
||||
* Since all currently defined elliptic curve identifiers are in the 0..31
|
||||
* range, it is convenient to encode support of some curves in a 32-bit
|
||||
* word, such that bit x corresponds to curve of identifier x.
|
||||
*
|
||||
* An EC implementation is incarnated by a `br_ec_impl` instance, that
|
||||
* offers the following fields:
|
||||
*
|
||||
* - `supported_curves`
|
||||
*
|
||||
* A 32-bit word that documents the identifiers of the curves supported
|
||||
* by this implementation.
|
||||
*
|
||||
* - `generator()`
|
||||
*
|
||||
* Callback method that returns a pointer to the conventional generator
|
||||
* point for that curve.
|
||||
*
|
||||
* - `order()`
|
||||
*
|
||||
* Callback method that returns a pointer to the subgroup order for
|
||||
* that curve. That value uses unsigned big-endian encoding.
|
||||
*
|
||||
* - `xoff()`
|
||||
*
|
||||
* Callback method that returns the offset and length of the X
|
||||
* coordinate in an encoded point.
|
||||
*
|
||||
* - `mul()`
|
||||
*
|
||||
* Multiply a curve point with an integer.
|
||||
*
|
||||
* - `mulgen()`
|
||||
*
|
||||
* Multiply the curve generator with an integer. This may be faster
|
||||
* than the generic `mul()`.
|
||||
*
|
||||
* - `muladd()`
|
||||
*
|
||||
* Multiply two curve points by two integers, and return the sum of
|
||||
* the two products.
|
||||
*
|
||||
* All curve points are represented in uncompressed format. The `mul()`
|
||||
* and `muladd()` methods take care to validate that the provided points
|
||||
* are really part of the relevant curve subgroup.
|
||||
*
|
||||
* For all point multiplication functions, the following holds:
|
||||
*
|
||||
* - Functions validate that the provided points are valid members
|
||||
* of the relevant curve subgroup. An error is reported if that is
|
||||
* not the case.
|
||||
*
|
||||
* - Processing is constant-time, even if the point operands are not
|
||||
* valid. This holds for both the source and resulting points, and
|
||||
* the multipliers (integers). Only the byte length of the provided
|
||||
* multiplier arrays (not their actual value length in bits) may
|
||||
* leak through timing-based side channels.
|
||||
*
|
||||
* - The multipliers (integers) MUST be lower than the subgroup order.
|
||||
* If this property is not met, then the result is indeterminate,
|
||||
* but an error value is not ncessearily returned.
|
||||
*
|
||||
*
|
||||
* ## ECDSA
|
||||
*
|
||||
* ECDSA signatures have two standard formats, called "raw" and "asn1".
|
||||
* Internally, such a signature is a pair of modular integers `(r,s)`.
|
||||
* The "raw" format is the concatenation of the unsigned big-endian
|
||||
* encodings of these two integers, possibly left-padded with zeros so
|
||||
* that they have the same encoded length. The "asn1" format is the
|
||||
* DER encoding of an ASN.1 structure that contains the two integer
|
||||
* values:
|
||||
*
|
||||
* ECDSASignature ::= SEQUENCE {
|
||||
* r INTEGER,
|
||||
* s INTEGER
|
||||
* }
|
||||
*
|
||||
* In general, in all of X.509 and SSL/TLS, the "asn1" format is used.
|
||||
* BearSSL offers ECDSA implementations for both formats; conversion
|
||||
* functions between the two formats are also provided. Conversion of a
|
||||
* "raw" format signature into "asn1" may enlarge a signature by no more
|
||||
* than 9 bytes for all supported curves; conversely, conversion of an
|
||||
* "asn1" signature to "raw" may expand the signature but the "raw"
|
||||
* length will never be more than twice the length of the "asn1" length
|
||||
* (and usually it will be shorter).
|
||||
*
|
||||
* Note that for a given signature, the "raw" format is not fully
|
||||
* deterministic, in that it does not enforce a minimal common length.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Standard curve ID. These ID are equal to the assigned numerical
|
||||
* identifiers assigned to these curves for TLS:
|
||||
* http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
|
||||
*/
|
||||
|
||||
/** \brief Identifier for named curve sect163k1. */
|
||||
#define BR_EC_sect163k1 1
|
||||
|
||||
/** \brief Identifier for named curve sect163r1. */
|
||||
#define BR_EC_sect163r1 2
|
||||
|
||||
/** \brief Identifier for named curve sect163r2. */
|
||||
#define BR_EC_sect163r2 3
|
||||
|
||||
/** \brief Identifier for named curve sect193r1. */
|
||||
#define BR_EC_sect193r1 4
|
||||
|
||||
/** \brief Identifier for named curve sect193r2. */
|
||||
#define BR_EC_sect193r2 5
|
||||
|
||||
/** \brief Identifier for named curve sect233k1. */
|
||||
#define BR_EC_sect233k1 6
|
||||
|
||||
/** \brief Identifier for named curve sect233r1. */
|
||||
#define BR_EC_sect233r1 7
|
||||
|
||||
/** \brief Identifier for named curve sect239k1. */
|
||||
#define BR_EC_sect239k1 8
|
||||
|
||||
/** \brief Identifier for named curve sect283k1. */
|
||||
#define BR_EC_sect283k1 9
|
||||
|
||||
/** \brief Identifier for named curve sect283r1. */
|
||||
#define BR_EC_sect283r1 10
|
||||
|
||||
/** \brief Identifier for named curve sect409k1. */
|
||||
#define BR_EC_sect409k1 11
|
||||
|
||||
/** \brief Identifier for named curve sect409r1. */
|
||||
#define BR_EC_sect409r1 12
|
||||
|
||||
/** \brief Identifier for named curve sect571k1. */
|
||||
#define BR_EC_sect571k1 13
|
||||
|
||||
/** \brief Identifier for named curve sect571r1. */
|
||||
#define BR_EC_sect571r1 14
|
||||
|
||||
/** \brief Identifier for named curve secp160k1. */
|
||||
#define BR_EC_secp160k1 15
|
||||
|
||||
/** \brief Identifier for named curve secp160r1. */
|
||||
#define BR_EC_secp160r1 16
|
||||
|
||||
/** \brief Identifier for named curve secp160r2. */
|
||||
#define BR_EC_secp160r2 17
|
||||
|
||||
/** \brief Identifier for named curve secp192k1. */
|
||||
#define BR_EC_secp192k1 18
|
||||
|
||||
/** \brief Identifier for named curve secp192r1. */
|
||||
#define BR_EC_secp192r1 19
|
||||
|
||||
/** \brief Identifier for named curve secp224k1. */
|
||||
#define BR_EC_secp224k1 20
|
||||
|
||||
/** \brief Identifier for named curve secp224r1. */
|
||||
#define BR_EC_secp224r1 21
|
||||
|
||||
/** \brief Identifier for named curve secp256k1. */
|
||||
#define BR_EC_secp256k1 22
|
||||
|
||||
/** \brief Identifier for named curve secp256r1. */
|
||||
#define BR_EC_secp256r1 23
|
||||
|
||||
/** \brief Identifier for named curve secp384r1. */
|
||||
#define BR_EC_secp384r1 24
|
||||
|
||||
/** \brief Identifier for named curve secp521r1. */
|
||||
#define BR_EC_secp521r1 25
|
||||
|
||||
/** \brief Identifier for named curve brainpoolP256r1. */
|
||||
#define BR_EC_brainpoolP256r1 26
|
||||
|
||||
/** \brief Identifier for named curve brainpoolP384r1. */
|
||||
#define BR_EC_brainpoolP384r1 27
|
||||
|
||||
/** \brief Identifier for named curve brainpoolP512r1. */
|
||||
#define BR_EC_brainpoolP512r1 28
|
||||
|
||||
/** \brief Identifier for named curve Curve25519. */
|
||||
#define BR_EC_curve25519 29
|
||||
|
||||
/** \brief Identifier for named curve Curve448. */
|
||||
#define BR_EC_curve448 30
|
||||
|
||||
/**
|
||||
* \brief Structure for an EC public key.
|
||||
*/
|
||||
typedef struct {
|
||||
/** \brief Identifier for the curve used by this key. */
|
||||
int curve;
|
||||
/** \brief Public curve point (uncompressed format). */
|
||||
unsigned char *q;
|
||||
/** \brief Length of public curve point (in bytes). */
|
||||
size_t qlen;
|
||||
} br_ec_public_key;
|
||||
|
||||
/**
|
||||
* \brief Structure for an EC private key.
|
||||
*
|
||||
* The private key is an integer modulo the curve subgroup order. The
|
||||
* encoding below tolerates extra leading zeros. In general, it is
|
||||
* recommended that the private key has the same length as the curve
|
||||
* subgroup order.
|
||||
*/
|
||||
typedef struct {
|
||||
/** \brief Identifier for the curve used by this key. */
|
||||
int curve;
|
||||
/** \brief Private key (integer, unsigned big-endian encoding). */
|
||||
unsigned char *x;
|
||||
/** \brief Private key length (in bytes). */
|
||||
size_t xlen;
|
||||
} br_ec_private_key;
|
||||
|
||||
/**
|
||||
* \brief Type for an EC implementation.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Supported curves.
|
||||
*
|
||||
* This word is a bitfield: bit `x` is set if the curve of ID `x`
|
||||
* is supported. E.g. an implementation supporting both NIST P-256
|
||||
* (secp256r1, ID 23) and NIST P-384 (secp384r1, ID 24) will have
|
||||
* value `0x01800000` in this field.
|
||||
*/
|
||||
uint32_t supported_curves;
|
||||
|
||||
/**
|
||||
* \brief Get the conventional generator.
|
||||
*
|
||||
* This function returns the conventional generator (encoded
|
||||
* curve point) for the specified curve. This function MUST NOT
|
||||
* be called if the curve is not supported.
|
||||
*
|
||||
* \param curve curve identifier.
|
||||
* \param len receiver for the encoded generator length (in bytes).
|
||||
* \return the encoded generator.
|
||||
*/
|
||||
const unsigned char *(*generator)(int curve, size_t *len);
|
||||
|
||||
/**
|
||||
* \brief Get the subgroup order.
|
||||
*
|
||||
* This function returns the order of the subgroup generated by
|
||||
* the conventional generator, for the specified curve. Unsigned
|
||||
* big-endian encoding is used. This function MUST NOT be called
|
||||
* if the curve is not supported.
|
||||
*
|
||||
* \param curve curve identifier.
|
||||
* \param len receiver for the encoded order length (in bytes).
|
||||
* \return the encoded order.
|
||||
*/
|
||||
const unsigned char *(*order)(int curve, size_t *len);
|
||||
|
||||
/**
|
||||
* \brief Get the offset and length for the X coordinate.
|
||||
*
|
||||
* This function returns the offset and length (in bytes) of
|
||||
* the X coordinate in an encoded non-zero point.
|
||||
*
|
||||
* \param curve curve identifier.
|
||||
* \param len receiver for the X coordinate length (in bytes).
|
||||
* \return the offset for the X coordinate (in bytes).
|
||||
*/
|
||||
size_t (*xoff)(int curve, size_t *len);
|
||||
|
||||
/**
|
||||
* \brief Multiply a curve point by an integer.
|
||||
*
|
||||
* The source point is provided in array `G` (of size `Glen` bytes);
|
||||
* the multiplication result is written over it. The multiplier
|
||||
* `x` (of size `xlen` bytes) uses unsigned big-endian encoding.
|
||||
*
|
||||
* Rules:
|
||||
*
|
||||
* - The specified curve MUST be supported.
|
||||
*
|
||||
* - The source point must be a valid point on the relevant curve
|
||||
* subgroup (and not the "point at infinity" either). If this is
|
||||
* not the case, then this function returns an error (0).
|
||||
*
|
||||
* - The multiplier integer MUST be non-zero and less than the
|
||||
* curve subgroup order. If this property does not hold, then
|
||||
* the result is indeterminate and an error code is not
|
||||
* guaranteed.
|
||||
*
|
||||
* Returned value is 1 on success, 0 on error. On error, the
|
||||
* contents of `G` are indeterminate.
|
||||
*
|
||||
* \param G point to multiply.
|
||||
* \param Glen length of the encoded point (in bytes).
|
||||
* \param x multiplier (unsigned big-endian).
|
||||
* \param xlen multiplier length (in bytes).
|
||||
* \param curve curve identifier.
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t (*mul)(unsigned char *G, size_t Glen,
|
||||
const unsigned char *x, size_t xlen, int curve);
|
||||
|
||||
/**
|
||||
* \brief Multiply the generator by an integer.
|
||||
*
|
||||
* The multiplier MUST be non-zero and less than the curve
|
||||
* subgroup order. Results are indeterminate if this property
|
||||
* does not hold.
|
||||
*
|
||||
* \param R output buffer for the point.
|
||||
* \param x multiplier (unsigned big-endian).
|
||||
* \param xlen multiplier length (in bytes).
|
||||
* \param curve curve identifier.
|
||||
* \return encoded result point length (in bytes).
|
||||
*/
|
||||
size_t (*mulgen)(unsigned char *R,
|
||||
const unsigned char *x, size_t xlen, int curve);
|
||||
|
||||
/**
|
||||
* \brief Multiply two points by two integers and add the
|
||||
* results.
|
||||
*
|
||||
* The point `x*A + y*B` is computed and written back in the `A`
|
||||
* array.
|
||||
*
|
||||
* Rules:
|
||||
*
|
||||
* - The specified curve MUST be supported.
|
||||
*
|
||||
* - The source points (`A` and `B`) must be valid points on
|
||||
* the relevant curve subgroup (and not the "point at
|
||||
* infinity" either). If this is not the case, then this
|
||||
* function returns an error (0).
|
||||
*
|
||||
* - If the `B` pointer is `NULL`, then the conventional
|
||||
* subgroup generator is used. With some implementations,
|
||||
* this may be faster than providing a pointer to the
|
||||
* generator.
|
||||
*
|
||||
* - The multiplier integers (`x` and `y`) MUST be non-zero
|
||||
* and less than the curve subgroup order. If either integer
|
||||
* is zero, then an error is reported, but if one of them is
|
||||
* not lower than the subgroup order, then the result is
|
||||
* indeterminate and an error code is not guaranteed.
|
||||
*
|
||||
* - If the final result is the point at infinity, then an
|
||||
* error is returned.
|
||||
*
|
||||
* Returned value is 1 on success, 0 on error. On error, the
|
||||
* contents of `A` are indeterminate.
|
||||
*
|
||||
* \param A first point to multiply.
|
||||
* \param B second point to multiply (`NULL` for the generator).
|
||||
* \param len common length of the encoded points (in bytes).
|
||||
* \param x multiplier for `A` (unsigned big-endian).
|
||||
* \param xlen length of multiplier for `A` (in bytes).
|
||||
* \param y multiplier for `A` (unsigned big-endian).
|
||||
* \param ylen length of multiplier for `A` (in bytes).
|
||||
* \param curve curve identifier.
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
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);
|
||||
} br_ec_impl;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i31".
|
||||
*
|
||||
* This implementation internally uses generic code for modular integers,
|
||||
* with a representation as sequences of 31-bit words. It supports secp256r1,
|
||||
* secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_prime_i31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i15".
|
||||
*
|
||||
* This implementation internally uses generic code for modular integers,
|
||||
* with a representation as sequences of 15-bit words. It supports secp256r1,
|
||||
* secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_prime_i15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m15" for P-256.
|
||||
*
|
||||
* This implementation uses specialised code for curve secp256r1 (also
|
||||
* known as NIST P-256), with optional Karatsuba decomposition, and fast
|
||||
* modular reduction thanks to the field modulus special format. Only
|
||||
* 32-bit multiplications are used (with 32-bit results, not 64-bit).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m31" for P-256.
|
||||
*
|
||||
* This implementation uses specialised code for curve secp256r1 (also
|
||||
* known as NIST P-256), relying on multiplications of 31-bit values
|
||||
* (MUL31).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m62" (specialised code) for P-256.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 64 bits, with a 128-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_p256_m62_get()` to dynamically obtain a pointer
|
||||
* to that implementation.
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m62;
|
||||
|
||||
/**
|
||||
* \brief Get the "m62" implementation of P-256, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_p256_m62_get(void);
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m64" (specialised code) for P-256.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 64 bits, with a 128-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_p256_m64_get()` to dynamically obtain a pointer
|
||||
* to that implementation.
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m64;
|
||||
|
||||
/**
|
||||
* \brief Get the "m64" implementation of P-256, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_p256_m64_get(void);
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i15" (generic code) for Curve25519.
|
||||
*
|
||||
* This implementation uses the generic code for modular integers (with
|
||||
* 15-bit words) to support Curve25519. Due to the specificities of the
|
||||
* curve definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_i15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i31" (generic code) for Curve25519.
|
||||
*
|
||||
* This implementation uses the generic code for modular integers (with
|
||||
* 31-bit words) to support Curve25519. Due to the specificities of the
|
||||
* curve definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_i31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m15" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 15 bits. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m31" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 31 bits. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m62" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 62 bits, with a 124-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_c25519_m62_get()` to dynamically obtain a pointer
|
||||
* to that implementation. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m62;
|
||||
|
||||
/**
|
||||
* \brief Get the "m62" implementation of Curve25519, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_c25519_m62_get(void);
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m64" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 64 bits, with a 128-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_c25519_m64_get()` to dynamically obtain a pointer
|
||||
* to that implementation. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m64;
|
||||
|
||||
/**
|
||||
* \brief Get the "m64" implementation of Curve25519, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_c25519_m64_get(void);
|
||||
|
||||
/**
|
||||
* \brief Aggregate EC implementation "m15".
|
||||
*
|
||||
* This implementation is a wrapper for:
|
||||
*
|
||||
* - `br_ec_c25519_m15` for Curve25519
|
||||
* - `br_ec_p256_m15` for NIST P-256
|
||||
* - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512)
|
||||
*/
|
||||
extern const br_ec_impl br_ec_all_m15;
|
||||
|
||||
/**
|
||||
* \brief Aggregate EC implementation "m31".
|
||||
*
|
||||
* This implementation is a wrapper for:
|
||||
*
|
||||
* - `br_ec_c25519_m31` for Curve25519
|
||||
* - `br_ec_p256_m31` for NIST P-256
|
||||
* - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512)
|
||||
*/
|
||||
extern const br_ec_impl br_ec_all_m31;
|
||||
|
||||
/**
|
||||
* \brief Get the "default" EC implementation for the current system.
|
||||
*
|
||||
* This returns a pointer to the preferred implementation on the
|
||||
* current system.
|
||||
*
|
||||
* \return the default EC implementation.
|
||||
*/
|
||||
const br_ec_impl *br_ec_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Convert a signature from "raw" to "asn1".
|
||||
*
|
||||
* Conversion is done "in place" and the new length is returned.
|
||||
* Conversion may enlarge the signature, but by no more than 9 bytes at
|
||||
* most. On error, 0 is returned (error conditions include an odd raw
|
||||
* signature length, or an oversized integer).
|
||||
*
|
||||
* \param sig signature to convert.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return the new signature length, or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief Convert a signature from "asn1" to "raw".
|
||||
*
|
||||
* Conversion is done "in place" and the new length is returned.
|
||||
* Conversion may enlarge the signature, but the new signature length
|
||||
* will be less than twice the source length at most. On error, 0 is
|
||||
* returned (error conditions include an invalid ASN.1 structure or an
|
||||
* oversized integer).
|
||||
*
|
||||
* \param sig signature to convert.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return the new signature length, or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief Type for an ECDSA signer function.
|
||||
*
|
||||
* A pointer to the EC implementation is provided. The hash value is
|
||||
* assumed to have the length inferred from the designated hash function
|
||||
* class.
|
||||
*
|
||||
* Signature is written in the buffer pointed to by `sig`, and the length
|
||||
* (in bytes) is returned. On error, nothing is written in the buffer,
|
||||
* and 0 is returned. This function returns 0 if the specified curve is
|
||||
* not supported by the provided EC implementation.
|
||||
*
|
||||
* The signature format is either "raw" or "asn1", depending on the
|
||||
* implementation; maximum length is predictable from the implemented
|
||||
* curve:
|
||||
*
|
||||
* | curve | raw | asn1 |
|
||||
* | :--------- | --: | ---: |
|
||||
* | NIST P-256 | 64 | 72 |
|
||||
* | NIST P-384 | 96 | 104 |
|
||||
* | NIST P-521 | 132 | 139 |
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
typedef size_t (*br_ecdsa_sign)(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief Type for an ECDSA signature verification function.
|
||||
*
|
||||
* A pointer to the EC implementation is provided. The hashed value,
|
||||
* computed over the purportedly signed data, is also provided with
|
||||
* its length.
|
||||
*
|
||||
* The signature format is either "raw" or "asn1", depending on the
|
||||
* implementation.
|
||||
*
|
||||
* Returned value is 1 on success (valid signature), 0 on error. This
|
||||
* function returns 0 if the specified curve is not supported by the
|
||||
* provided EC implementation.
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
typedef uint32_t (*br_ecdsa_vrfy)(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i31" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i31_sign_asn1(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i31" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i31_sign_raw(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i31" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i31" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i15" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i15_sign_asn1(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i15" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i15_sign_raw(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i15" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i15" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (signer, asn1 format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature generation
|
||||
* ("asn1" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_sign br_ecdsa_sign_asn1_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (signer, raw format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature generation
|
||||
* ("raw" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_sign br_ecdsa_sign_raw_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (verifier, asn1 format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature verification
|
||||
* ("asn1" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_vrfy br_ecdsa_vrfy_asn1_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (verifier, raw format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature verification
|
||||
* ("raw" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_vrfy br_ecdsa_vrfy_raw_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Maximum size for EC private key element buffer.
|
||||
*
|
||||
* This is the largest number of bytes that `br_ec_keygen()` may need or
|
||||
* ever return.
|
||||
*/
|
||||
#define BR_EC_KBUF_PRIV_MAX_SIZE 72
|
||||
|
||||
/**
|
||||
* \brief Maximum size for EC public key element buffer.
|
||||
*
|
||||
* This is the largest number of bytes that `br_ec_compute_public()` may
|
||||
* need or ever return.
|
||||
*/
|
||||
#define BR_EC_KBUF_PUB_MAX_SIZE 145
|
||||
|
||||
/**
|
||||
* \brief Generate a new EC private key.
|
||||
*
|
||||
* If the specified `curve` is not supported by the elliptic curve
|
||||
* implementation (`impl`), then this function returns zero.
|
||||
*
|
||||
* The `sk` structure fields are set to the new private key data. In
|
||||
* particular, `sk.x` is made to point to the provided key buffer (`kbuf`),
|
||||
* in which the actual private key data is written. That buffer is assumed
|
||||
* to be large enough. The `BR_EC_KBUF_PRIV_MAX_SIZE` defines the maximum
|
||||
* size for all supported curves.
|
||||
*
|
||||
* The number of bytes used in `kbuf` is returned. If `kbuf` is `NULL`, then
|
||||
* the private key is not actually generated, and `sk` may also be `NULL`;
|
||||
* the minimum length for `kbuf` is still computed and returned.
|
||||
*
|
||||
* If `sk` is `NULL` but `kbuf` is not `NULL`, then the private key is
|
||||
* still generated and stored in `kbuf`.
|
||||
*
|
||||
* \param rng_ctx source PRNG context (already initialized).
|
||||
* \param impl the elliptic curve implementation.
|
||||
* \param sk the private key structure to fill, or `NULL`.
|
||||
* \param kbuf the key element buffer, or `NULL`.
|
||||
* \param curve the curve identifier.
|
||||
* \return the key data length (in bytes), or zero.
|
||||
*/
|
||||
size_t br_ec_keygen(const br_prng_class **rng_ctx,
|
||||
const br_ec_impl *impl, br_ec_private_key *sk,
|
||||
void *kbuf, int curve);
|
||||
|
||||
/**
|
||||
* \brief Compute EC public key from EC private key.
|
||||
*
|
||||
* This function uses the provided elliptic curve implementation (`impl`)
|
||||
* to compute the public key corresponding to the private key held in `sk`.
|
||||
* The public key point is written into `kbuf`, which is then linked from
|
||||
* the `*pk` structure. The size of the public key point, i.e. the number
|
||||
* of bytes used in `kbuf`, is returned.
|
||||
*
|
||||
* If `kbuf` is `NULL`, then the public key point is NOT computed, and
|
||||
* the public key structure `*pk` is unmodified (`pk` may be `NULL` in
|
||||
* that case). The size of the public key point is still returned.
|
||||
*
|
||||
* If `pk` is `NULL` but `kbuf` is not `NULL`, then the public key
|
||||
* point is computed and stored in `kbuf`, and its size is returned.
|
||||
*
|
||||
* If the curve used by the private key is not supported by the curve
|
||||
* implementation, then this function returns zero.
|
||||
*
|
||||
* The private key MUST be valid. An off-range private key value is not
|
||||
* necessarily detected, and leads to unpredictable results.
|
||||
*
|
||||
* \param impl the elliptic curve implementation.
|
||||
* \param pk the public key structure to fill (or `NULL`).
|
||||
* \param kbuf the public key point buffer (or `NULL`).
|
||||
* \param sk the source private key.
|
||||
* \return the public key point length (in bytes), or zero.
|
||||
*/
|
||||
size_t br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
|
||||
void *kbuf, const br_ec_private_key *sk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_HMAC_H__
|
||||
#define BR_BEARSSL_HMAC_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_hash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_hmac.h
|
||||
*
|
||||
* # HMAC
|
||||
*
|
||||
* HMAC is initialized with a key and an underlying hash function; it
|
||||
* then fills a "key context". That context contains the processed
|
||||
* key.
|
||||
*
|
||||
* With the key context, a HMAC context can be initialized to process
|
||||
* the input bytes and obtain the MAC output. The key context is not
|
||||
* modified during that process, and can be reused.
|
||||
*
|
||||
* IMPORTANT: HMAC shall be used only with functions that have the
|
||||
* following properties:
|
||||
*
|
||||
* - hash output size does not exceed 64 bytes;
|
||||
* - hash internal state size does not exceed 64 bytes;
|
||||
* - internal block length is a power of 2 between 16 and 256 bytes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief HMAC key context.
|
||||
*
|
||||
* The HMAC key context is initialised with a hash function implementation
|
||||
* and a secret key. Contents are opaque (callers should not access them
|
||||
* directly). The caller is responsible for allocating the context where
|
||||
* appropriate. Context initialisation and usage incurs no dynamic
|
||||
* allocation, so there is no release function.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
const br_hash_class *dig_vtable;
|
||||
unsigned char ksi[64], kso[64];
|
||||
#endif
|
||||
} br_hmac_key_context;
|
||||
|
||||
/**
|
||||
* \brief HMAC key context initialisation.
|
||||
*
|
||||
* Initialise the key context with the provided key, using the hash function
|
||||
* identified by `digest_vtable`. This supports arbitrary key lengths.
|
||||
*
|
||||
* \param kc HMAC key context to initialise.
|
||||
* \param digest_vtable pointer to the hash function implementation vtable.
|
||||
* \param key pointer to the HMAC secret key.
|
||||
* \param key_len HMAC secret key length (in bytes).
|
||||
*/
|
||||
void br_hmac_key_init(br_hmac_key_context *kc,
|
||||
const br_hash_class *digest_vtable, const void *key, size_t key_len);
|
||||
|
||||
/*
|
||||
* \brief Get the underlying hash function.
|
||||
*
|
||||
* This function returns a pointer to the implementation vtable of the
|
||||
* hash function used for this HMAC key context.
|
||||
*
|
||||
* \param kc HMAC key context.
|
||||
* \return the hash function implementation.
|
||||
*/
|
||||
static inline const br_hash_class *br_hmac_key_get_digest(
|
||||
const br_hmac_key_context *kc)
|
||||
{
|
||||
return kc->dig_vtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief HMAC computation context.
|
||||
*
|
||||
* The HMAC computation context maintains the state for a single HMAC
|
||||
* computation. It is modified as input bytes are injected. The context
|
||||
* is caller-allocated and has no release function since it does not
|
||||
* dynamically allocate external resources. Its contents are opaque.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
br_hash_compat_context dig;
|
||||
unsigned char kso[64];
|
||||
size_t out_len;
|
||||
#endif
|
||||
} br_hmac_context;
|
||||
|
||||
/**
|
||||
* \brief HMAC computation initialisation.
|
||||
*
|
||||
* Initialise a HMAC context with a key context. The key context is
|
||||
* unmodified. Relevant data from the key context is immediately copied;
|
||||
* the key context can thus be independently reused, modified or released
|
||||
* without impacting this HMAC computation.
|
||||
*
|
||||
* An explicit output length can be specified; the actual output length
|
||||
* will be the minimum of that value and the natural HMAC output length.
|
||||
* If `out_len` is 0, then the natural HMAC output length is selected. The
|
||||
* "natural output length" is the output length of the underlying hash
|
||||
* function.
|
||||
*
|
||||
* \param ctx HMAC context to initialise.
|
||||
* \param kc HMAC key context (already initialised with the key).
|
||||
* \param out_len HMAC output length (0 to select "natural length").
|
||||
*/
|
||||
void br_hmac_init(br_hmac_context *ctx,
|
||||
const br_hmac_key_context *kc, size_t out_len);
|
||||
|
||||
/**
|
||||
* \brief Get the HMAC output size.
|
||||
*
|
||||
* The HMAC output size is the number of bytes that will actually be
|
||||
* produced with `br_hmac_out()` with the provided context. This function
|
||||
* MUST NOT be called on a non-initialised HMAC computation context.
|
||||
* The returned value is the minimum of the HMAC natural length (output
|
||||
* size of the underlying hash function) and the `out_len` parameter which
|
||||
* was used with the last `br_hmac_init()` call on that context (if the
|
||||
* initialisation `out_len` parameter was 0, then this function will
|
||||
* return the HMAC natural length).
|
||||
*
|
||||
* \param ctx the (already initialised) HMAC computation context.
|
||||
* \return the HMAC actual output size.
|
||||
*/
|
||||
static inline size_t
|
||||
br_hmac_size(br_hmac_context *ctx)
|
||||
{
|
||||
return ctx->out_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Get the underlying hash function.
|
||||
*
|
||||
* This function returns a pointer to the implementation vtable of the
|
||||
* hash function used for this HMAC context.
|
||||
*
|
||||
* \param hc HMAC context.
|
||||
* \return the hash function implementation.
|
||||
*/
|
||||
static inline const br_hash_class *br_hmac_get_digest(
|
||||
const br_hmac_context *hc)
|
||||
{
|
||||
return hc->dig.vtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Inject some bytes in HMAC.
|
||||
*
|
||||
* The provided `len` bytes are injected as extra input in the HMAC
|
||||
* computation incarnated by the `ctx` HMAC context. It is acceptable
|
||||
* that `len` is zero, in which case `data` is ignored (and may be
|
||||
* `NULL`) and this function does nothing.
|
||||
*/
|
||||
void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Compute the HMAC output.
|
||||
*
|
||||
* The destination buffer MUST be large enough to accommodate the result;
|
||||
* its length is at most the "natural length" of HMAC (i.e. the output
|
||||
* length of the underlying hash function). The context is NOT modified;
|
||||
* further bytes may be processed. Thus, "partial HMAC" values can be
|
||||
* efficiently obtained.
|
||||
*
|
||||
* Returned value is the output length (in bytes).
|
||||
*
|
||||
* \param ctx HMAC computation context.
|
||||
* \param out destination buffer for the HMAC output.
|
||||
* \return the produced value length (in bytes).
|
||||
*/
|
||||
size_t br_hmac_out(const br_hmac_context *ctx, void *out);
|
||||
|
||||
/**
|
||||
* \brief Constant-time HMAC computation.
|
||||
*
|
||||
* This function compute the HMAC output in constant time. Some extra
|
||||
* input bytes are processed, then the output is computed. The extra
|
||||
* input consists in the `len` bytes pointed to by `data`. The `len`
|
||||
* parameter must lie between `min_len` and `max_len` (inclusive);
|
||||
* `max_len` bytes are actually read from `data`. Computing time (and
|
||||
* memory access pattern) will not depend upon the data byte contents or
|
||||
* the value of `len`.
|
||||
*
|
||||
* The output is written in the `out` buffer, that MUST be large enough
|
||||
* to receive it.
|
||||
*
|
||||
* The difference `max_len - min_len` MUST be less than 2<sup>30</sup>
|
||||
* (i.e. about one gigabyte).
|
||||
*
|
||||
* This function computes the output properly only if the underlying
|
||||
* hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256,
|
||||
* SHA-384 or SHA-512).
|
||||
*
|
||||
* The provided context is NOT modified.
|
||||
*
|
||||
* \param ctx the (already initialised) HMAC computation context.
|
||||
* \param data the extra input bytes.
|
||||
* \param len the extra input length (in bytes).
|
||||
* \param min_len minimum extra input length (in bytes).
|
||||
* \param max_len maximum extra input length (in bytes).
|
||||
* \param out destination buffer for the HMAC output.
|
||||
* \return the produced value length (in bytes).
|
||||
*/
|
||||
size_t br_hmac_outCT(const br_hmac_context *ctx,
|
||||
const void *data, size_t len, size_t min_len, size_t max_len,
|
||||
void *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_KDF_H__
|
||||
#define BR_BEARSSL_KDF_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_hash.h"
|
||||
#include "bearssl_hmac.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_kdf.h
|
||||
*
|
||||
* # Key Derivation Functions
|
||||
*
|
||||
* KDF are functions that takes a variable length input, and provide a
|
||||
* variable length output, meant to be used to derive subkeys from a
|
||||
* master key.
|
||||
*
|
||||
* ## HKDF
|
||||
*
|
||||
* HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869).
|
||||
* It is based on HMAC, itself using an underlying hash function. Any
|
||||
* hash function can be used, as long as it is compatible with the rules
|
||||
* for the HMAC implementation (i.e. output size is 64 bytes or less, hash
|
||||
* internal state size is 64 bytes or less, and the internal block length is
|
||||
* a power of 2 between 16 and 256 bytes). HKDF has two phases:
|
||||
*
|
||||
* - HKDF-Extract: the input data in ingested, along with a "salt" value.
|
||||
*
|
||||
* - HKDF-Expand: the output is produced, from the result of processing
|
||||
* the input and salt, and using an extra non-secret parameter called
|
||||
* "info".
|
||||
*
|
||||
* The "salt" and "info" strings are non-secret and can be empty. Their role
|
||||
* is normally to bind the input and output, respectively, to conventional
|
||||
* identifiers that qualifu them within the used protocol or application.
|
||||
*
|
||||
* The implementation defined in this file uses the following functions:
|
||||
*
|
||||
* - `br_hkdf_init()`: initialize an HKDF context, with a hash function,
|
||||
* and the salt. This starts the HKDF-Extract process.
|
||||
*
|
||||
* - `br_hkdf_inject()`: inject more input bytes. This function may be
|
||||
* called repeatedly if the input data is provided by chunks.
|
||||
*
|
||||
* - `br_hkdf_flip()`: end the HKDF-Extract process, and start the
|
||||
* HKDF-Expand process.
|
||||
*
|
||||
* - `br_hkdf_produce()`: get the next bytes of output. This function
|
||||
* may be called several times to obtain the full output by chunks.
|
||||
* For correct HKDF processing, the same "info" string must be
|
||||
* provided for each call.
|
||||
*
|
||||
* Note that the HKDF total output size (the number of bytes that
|
||||
* HKDF-Expand is willing to produce) is limited: if the hash output size
|
||||
* is _n_ bytes, then the maximum output size is _255*n_.
|
||||
*
|
||||
* ## SHAKE
|
||||
*
|
||||
* SHAKE is defined in
|
||||
* [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final)
|
||||
* under two versions: SHAKE128 and SHAKE256, offering an alleged
|
||||
* "security level" of 128 and 256 bits, respectively (SHAKE128 is
|
||||
* about 20 to 25% faster than SHAKE256). SHAKE internally relies on
|
||||
* the Keccak family of sponge functions, not on any externally provided
|
||||
* hash function. Contrary to HKDF, SHAKE does not have a concept of
|
||||
* either a "salt" or an "info" string. The API consists in four
|
||||
* functions:
|
||||
*
|
||||
* - `br_shake_init()`: initialize a SHAKE context for a given
|
||||
* security level.
|
||||
*
|
||||
* - `br_shake_inject()`: inject more input bytes. This function may be
|
||||
* called repeatedly if the input data is provided by chunks.
|
||||
*
|
||||
* - `br_shake_flip()`: end the data injection process, and start the
|
||||
* data production process.
|
||||
*
|
||||
* - `br_shake_produce()`: get the next bytes of output. This function
|
||||
* may be called several times to obtain the full output by chunks.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief HKDF context.
|
||||
*
|
||||
* The HKDF context is initialized with a hash function implementation
|
||||
* and a salt value. Contents are opaque (callers should not access them
|
||||
* directly). The caller is responsible for allocating the context where
|
||||
* appropriate. Context initialisation and usage incurs no dynamic
|
||||
* allocation, so there is no release function.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
union {
|
||||
br_hmac_context hmac_ctx;
|
||||
br_hmac_key_context prk_ctx;
|
||||
} u;
|
||||
unsigned char buf[64];
|
||||
size_t ptr;
|
||||
size_t dig_len;
|
||||
unsigned chunk_num;
|
||||
#endif
|
||||
} br_hkdf_context;
|
||||
|
||||
/**
|
||||
* \brief HKDF context initialization.
|
||||
*
|
||||
* The underlying hash function and salt value are provided. Arbitrary
|
||||
* salt lengths can be used.
|
||||
*
|
||||
* HKDF makes a difference between a salt of length zero, and an
|
||||
* absent salt (the latter being equivalent to a salt consisting of
|
||||
* bytes of value zero, of the same length as the hash function output).
|
||||
* If `salt_len` is zero, then this function assumes that the salt is
|
||||
* present but of length zero. To specify an _absent_ salt, use
|
||||
* `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored).
|
||||
*
|
||||
* \param hc HKDF context to initialise.
|
||||
* \param digest_vtable pointer to the hash function implementation vtable.
|
||||
* \param salt HKDF-Extract salt.
|
||||
* \param salt_len HKDF-Extract salt length (in bytes).
|
||||
*/
|
||||
void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
|
||||
const void *salt, size_t salt_len);
|
||||
|
||||
/**
|
||||
* \brief The special "absent salt" value for HKDF.
|
||||
*/
|
||||
#define BR_HKDF_NO_SALT (&br_hkdf_no_salt)
|
||||
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
extern const unsigned char br_hkdf_no_salt;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief HKDF input injection (HKDF-Extract).
|
||||
*
|
||||
* This function injects some more input bytes ("key material") into
|
||||
* HKDF. This function may be called several times, after `br_hkdf_init()`
|
||||
* but before `br_hkdf_flip()`.
|
||||
*
|
||||
* \param hc HKDF context.
|
||||
* \param ikm extra input bytes.
|
||||
* \param ikm_len number of extra input bytes.
|
||||
*/
|
||||
void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len);
|
||||
|
||||
/**
|
||||
* \brief HKDF switch to the HKDF-Expand phase.
|
||||
*
|
||||
* This call terminates the HKDF-Extract process (input injection), and
|
||||
* starts the HKDF-Expand process (output production).
|
||||
*
|
||||
* \param hc HKDF context.
|
||||
*/
|
||||
void br_hkdf_flip(br_hkdf_context *hc);
|
||||
|
||||
/**
|
||||
* \brief HKDF output production (HKDF-Expand).
|
||||
*
|
||||
* Produce more output bytes from the current state. This function may be
|
||||
* called several times, but only after `br_hkdf_flip()`.
|
||||
*
|
||||
* Returned value is the number of actually produced bytes. The total
|
||||
* output length is limited to 255 times the output length of the
|
||||
* underlying hash function.
|
||||
*
|
||||
* \param hc HKDF context.
|
||||
* \param info application specific information string.
|
||||
* \param info_len application specific information string length (in bytes).
|
||||
* \param out destination buffer for the HKDF output.
|
||||
* \param out_len the length of the requested output (in bytes).
|
||||
* \return the produced output length (in bytes).
|
||||
*/
|
||||
size_t br_hkdf_produce(br_hkdf_context *hc,
|
||||
const void *info, size_t info_len, void *out, size_t out_len);
|
||||
|
||||
/**
|
||||
* \brief SHAKE context.
|
||||
*
|
||||
* The HKDF context is initialized with a "security level". The internal
|
||||
* notion is called "capacity"; the capacity is twice the security level
|
||||
* (for instance, SHAKE128 has capacity 256).
|
||||
*
|
||||
* The caller is responsible for allocating the context where
|
||||
* appropriate. Context initialisation and usage incurs no dynamic
|
||||
* allocation, so there is no release function.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
unsigned char dbuf[200];
|
||||
size_t dptr;
|
||||
size_t rate;
|
||||
uint64_t A[25];
|
||||
#endif
|
||||
} br_shake_context;
|
||||
|
||||
/**
|
||||
* \brief SHAKE context initialization.
|
||||
*
|
||||
* The context is initialized for the provided "security level".
|
||||
* Internally, this sets the "capacity" to twice the security level;
|
||||
* thus, for SHAKE128, the `security_level` parameter should be 128,
|
||||
* which corresponds to a 256-bit capacity.
|
||||
*
|
||||
* Allowed security levels are all multiples of 32, from 32 to 768,
|
||||
* inclusive. Larger security levels imply lower performance; levels
|
||||
* beyond 256 bits don't make much sense. Standard levels are 128
|
||||
* and 256 bits (for SHAKE128 and SHAKE256, respectively).
|
||||
*
|
||||
* \param sc SHAKE context to initialise.
|
||||
* \param security_level security level (in bits).
|
||||
*/
|
||||
void br_shake_init(br_shake_context *sc, int security_level);
|
||||
|
||||
/**
|
||||
* \brief SHAKE input injection.
|
||||
*
|
||||
* This function injects some more input bytes ("key material") into
|
||||
* SHAKE. This function may be called several times, after `br_shake_init()`
|
||||
* but before `br_shake_flip()`.
|
||||
*
|
||||
* \param sc SHAKE context.
|
||||
* \param data extra input bytes.
|
||||
* \param len number of extra input bytes.
|
||||
*/
|
||||
void br_shake_inject(br_shake_context *sc, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief SHAKE switch to production phase.
|
||||
*
|
||||
* This call terminates the input injection process, and starts the
|
||||
* output production process.
|
||||
*
|
||||
* \param sc SHAKE context.
|
||||
*/
|
||||
void br_shake_flip(br_shake_context *hc);
|
||||
|
||||
/**
|
||||
* \brief SHAKE output production.
|
||||
*
|
||||
* Produce more output bytes from the current state. This function may be
|
||||
* called several times, but only after `br_shake_flip()`.
|
||||
*
|
||||
* There is no practical limit to the number of bytes that may be produced.
|
||||
*
|
||||
* \param sc SHAKE context.
|
||||
* \param out destination buffer for the SHAKE output.
|
||||
* \param len the length of the requested output (in bytes).
|
||||
*/
|
||||
void br_shake_produce(br_shake_context *sc, void *out, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_PEM_H__
|
||||
#define BR_BEARSSL_PEM_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_pem.h
|
||||
*
|
||||
* # PEM Support
|
||||
*
|
||||
* PEM is a traditional encoding layer use to store binary objects (in
|
||||
* particular X.509 certificates, and private keys) in text files. While
|
||||
* the acronym comes from an old, defunct standard ("Privacy Enhanced
|
||||
* Mail"), the format has been reused, with some variations, by many
|
||||
* systems, and is a _de facto_ standard, even though it is not, actually,
|
||||
* specified in all clarity anywhere.
|
||||
*
|
||||
* ## Format Details
|
||||
*
|
||||
* BearSSL contains a generic, streamed PEM decoder, which handles the
|
||||
* following format:
|
||||
*
|
||||
* - The input source (a sequence of bytes) is assumed to be the
|
||||
* encoding of a text file in an ASCII-compatible charset. This
|
||||
* includes ISO-8859-1, Windows-1252, and UTF-8 encodings. Each
|
||||
* line ends on a newline character (U+000A LINE FEED). The
|
||||
* U+000D CARRIAGE RETURN characters are ignored, so the code
|
||||
* accepts both Windows-style and Unix-style line endings.
|
||||
*
|
||||
* - Each object begins with a banner that occurs at the start of
|
||||
* a line; the first banner characters are "`-----BEGIN `" (five
|
||||
* dashes, the word "BEGIN", and a space). The banner matching is
|
||||
* not case-sensitive.
|
||||
*
|
||||
* - The _object name_ consists in the characters that follow the
|
||||
* banner start sequence, up to the end of the line, but without
|
||||
* trailing dashes (in "normal" PEM, there are five trailing
|
||||
* dashes, but this implementation is not picky about these dashes).
|
||||
* The BearSSL decoder normalises the name characters to uppercase
|
||||
* (for ASCII letters only) and accepts names up to 127 characters.
|
||||
*
|
||||
* - The object ends with a banner that again occurs at the start of
|
||||
* a line, and starts with "`-----END `" (again case-insensitive).
|
||||
*
|
||||
* - Between that start and end banner, only Base64 data shall occur.
|
||||
* Base64 converts each sequence of three bytes into four
|
||||
* characters; the four characters are ASCII letters, digits, "`+`"
|
||||
* or "`-`" signs, and one or two "`=`" signs may occur in the last
|
||||
* quartet. Whitespace is ignored (whitespace is any ASCII character
|
||||
* of code 32 or less, so control characters are whitespace) and
|
||||
* lines may have arbitrary length; the only restriction is that the
|
||||
* four characters of a quartet must appear on the same line (no
|
||||
* line break inside a quartet).
|
||||
*
|
||||
* - A single file may contain more than one PEM object. Bytes that
|
||||
* occur between objects are ignored.
|
||||
*
|
||||
*
|
||||
* ## PEM Decoder API
|
||||
*
|
||||
* The PEM decoder offers a state-machine API. The caller allocates a
|
||||
* decoder context, then injects source bytes. Source bytes are pushed
|
||||
* with `br_pem_decoder_push()`. The decoder stops accepting bytes when
|
||||
* it reaches an "event", which is either the start of an object, the
|
||||
* end of an object, or a decoding error within an object.
|
||||
*
|
||||
* The `br_pem_decoder_event()` function is used to obtain the current
|
||||
* event; it also clears it, thus allowing the decoder to accept more
|
||||
* bytes. When a object start event is raised, the decoder context
|
||||
* offers the found object name (normalised to ASCII uppercase).
|
||||
*
|
||||
* When an object is reached, the caller must set an appropriate callback
|
||||
* function, which will receive (by chunks) the decoded object data.
|
||||
*
|
||||
* Since the decoder context makes no dynamic allocation, it requires
|
||||
* no explicit deallocation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief PEM decoder context.
|
||||
*
|
||||
* Contents are opaque (they should not be accessed directly).
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
/* CPU for the T0 virtual machine. */
|
||||
struct {
|
||||
uint32_t *dp;
|
||||
uint32_t *rp;
|
||||
const unsigned char *ip;
|
||||
} cpu;
|
||||
uint32_t dp_stack[32];
|
||||
uint32_t rp_stack[32];
|
||||
int err;
|
||||
|
||||
const unsigned char *hbuf;
|
||||
size_t hlen;
|
||||
|
||||
void (*dest)(void *dest_ctx, const void *src, size_t len);
|
||||
void *dest_ctx;
|
||||
|
||||
unsigned char event;
|
||||
char name[128];
|
||||
unsigned char buf[255];
|
||||
size_t ptr;
|
||||
#endif
|
||||
} br_pem_decoder_context;
|
||||
|
||||
/**
|
||||
* \brief Initialise a PEM decoder structure.
|
||||
*
|
||||
* \param ctx decoder context to initialise.
|
||||
*/
|
||||
void br_pem_decoder_init(br_pem_decoder_context *ctx);
|
||||
|
||||
/**
|
||||
* \brief Push some bytes into the decoder.
|
||||
*
|
||||
* Returned value is the number of bytes actually consumed; this may be
|
||||
* less than the number of provided bytes if an event is raised. When an
|
||||
* event is raised, it must be read (with `br_pem_decoder_event()`);
|
||||
* until the event is read, this function will return 0.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \param data new data bytes.
|
||||
* \param len number of new data bytes.
|
||||
* \return the number of bytes actually received (may be less than `len`).
|
||||
*/
|
||||
size_t br_pem_decoder_push(br_pem_decoder_context *ctx,
|
||||
const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Set the receiver for decoded data.
|
||||
*
|
||||
* When an object is entered, the provided function (with opaque context
|
||||
* pointer) will be called repeatedly with successive chunks of decoded
|
||||
* data for that object. If `dest` is set to 0, then decoded data is
|
||||
* simply ignored. The receiver can be set at any time, but, in practice,
|
||||
* it should be called immediately after receiving a "start of object"
|
||||
* event.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \param dest callback for receiving decoded data.
|
||||
* \param dest_ctx opaque context pointer for the `dest` callback.
|
||||
*/
|
||||
static inline void
|
||||
br_pem_decoder_setdest(br_pem_decoder_context *ctx,
|
||||
void (*dest)(void *dest_ctx, const void *src, size_t len),
|
||||
void *dest_ctx)
|
||||
{
|
||||
ctx->dest = dest;
|
||||
ctx->dest_ctx = dest_ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the last event.
|
||||
*
|
||||
* If an event was raised, then this function returns the event value, and
|
||||
* also clears it, thereby allowing the decoder to proceed. If no event
|
||||
* was raised since the last call to `br_pem_decoder_event()`, then this
|
||||
* function returns 0.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \return the raised event, or 0.
|
||||
*/
|
||||
int br_pem_decoder_event(br_pem_decoder_context *ctx);
|
||||
|
||||
/**
|
||||
* \brief Event: start of object.
|
||||
*
|
||||
* This event is raised when the start of a new object has been detected.
|
||||
* The object name (normalised to uppercase) can be accessed with
|
||||
* `br_pem_decoder_name()`.
|
||||
*/
|
||||
#define BR_PEM_BEGIN_OBJ 1
|
||||
|
||||
/**
|
||||
* \brief Event: end of object.
|
||||
*
|
||||
* This event is raised when the end of the current object is reached
|
||||
* (normally, i.e. with no decoding error).
|
||||
*/
|
||||
#define BR_PEM_END_OBJ 2
|
||||
|
||||
/**
|
||||
* \brief Event: decoding error.
|
||||
*
|
||||
* This event is raised when decoding fails within an object.
|
||||
* This formally closes the current object and brings the decoder back
|
||||
* to the "out of any object" state. The offending line in the source
|
||||
* is consumed.
|
||||
*/
|
||||
#define BR_PEM_ERROR 3
|
||||
|
||||
/**
|
||||
* \brief Get the name of the encountered object.
|
||||
*
|
||||
* The encountered object name is defined only when the "start of object"
|
||||
* event is raised. That name is normalised to uppercase (for ASCII letters
|
||||
* only) and does not include trailing dashes.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \return the current object name.
|
||||
*/
|
||||
static inline const char *
|
||||
br_pem_decoder_name(br_pem_decoder_context *ctx)
|
||||
{
|
||||
return ctx->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Encode an object in PEM.
|
||||
*
|
||||
* This function encodes the provided binary object (`data`, of length `len`
|
||||
* bytes) into PEM. The `banner` text will be included in the header and
|
||||
* footer (e.g. use `"CERTIFICATE"` to get a `"BEGIN CERTIFICATE"` header).
|
||||
*
|
||||
* The length (in characters) of the PEM output is returned; that length
|
||||
* does NOT include the terminating zero, that this function nevertheless
|
||||
* adds. If using the returned value for allocation purposes, the allocated
|
||||
* buffer size MUST be at least one byte larger than the returned size.
|
||||
*
|
||||
* If `dest` is `NULL`, then the encoding does not happen; however, the
|
||||
* length of the encoded object is still computed and returned.
|
||||
*
|
||||
* The `data` pointer may be `NULL` only if `len` is zero (when encoding
|
||||
* an object of length zero, which is not very useful), or when `dest`
|
||||
* is `NULL` (in that case, source data bytes are ignored).
|
||||
*
|
||||
* Some `flags` can be specified to alter the encoding behaviour:
|
||||
*
|
||||
* - If `BR_PEM_LINE64` is set, then line-breaking will occur after
|
||||
* every 64 characters of output, instead of the default of 76.
|
||||
*
|
||||
* - If `BR_PEM_CRLF` is set, then end-of-line sequence will use
|
||||
* CR+LF instead of a single LF.
|
||||
*
|
||||
* The `data` and `dest` buffers may overlap, in which case the source
|
||||
* binary data is destroyed in the process. Note that the PEM-encoded output
|
||||
* is always larger than the source binary.
|
||||
*
|
||||
* \param dest the destination buffer (or `NULL`).
|
||||
* \param data the source buffer (can be `NULL` in some cases).
|
||||
* \param len the source length (in bytes).
|
||||
* \param banner the PEM banner expression.
|
||||
* \param flags the behavioural flags.
|
||||
* \return the PEM object length (in characters), EXCLUDING the final zero.
|
||||
*/
|
||||
size_t br_pem_encode(void *dest, const void *data, size_t len,
|
||||
const char *banner, unsigned flags);
|
||||
|
||||
/**
|
||||
* \brief PEM encoding flag: split lines at 64 characters.
|
||||
*/
|
||||
#define BR_PEM_LINE64 0x0001
|
||||
|
||||
/**
|
||||
* \brief PEM encoding flag: use CR+LF line endings.
|
||||
*/
|
||||
#define BR_PEM_CRLF 0x0002
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_PRF_H__
|
||||
#define BR_BEARSSL_PRF_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_prf.h
|
||||
*
|
||||
* # The TLS PRF
|
||||
*
|
||||
* The "PRF" is the pseudorandom function used internally during the
|
||||
* SSL/TLS handshake, notably to expand negotiated shared secrets into
|
||||
* the symmetric encryption keys that will be used to process the
|
||||
* application data.
|
||||
*
|
||||
* TLS 1.0 and 1.1 define a PRF that is based on both MD5 and SHA-1. This
|
||||
* is implemented by the `br_tls10_prf()` function.
|
||||
*
|
||||
* TLS 1.2 redefines the PRF, using an explicit hash function. The
|
||||
* `br_tls12_sha256_prf()` and `br_tls12_sha384_prf()` functions apply that
|
||||
* PRF with, respectively, SHA-256 and SHA-384. Most standard cipher suites
|
||||
* rely on the SHA-256 based PRF, but some use SHA-384.
|
||||
*
|
||||
* The PRF always uses as input three parameters: a "secret" (some
|
||||
* bytes), a "label" (ASCII string), and a "seed" (again some bytes). An
|
||||
* arbitrary output length can be produced. The "seed" is provided as an
|
||||
* arbitrary number of binary chunks, that gets internally concatenated.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Type for a seed chunk.
|
||||
*
|
||||
* Each chunk may have an arbitrary length, and may be empty (no byte at
|
||||
* all). If the chunk length is zero, then the pointer to the chunk data
|
||||
* may be `NULL`.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Pointer to the chunk data.
|
||||
*/
|
||||
const void *data;
|
||||
|
||||
/**
|
||||
* \brief Chunk length (in bytes).
|
||||
*/
|
||||
size_t len;
|
||||
} br_tls_prf_seed_chunk;
|
||||
|
||||
/**
|
||||
* \brief PRF implementation for TLS 1.0 and 1.1.
|
||||
*
|
||||
* This PRF is the one specified by TLS 1.0 and 1.1. It internally uses
|
||||
* MD5 and SHA-1.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
void br_tls10_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
/**
|
||||
* \brief PRF implementation for TLS 1.2, with SHA-256.
|
||||
*
|
||||
* This PRF is the one specified by TLS 1.2, when the underlying hash
|
||||
* function is SHA-256.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
void br_tls12_sha256_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
/**
|
||||
* \brief PRF implementation for TLS 1.2, with SHA-384.
|
||||
*
|
||||
* This PRF is the one specified by TLS 1.2, when the underlying hash
|
||||
* function is SHA-384.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
void br_tls12_sha384_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
/**
|
||||
* brief A convenient type name for a PRF implementation.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
typedef void (*br_tls_prf_impl)(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_RAND_H__
|
||||
#define BR_BEARSSL_RAND_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_block.h"
|
||||
#include "bearssl_hash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_rand.h
|
||||
*
|
||||
* # Pseudo-Random Generators
|
||||
*
|
||||
* A PRNG is a state-based engine that outputs pseudo-random bytes on
|
||||
* demand. It is initialized with an initial seed, and additional seed
|
||||
* bytes can be added afterwards. Bytes produced depend on the seeds and
|
||||
* also on the exact sequence of calls (including sizes requested for
|
||||
* each call).
|
||||
*
|
||||
*
|
||||
* ## Procedural and OOP API
|
||||
*
|
||||
* For the PRNG of name "`xxx`", two API are provided. The _procedural_
|
||||
* API defined a context structure `br_xxx_context` and three functions:
|
||||
*
|
||||
* - `br_xxx_init()`
|
||||
*
|
||||
* Initialise the context with an initial seed.
|
||||
*
|
||||
* - `br_xxx_generate()`
|
||||
*
|
||||
* Produce some pseudo-random bytes.
|
||||
*
|
||||
* - `br_xxx_update()`
|
||||
*
|
||||
* Inject some additional seed.
|
||||
*
|
||||
* The initialisation function sets the first context field (`vtable`)
|
||||
* to a pointer to the vtable that supports the OOP API. The OOP API
|
||||
* provides access to the same functions through function pointers,
|
||||
* named `init()`, `generate()` and `update()`.
|
||||
*
|
||||
* Note that the context initialisation method may accept additional
|
||||
* parameters, provided as a 'const void *' pointer at API level. These
|
||||
* additional parameters depend on the implemented PRNG.
|
||||
*
|
||||
*
|
||||
* ## HMAC_DRBG
|
||||
*
|
||||
* HMAC_DRBG is defined in [NIST SP 800-90A Revision
|
||||
* 1](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf).
|
||||
* It uses HMAC repeatedly, over some configurable underlying hash
|
||||
* function. In BearSSL, it is implemented under the "`hmac_drbg`" name.
|
||||
* The "extra parameters" pointer for context initialisation should be
|
||||
* set to a pointer to the vtable for the underlying hash function (e.g.
|
||||
* pointer to `br_sha256_vtable` to use HMAC_DRBG with SHA-256).
|
||||
*
|
||||
* According to the NIST standard, each request shall produce up to
|
||||
* 2<sup>19</sup> bits (i.e. 64 kB of data); moreover, the context shall
|
||||
* be reseeded at least once every 2<sup>48</sup> requests. This
|
||||
* implementation does not maintain the reseed counter (the threshold is
|
||||
* too high to be reached in practice) and does not object to producing
|
||||
* more than 64 kB in a single request; thus, the code cannot fail,
|
||||
* which corresponds to the fact that the API has no room for error
|
||||
* codes. However, this implies that requesting more than 64 kB in one
|
||||
* `generate()` request, or making more than 2<sup>48</sup> requests
|
||||
* without reseeding, is formally out of NIST specification. There is
|
||||
* no currently known security penalty for exceeding the NIST limits,
|
||||
* and, in any case, HMAC_DRBG usage in implementing SSL/TLS always
|
||||
* stays much below these thresholds.
|
||||
*
|
||||
*
|
||||
* ## AESCTR_DRBG
|
||||
*
|
||||
* AESCTR_DRBG is a custom PRNG based on AES-128 in CTR mode. This is
|
||||
* meant to be used only in situations where you are desperate for
|
||||
* speed, and have an hardware-optimized AES/CTR implementation. Whether
|
||||
* this will yield perceptible improvements depends on what you use the
|
||||
* pseudorandom bytes for, and how many you want; for instance, RSA key
|
||||
* pair generation uses a substantial amount of randomness, and using
|
||||
* AESCTR_DRBG instead of HMAC_DRBG yields a 15 to 20% increase in key
|
||||
* generation speed on a recent x86 CPU (Intel Core i7-6567U at 3.30 GHz).
|
||||
*
|
||||
* Internally, it uses CTR mode with successive counter values, starting
|
||||
* at zero (counter value expressed over 128 bits, big-endian convention).
|
||||
* The counter is not allowed to reach 32768; thus, every 32768*16 bytes
|
||||
* at most, the `update()` function is run (on an empty seed, if none is
|
||||
* provided). The `update()` function computes the new AES-128 key by
|
||||
* applying a custom hash function to the concatenation of a state-dependent
|
||||
* word (encryption of an all-one block with the current key) and the new
|
||||
* seed. The custom hash function uses Hirose's construction over AES-256;
|
||||
* see the comments in `aesctr_drbg.c` for details.
|
||||
*
|
||||
* This DRBG does not follow an existing standard, and thus should be
|
||||
* considered as inadequate for production use until it has been properly
|
||||
* analysed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Class type for PRNG implementations.
|
||||
*
|
||||
* A `br_prng_class` instance references the methods implementing a PRNG.
|
||||
* Constant instances of this structure are defined for each implemented
|
||||
* PRNG. Such instances are also called "vtables".
|
||||
*/
|
||||
typedef struct br_prng_class_ br_prng_class;
|
||||
struct br_prng_class_ {
|
||||
/**
|
||||
* \brief Size (in bytes) of the context structure appropriate for
|
||||
* running this PRNG.
|
||||
*/
|
||||
size_t context_size;
|
||||
|
||||
/**
|
||||
* \brief Initialisation method.
|
||||
*
|
||||
* The context to initialise is provided as a pointer to its
|
||||
* first field (the vtable pointer); this function sets that
|
||||
* first field to a pointer to the vtable.
|
||||
*
|
||||
* The extra parameters depend on the implementation; each
|
||||
* implementation defines what kind of extra parameters it
|
||||
* expects (if any).
|
||||
*
|
||||
* Requirements on the initial seed depend on the implemented
|
||||
* PRNG.
|
||||
*
|
||||
* \param ctx PRNG context to initialise.
|
||||
* \param params extra parameters for the PRNG.
|
||||
* \param seed initial seed.
|
||||
* \param seed_len initial seed length (in bytes).
|
||||
*/
|
||||
void (*init)(const br_prng_class **ctx, const void *params,
|
||||
const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Random bytes generation.
|
||||
*
|
||||
* This method produces `len` pseudorandom bytes, in the `out`
|
||||
* buffer. The context is updated accordingly.
|
||||
*
|
||||
* \param ctx PRNG context.
|
||||
* \param out output buffer.
|
||||
* \param len number of pseudorandom bytes to produce.
|
||||
*/
|
||||
void (*generate)(const br_prng_class **ctx, void *out, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional seed bytes.
|
||||
*
|
||||
* The provided seed bytes are added into the PRNG internal
|
||||
* entropy pool.
|
||||
*
|
||||
* \param ctx PRNG context.
|
||||
* \param seed additional seed.
|
||||
* \param seed_len additional seed length (in bytes).
|
||||
*/
|
||||
void (*update)(const br_prng_class **ctx,
|
||||
const void *seed, size_t seed_len);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Context for HMAC_DRBG.
|
||||
*
|
||||
* The context contents are opaque, except the first field, which
|
||||
* supports OOP.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Pointer to the vtable.
|
||||
*
|
||||
* This field is set with the initialisation method/function.
|
||||
*/
|
||||
const br_prng_class *vtable;
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
unsigned char K[64];
|
||||
unsigned char V[64];
|
||||
const br_hash_class *digest_class;
|
||||
#endif
|
||||
} br_hmac_drbg_context;
|
||||
|
||||
/**
|
||||
* \brief Statically allocated, constant vtable for HMAC_DRBG.
|
||||
*/
|
||||
extern const br_prng_class br_hmac_drbg_vtable;
|
||||
|
||||
/**
|
||||
* \brief HMAC_DRBG initialisation.
|
||||
*
|
||||
* The context to initialise is provided as a pointer to its first field
|
||||
* (the vtable pointer); this function sets that first field to a
|
||||
* pointer to the vtable.
|
||||
*
|
||||
* The `seed` value is what is called, in NIST terminology, the
|
||||
* concatenation of the "seed", "nonce" and "personalization string", in
|
||||
* that order.
|
||||
*
|
||||
* The `digest_class` parameter defines the underlying hash function.
|
||||
* Formally, the NIST standard specifies that the hash function shall
|
||||
* be only SHA-1 or one of the SHA-2 functions. This implementation also
|
||||
* works with any other implemented hash function (such as MD5), but
|
||||
* this is non-standard and therefore not recommended.
|
||||
*
|
||||
* \param ctx HMAC_DRBG context to initialise.
|
||||
* \param digest_class vtable for the underlying hash function.
|
||||
* \param seed initial seed.
|
||||
* \param seed_len initial seed length (in bytes).
|
||||
*/
|
||||
void br_hmac_drbg_init(br_hmac_drbg_context *ctx,
|
||||
const br_hash_class *digest_class, const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Random bytes generation with HMAC_DRBG.
|
||||
*
|
||||
* This method produces `len` pseudorandom bytes, in the `out`
|
||||
* buffer. The context is updated accordingly. Formally, requesting
|
||||
* more than 65536 bytes in one request falls out of specification
|
||||
* limits (but it won't fail).
|
||||
*
|
||||
* \param ctx HMAC_DRBG context.
|
||||
* \param out output buffer.
|
||||
* \param len number of pseudorandom bytes to produce.
|
||||
*/
|
||||
void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional seed bytes in HMAC_DRBG.
|
||||
*
|
||||
* The provided seed bytes are added into the HMAC_DRBG internal
|
||||
* entropy pool. The process does not _replace_ existing entropy,
|
||||
* thus pushing non-random bytes (i.e. bytes which are known to the
|
||||
* attackers) does not degrade the overall quality of generated bytes.
|
||||
*
|
||||
* \param ctx HMAC_DRBG context.
|
||||
* \param seed additional seed.
|
||||
* \param seed_len additional seed length (in bytes).
|
||||
*/
|
||||
void br_hmac_drbg_update(br_hmac_drbg_context *ctx,
|
||||
const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Get the hash function implementation used by a given instance of
|
||||
* HMAC_DRBG.
|
||||
*
|
||||
* This calls MUST NOT be performed on a context which was not
|
||||
* previously initialised.
|
||||
*
|
||||
* \param ctx HMAC_DRBG context.
|
||||
* \return the hash function vtable.
|
||||
*/
|
||||
static inline const br_hash_class *
|
||||
br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx)
|
||||
{
|
||||
return ctx->digest_class;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Type for a provider of entropy seeds.
|
||||
*
|
||||
* A "seeder" is a function that is able to obtain random values from
|
||||
* some source and inject them as entropy seed in a PRNG. A seeder
|
||||
* shall guarantee that the total entropy of the injected seed is large
|
||||
* enough to seed a PRNG for purposes of cryptographic key generation
|
||||
* (i.e. at least 128 bits).
|
||||
*
|
||||
* A seeder may report a failure to obtain adequate entropy. Seeders
|
||||
* shall endeavour to fix themselves transient errors by trying again;
|
||||
* thus, callers may consider reported errors as permanent.
|
||||
*
|
||||
* \param ctx PRNG context to seed.
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
typedef int (*br_prng_seeder)(const br_prng_class **ctx);
|
||||
|
||||
/**
|
||||
* \brief Get a seeder backed by the operating system or hardware.
|
||||
*
|
||||
* Get a seeder that feeds on RNG facilities provided by the current
|
||||
* operating system or hardware. If no such facility is known, then 0
|
||||
* is returned.
|
||||
*
|
||||
* If `name` is not `NULL`, then `*name` is set to a symbolic string
|
||||
* that identifies the seeder implementation. If no seeder is returned
|
||||
* and `name` is not `NULL`, then `*name` is set to a pointer to the
|
||||
* constant string `"none"`.
|
||||
*
|
||||
* \param name receiver for seeder name, or `NULL`.
|
||||
* \return the system seeder, if available, or 0.
|
||||
*/
|
||||
br_prng_seeder br_prng_seeder_system(const char **name);
|
||||
|
||||
/**
|
||||
* \brief Context for AESCTR_DRBG.
|
||||
*
|
||||
* The context contents are opaque, except the first field, which
|
||||
* supports OOP.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Pointer to the vtable.
|
||||
*
|
||||
* This field is set with the initialisation method/function.
|
||||
*/
|
||||
const br_prng_class *vtable;
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
br_aes_gen_ctr_keys sk;
|
||||
uint32_t cc;
|
||||
#endif
|
||||
} br_aesctr_drbg_context;
|
||||
|
||||
/**
|
||||
* \brief Statically allocated, constant vtable for AESCTR_DRBG.
|
||||
*/
|
||||
extern const br_prng_class br_aesctr_drbg_vtable;
|
||||
|
||||
/**
|
||||
* \brief AESCTR_DRBG initialisation.
|
||||
*
|
||||
* The context to initialise is provided as a pointer to its first field
|
||||
* (the vtable pointer); this function sets that first field to a
|
||||
* pointer to the vtable.
|
||||
*
|
||||
* The internal AES key is first set to the all-zero key; then, the
|
||||
* `br_aesctr_drbg_update()` function is called with the provided `seed`.
|
||||
* The call is performed even if the seed length (`seed_len`) is zero.
|
||||
*
|
||||
* The `aesctr` parameter defines the underlying AES/CTR implementation.
|
||||
*
|
||||
* \param ctx AESCTR_DRBG context to initialise.
|
||||
* \param aesctr vtable for the AES/CTR implementation.
|
||||
* \param seed initial seed (can be `NULL` if `seed_len` is zero).
|
||||
* \param seed_len initial seed length (in bytes).
|
||||
*/
|
||||
void br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
|
||||
const br_block_ctr_class *aesctr, const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Random bytes generation with AESCTR_DRBG.
|
||||
*
|
||||
* This method produces `len` pseudorandom bytes, in the `out`
|
||||
* buffer. The context is updated accordingly.
|
||||
*
|
||||
* \param ctx AESCTR_DRBG context.
|
||||
* \param out output buffer.
|
||||
* \param len number of pseudorandom bytes to produce.
|
||||
*/
|
||||
void br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx,
|
||||
void *out, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional seed bytes in AESCTR_DRBG.
|
||||
*
|
||||
* The provided seed bytes are added into the AESCTR_DRBG internal
|
||||
* entropy pool. The process does not _replace_ existing entropy,
|
||||
* thus pushing non-random bytes (i.e. bytes which are known to the
|
||||
* attackers) does not degrade the overall quality of generated bytes.
|
||||
*
|
||||
* \param ctx AESCTR_DRBG context.
|
||||
* \param seed additional seed.
|
||||
* \param seed_len additional seed length (in bytes).
|
||||
*/
|
||||
void br_aesctr_drbg_update(br_aesctr_drbg_context *ctx,
|
||||
const void *seed, size_t seed_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -16,6 +16,9 @@ There are only two changes in `src/inner.h`:
|
|||
|
||||
Then compile with
|
||||
|
||||
```make CONF=esp8266```
|
||||
```
|
||||
make CONF=esp8266
|
||||
xtensa-lx106-elf-ar d esp8266/libbearssl.a `xtensa-lx106-elf-ar t esp8266/libbearssl.a | egrep 'i31|i32|x86|sse|pwr8|i62|m31|m32|m62|m64|ct64|ctmul64'`
|
||||
```
|
||||
|
||||
Finally copy `libbearssl.a` to this directory.
|
||||
|
|
Binary file not shown.
|
@ -57,6 +57,8 @@ platform = espressif8266@1.8.0
|
|||
build_flags = ${esp82xx_defaults.build_flags}
|
||||
-Wl,-Teagle.flash.1m0.ld
|
||||
-lstdc++ -lsupc++
|
||||
; link with an memory optimized version of lib_bearssl
|
||||
-Llib_bearssl -lbearssl
|
||||
; lwIP 1.4
|
||||
; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
|
||||
; lwIP 2 - Low Memory
|
||||
|
|
|
@ -38,7 +38,7 @@ uint32_t *stack_thunk_light_save = NULL; /* Saved A1 while in BearSSL */
|
|||
uint32_t stack_thunk_light_refcnt = 0;
|
||||
|
||||
//#define _stackSize (5600/4)
|
||||
#define _stackSize (5100/4) // using a light version of bearssl we can save 1KB
|
||||
#define _stackSize (4600/4) // using a light version of bearssl we can save 1KB
|
||||
#define _stackPaint 0xdeadbeef
|
||||
|
||||
/* Add a reference, and allocate the stack if necessary */
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <core_version.h>
|
||||
#ifdef ARDUINO_ESP8266_RELEASE_2_5_2
|
||||
|
||||
#define LWIP_INTERNAL
|
||||
|
||||
#include <list>
|
||||
|
@ -45,12 +42,13 @@ extern "C" {
|
|||
#include "lwip/netif.h"
|
||||
#include <include/ClientContext.h>
|
||||
#include "c_types.h"
|
||||
#include "coredecls.h"
|
||||
|
||||
#define SKEY_ON_STACK // copy private key+cert on stack rather than on heap, this works for now because it takes ~800 bytes
|
||||
#include "my_user_config.h"
|
||||
|
||||
//#define DEBUG_TLS
|
||||
|
||||
#ifdef DEBUG_TLS
|
||||
#include "coredecls.h"
|
||||
#define LOG_HEAP_SIZE(a) _Log_heap_size(a)
|
||||
void _Log_heap_size(const char *msg) {
|
||||
register uint32_t *sp asm("a1");
|
||||
|
@ -247,14 +245,24 @@ void WiFiClientSecure_light::setBufferSizes(int recv, int xmit) {
|
|||
}
|
||||
|
||||
bool WiFiClientSecure_light::stop(unsigned int maxWaitMs) {
|
||||
#ifdef ARDUINO_ESP8266_RELEASE_2_4_2
|
||||
WiFiClient::stop(); // calls our virtual flush()
|
||||
_freeSSL();
|
||||
return true;
|
||||
#else
|
||||
bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
|
||||
_freeSSL();
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WiFiClientSecure_light::flush(unsigned int maxWaitMs) {
|
||||
(void) _run_until(BR_SSL_SENDAPP);
|
||||
#ifdef ARDUINO_ESP8266_RELEASE_2_4_2
|
||||
WiFiClient::flush();
|
||||
#else
|
||||
return WiFiClient::flush(maxWaitMs);
|
||||
#endif
|
||||
}
|
||||
|
||||
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
|
||||
|
@ -283,10 +291,6 @@ int WiFiClientSecure_light::connect(const char* name, uint16_t port) {
|
|||
return _connectSSL(name);
|
||||
}
|
||||
|
||||
int WiFiClientSecure_light::connect(const String& host, uint16_t port) {
|
||||
return connect(host.c_str(), port);
|
||||
}
|
||||
|
||||
void WiFiClientSecure_light::_freeSSL() {
|
||||
_ctx_present = false;
|
||||
_recvapp_buf = nullptr;
|
||||
|
@ -776,11 +780,13 @@ extern "C" {
|
|||
// Called by connect() to do the actual SSL setup and handshake.
|
||||
// Returns if the SSL handshake succeeded.
|
||||
bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
br_ec_private_key sk_ec;
|
||||
br_x509_certificate chain;
|
||||
#ifdef SKEY_ON_STACK
|
||||
#ifdef USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
unsigned char chain_data[_chain_P->data_len];
|
||||
unsigned char sk_data[_sk_ec_P->xlen];
|
||||
#endif
|
||||
#endif
|
||||
br_x509_pubkeyfingerprint_context *x509_insecure;
|
||||
|
||||
|
@ -808,11 +814,10 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
|||
br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
|
||||
|
||||
LOG_HEAP_SIZE("_connectSSL after PrivKey allocation");
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
// allocate Private key and client certificate
|
||||
//chain = new X509List(_chain_PEM);
|
||||
//sk = new PrivateKey(_sk_PEM);
|
||||
chain.data_len = _chain_P->data_len;
|
||||
#ifdef SKEY_ON_STACK // allocate on stack
|
||||
#ifdef USE_MQTT_AWS_IOT_SKEY_ON_STACK // allocate on stack
|
||||
chain.data = &chain_data[0];
|
||||
#else // allocate with malloc
|
||||
chain.data = (unsigned char *) malloc(chain.data_len);
|
||||
|
@ -821,38 +826,47 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
|||
|
||||
sk_ec.curve = _sk_ec_P->curve;
|
||||
sk_ec.xlen = _sk_ec_P->xlen;
|
||||
#ifdef SKEY_ON_STACK
|
||||
#ifdef USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
sk_ec.x = &sk_data[0];
|
||||
#else
|
||||
#else // USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
sk_ec.x = (unsigned char *) malloc(sk_ec.xlen);
|
||||
#endif
|
||||
#endif // USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
if (sk_ec.x) memcpy_P(sk_ec.x, _sk_ec_P->x, sk_ec.xlen);
|
||||
LOG_HEAP_SIZE("_connectSSL after PrivKey allocation");
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
|
||||
// check if memory was correctly allocated
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
if ((!stack_thunk_light_get_stack_bot()) || (!x509_insecure) ||
|
||||
(!chain.data) || (!sk_ec.x)) {
|
||||
// memory allocation problem
|
||||
setLastError(ERR_OOM);
|
||||
#ifndef SKEY_ON_STACK
|
||||
#ifndef USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
free(chain.data);
|
||||
free(sk_ec.x);
|
||||
#endif
|
||||
#endif // USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
#else
|
||||
if ((!stack_thunk_light_get_stack_bot()) || (!x509_insecure)) {
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
// memory allocation problem
|
||||
setLastError(ERR_OOM);
|
||||
free(x509_insecure);
|
||||
stack_thunk_light_del_ref();
|
||||
DEBUG_BSSL("_connectSSL: Out of memory\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
// limited to P256 curve
|
||||
br_ssl_client_set_single_ec(_sc.get(), &chain, 1,
|
||||
&sk_ec, _allowed_usages,
|
||||
_cert_issuer_key_type, &br_ec_p256_m15, br_ecdsa_sign_asn1_get_default());
|
||||
#endif
|
||||
|
||||
if (!br_ssl_client_reset(_sc.get(), hostName, 0)) {
|
||||
#ifndef SKEY_ON_STACK
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
#ifndef USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
free(chain.data);
|
||||
free(sk_ec.x);
|
||||
#endif
|
||||
#endif
|
||||
free(x509_insecure);
|
||||
stack_thunk_light_del_ref();
|
||||
|
@ -873,9 +887,11 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
|||
stack_thunk_light_del_ref();
|
||||
//stack_thunk_light_repaint();
|
||||
LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
|
||||
#ifndef SKEY_ON_STACK
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
#ifndef USE_MQTT_AWS_IOT_SKEY_ON_STACK
|
||||
free(chain.data);
|
||||
free(sk_ec.x);
|
||||
#endif
|
||||
#endif
|
||||
free(x509_insecure);
|
||||
LOG_HEAP_SIZE("_connectSSL after release of Priv Key");
|
||||
|
@ -883,5 +899,3 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
|||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // ARDUINO_ESP8266_RELEASE_2_5_2
|
|
@ -21,15 +21,12 @@
|
|||
*/
|
||||
|
||||
#include <core_version.h>
|
||||
#ifdef ARDUINO_ESP8266_RELEASE_2_5_2
|
||||
|
||||
#ifndef wificlientlightbearssl_h
|
||||
#define wificlientlightbearssl_h
|
||||
#include <vector>
|
||||
#include "WiFiClient.h"
|
||||
#include <bearssl/bearssl.h>
|
||||
#include "BearSSLHelpers.h"
|
||||
#include "CertStoreBearSSL.h"
|
||||
|
||||
namespace BearSSL {
|
||||
|
||||
|
@ -41,7 +38,6 @@ class WiFiClientSecure_light : public WiFiClient {
|
|||
void allocateBuffers(void);
|
||||
|
||||
int connect(IPAddress ip, uint16_t port) override;
|
||||
int connect(const String& host, uint16_t port) override;
|
||||
int connect(const char* name, uint16_t port) override;
|
||||
|
||||
uint8_t connected() override;
|
||||
|
@ -148,5 +144,3 @@ class WiFiClientSecure_light : public WiFiClient {
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ARDUINO_ESP8266_RELEASE_2_5_2
|
|
@ -7,6 +7,7 @@
|
|||
* Fix include of my_user_config.h in sonoff_aws_iot.cpp (#5930)
|
||||
* Fix exception 9 when syslog is enabled and NTP is just synced (#5917)
|
||||
* Fix Toggle functionality to button double press when one button and two devices are detected (#5935)
|
||||
* Refactored TLS based on BearSSL, warning breaking change for fongerprints validation (see doc)
|
||||
*
|
||||
* 6.5.0.14 20190602
|
||||
* Change webserver HTML input, button, textarea, and select name based on id
|
||||
|
|
|
@ -262,16 +262,15 @@
|
|||
#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+7k code)
|
||||
#define HOME_ASSISTANT_DISCOVERY_PREFIX "homeassistant" // Home Assistant discovery prefix
|
||||
|
||||
// -- MQTT - TLS ----------------------------------
|
||||
// !!! TLS uses a LOT OF MEMORY so be careful to enable other options at the same time !!!
|
||||
//#define USE_MQTT_TLS // Use TLS for MQTT connection (+53k code, +15k mem)
|
||||
// #define USE_MQTT_TLS_CA_CERT // Use LetsEncrypt Certificate from sonoff_letsencrypt.h - Not supported with core 2.3.0
|
||||
|
||||
// -- MQTT - Special version for AWS IoT on core 2.5.2 only
|
||||
// -- MQTT - TLS - AWS IoT ----------------------------------
|
||||
//#define USE_MQTT_TLS // Use TLS for MQTT connection (+56.7k code, +6.0k mem and +6.6k additional during connection handshake)
|
||||
//#define USE_MQTT_AWS_IOT // Enable MQTT for AWS IoT - requires a private key (+56.7k code, +6.0k mem and +6.6k additional during connection handshake)
|
||||
// note: enabling USE_MQTT_AWS_IOT autoamtically enables USE_MQTT_TLS
|
||||
// you need to generate a private key + certificate per device
|
||||
// and update 'sonoff/sonoff_aws_iot.cpp'
|
||||
// Full documentation here: https://github.com/arendst/Sonoff-Tasmota/wiki/AWS-IoT
|
||||
#define USE_MQTT_AWS_IOT_SKEY_ON_STACK // copy private key+cert on stack rather than on heap, don't disable unless you see crashes during connections
|
||||
|
||||
|
||||
// -- KNX IP Protocol -----------------------------
|
||||
//#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem)
|
||||
|
@ -285,7 +284,7 @@
|
|||
#define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem common)
|
||||
|
||||
// -- mDNS ----------------------------------------
|
||||
#define USE_DISCOVERY // Enable mDNS for the following services (+8k code or +23.5k code with core 2_5_x, +0.3k mem)
|
||||
//#define USE_DISCOVERY // Enable mDNS for the following services (+8k code or +23.5k code with core 2_5_x, +0.3k mem)
|
||||
#define WEBSERVER_ADVERTISE // Provide access to webserver by name <Hostname>.local/
|
||||
#define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found)
|
||||
|
||||
|
@ -475,15 +474,7 @@
|
|||
* No user configurable items below
|
||||
\*********************************************************************************************/
|
||||
|
||||
#if defined(USE_MQTT_TLS) && defined(USE_WEBSERVER)
|
||||
#error "Select either USE_MQTT_TLS or USE_WEBSERVER as there is just not enough memory to play with"
|
||||
#endif
|
||||
|
||||
#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT)
|
||||
#error "Select either USE_MQTT_TLS or USE_MQTT_AWS_IOT, they are not compatible"
|
||||
#endif
|
||||
|
||||
#if defined(USE_DISCOVERY) && defined(USE_MQTT_AWS_IOT)
|
||||
#if defined(USE_DISCOVERY) && defined(USE_MQTT_TLS)
|
||||
#error "Select either USE_DISCOVERY or USE_MQTT_AWS_IOT, mDNS takes too much code space and is not needed for AWS IoT"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1855,8 +1855,13 @@ void PublishStatus(uint8_t payload)
|
|||
}
|
||||
|
||||
if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) {
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
|
||||
Settings.mqtt_user, Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
|
||||
#else
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
|
||||
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
|
||||
#endif
|
||||
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6"));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
sonoff_ca.ino - Certificate authorities for Sonoff-Tasmota, LetsEncrypt and AWS
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// The below is currenlty not used, CA validation takes too much memory and compute time.
|
||||
// Please use fingerprint validation instead
|
||||
// However, the CA are available below for future use if it appears to be useful
|
||||
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
/*********************************************************************************************\
|
||||
* LetsEncrypt IdenTrust DST Root CA X3 certificate, RSA 2048 bits SHA 256, valid until 20210417
|
||||
*
|
||||
* https://letsencrypt.org/certificates/
|
||||
* Downloaded from https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt
|
||||
*
|
||||
* to convert do: ‘bearssl chain lets-encrypt-x3-cross-signed.pem.txt’
|
||||
* then copy and paste below, chain the generic names to the same as below
|
||||
* remove ‘static’ and add ‘PROGMEM’
|
||||
\*********************************************************************************************/
|
||||
|
||||
const unsigned char PROGMEM LetsencryptRootCA3[] = {
|
||||
0x30, 0x82, 0x04, 0x92, 0x30, 0x82, 0x03, 0x7A, 0xA0, 0x03, 0x02, 0x01,
|
||||
0x02, 0x02, 0x10, 0x0A, 0x01, 0x41, 0x42, 0x00, 0x00, 0x01, 0x53, 0x85,
|
||||
0x73, 0x6A, 0x0B, 0x85, 0xEC, 0xA7, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x2A,
|
||||
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x3F,
|
||||
0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1B, 0x44,
|
||||
0x69, 0x67, 0x69, 0x74, 0x61, 0x6C, 0x20, 0x53, 0x69, 0x67, 0x6E, 0x61,
|
||||
0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43,
|
||||
0x6F, 0x2E, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
|
||||
0x0E, 0x44, 0x53, 0x54, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41,
|
||||
0x20, 0x58, 0x33, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x36, 0x30, 0x33, 0x31,
|
||||
0x37, 0x31, 0x36, 0x34, 0x30, 0x34, 0x36, 0x5A, 0x17, 0x0D, 0x32, 0x31,
|
||||
0x30, 0x33, 0x31, 0x37, 0x31, 0x36, 0x34, 0x30, 0x34, 0x36, 0x5A, 0x30,
|
||||
0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
|
||||
0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13,
|
||||
0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72, 0x79,
|
||||
0x70, 0x74, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
|
||||
0x1A, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72, 0x79,
|
||||
0x70, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79,
|
||||
0x20, 0x58, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A,
|
||||
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
|
||||
0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00,
|
||||
0x9C, 0xD3, 0x0C, 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 0x37,
|
||||
0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1,
|
||||
0xBD, 0xBE, 0x35, 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 0x05,
|
||||
0xAB, 0xA9, 0x9E, 0x35, 0x08, 0x58, 0xEC, 0xB1, 0x2A, 0xC4, 0x68, 0x87,
|
||||
0x0B, 0xA3, 0xE3, 0x75, 0xE4, 0xE6, 0xF3, 0xA7, 0x62, 0x71, 0xBA, 0x79,
|
||||
0x81, 0x60, 0x1F, 0xD7, 0x91, 0x9A, 0x9F, 0xF3, 0xD0, 0x78, 0x67, 0x71,
|
||||
0xC8, 0x69, 0x0E, 0x95, 0x91, 0xCF, 0xFE, 0xE6, 0x99, 0xE9, 0x60, 0x3C,
|
||||
0x48, 0xCC, 0x7E, 0xCA, 0x4D, 0x77, 0x12, 0x24, 0x9D, 0x47, 0x1B, 0x5A,
|
||||
0xEB, 0xB9, 0xEC, 0x1E, 0x37, 0x00, 0x1C, 0x9C, 0xAC, 0x7B, 0xA7, 0x05,
|
||||
0xEA, 0xCE, 0x4A, 0xEB, 0xBD, 0x41, 0xE5, 0x36, 0x98, 0xB9, 0xCB, 0xFD,
|
||||
0x6D, 0x3C, 0x96, 0x68, 0xDF, 0x23, 0x2A, 0x42, 0x90, 0x0C, 0x86, 0x74,
|
||||
0x67, 0xC8, 0x7F, 0xA5, 0x9A, 0xB8, 0x52, 0x61, 0x14, 0x13, 0x3F, 0x65,
|
||||
0xE9, 0x82, 0x87, 0xCB, 0xDB, 0xFA, 0x0E, 0x56, 0xF6, 0x86, 0x89, 0xF3,
|
||||
0x85, 0x3F, 0x97, 0x86, 0xAF, 0xB0, 0xDC, 0x1A, 0xEF, 0x6B, 0x0D, 0x95,
|
||||
0x16, 0x7D, 0xC4, 0x2B, 0xA0, 0x65, 0xB2, 0x99, 0x04, 0x36, 0x75, 0x80,
|
||||
0x6B, 0xAC, 0x4A, 0xF3, 0x1B, 0x90, 0x49, 0x78, 0x2F, 0xA2, 0x96, 0x4F,
|
||||
0x2A, 0x20, 0x25, 0x29, 0x04, 0xC6, 0x74, 0xC0, 0xD0, 0x31, 0xCD, 0x8F,
|
||||
0x31, 0x38, 0x95, 0x16, 0xBA, 0xA8, 0x33, 0xB8, 0x43, 0xF1, 0xB1, 0x1F,
|
||||
0xC3, 0x30, 0x7F, 0xA2, 0x79, 0x31, 0x13, 0x3D, 0x2D, 0x36, 0xF8, 0xE3,
|
||||
0xFC, 0xF2, 0x33, 0x6A, 0xB9, 0x39, 0x31, 0xC5, 0xAF, 0xC4, 0x8D, 0x0D,
|
||||
0x1D, 0x64, 0x16, 0x33, 0xAA, 0xFA, 0x84, 0x29, 0xB6, 0xD4, 0x0B, 0xC0,
|
||||
0xD8, 0x7D, 0xC3, 0x93, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x82, 0x01,
|
||||
0x7D, 0x30, 0x82, 0x01, 0x79, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1D, 0x13,
|
||||
0x01, 0x01, 0xFF, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01,
|
||||
0x00, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04,
|
||||
0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x7F, 0x06, 0x08, 0x2B, 0x06, 0x01,
|
||||
0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x32, 0x06,
|
||||
0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x26, 0x68,
|
||||
0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x69, 0x73, 0x72, 0x67, 0x2E, 0x74,
|
||||
0x72, 0x75, 0x73, 0x74, 0x69, 0x64, 0x2E, 0x6F, 0x63, 0x73, 0x70, 0x2E,
|
||||
0x69, 0x64, 0x65, 0x6E, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2E, 0x63, 0x6F,
|
||||
0x6D, 0x30, 0x3B, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30,
|
||||
0x02, 0x86, 0x2F, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x61, 0x70,
|
||||
0x70, 0x73, 0x2E, 0x69, 0x64, 0x65, 0x6E, 0x74, 0x72, 0x75, 0x73, 0x74,
|
||||
0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x72, 0x6F, 0x6F, 0x74, 0x73, 0x2F, 0x64,
|
||||
0x73, 0x74, 0x72, 0x6F, 0x6F, 0x74, 0x63, 0x61, 0x78, 0x33, 0x2E, 0x70,
|
||||
0x37, 0x63, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30,
|
||||
0x16, 0x80, 0x14, 0xC4, 0xA7, 0xB1, 0xA4, 0x7B, 0x2C, 0x71, 0xFA, 0xDB,
|
||||
0xE1, 0x4B, 0x90, 0x75, 0xFF, 0xC4, 0x15, 0x60, 0x85, 0x89, 0x10, 0x30,
|
||||
0x54, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04, 0x4D, 0x30, 0x4B, 0x30, 0x08,
|
||||
0x06, 0x06, 0x67, 0x81, 0x0C, 0x01, 0x02, 0x01, 0x30, 0x3F, 0x06, 0x0B,
|
||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xDF, 0x13, 0x01, 0x01, 0x01, 0x30,
|
||||
0x30, 0x30, 0x2E, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02,
|
||||
0x01, 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 0x70,
|
||||
0x73, 0x2E, 0x72, 0x6F, 0x6F, 0x74, 0x2D, 0x78, 0x31, 0x2E, 0x6C, 0x65,
|
||||
0x74, 0x73, 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2E, 0x6F, 0x72,
|
||||
0x67, 0x30, 0x3C, 0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x35, 0x30, 0x33,
|
||||
0x30, 0x31, 0xA0, 0x2F, 0xA0, 0x2D, 0x86, 0x2B, 0x68, 0x74, 0x74, 0x70,
|
||||
0x3A, 0x2F, 0x2F, 0x63, 0x72, 0x6C, 0x2E, 0x69, 0x64, 0x65, 0x6E, 0x74,
|
||||
0x72, 0x75, 0x73, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x44, 0x53, 0x54,
|
||||
0x52, 0x4F, 0x4F, 0x54, 0x43, 0x41, 0x58, 0x33, 0x43, 0x52, 0x4C, 0x2E,
|
||||
0x63, 0x72, 0x6C, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16,
|
||||
0x04, 0x14, 0xA8, 0x4A, 0x6A, 0x63, 0x04, 0x7D, 0xDD, 0xBA, 0xE6, 0xD1,
|
||||
0x39, 0xB7, 0xA6, 0x45, 0x65, 0xEF, 0xF3, 0xA8, 0xEC, 0xA1, 0x30, 0x0D,
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05,
|
||||
0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xDD, 0x33, 0xD7, 0x11, 0xF3, 0x63,
|
||||
0x58, 0x38, 0xDD, 0x18, 0x15, 0xFB, 0x09, 0x55, 0xBE, 0x76, 0x56, 0xB9,
|
||||
0x70, 0x48, 0xA5, 0x69, 0x47, 0x27, 0x7B, 0xC2, 0x24, 0x08, 0x92, 0xF1,
|
||||
0x5A, 0x1F, 0x4A, 0x12, 0x29, 0x37, 0x24, 0x74, 0x51, 0x1C, 0x62, 0x68,
|
||||
0xB8, 0xCD, 0x95, 0x70, 0x67, 0xE5, 0xF7, 0xA4, 0xBC, 0x4E, 0x28, 0x51,
|
||||
0xCD, 0x9B, 0xE8, 0xAE, 0x87, 0x9D, 0xEA, 0xD8, 0xBA, 0x5A, 0xA1, 0x01,
|
||||
0x9A, 0xDC, 0xF0, 0xDD, 0x6A, 0x1D, 0x6A, 0xD8, 0x3E, 0x57, 0x23, 0x9E,
|
||||
0xA6, 0x1E, 0x04, 0x62, 0x9A, 0xFF, 0xD7, 0x05, 0xCA, 0xB7, 0x1F, 0x3F,
|
||||
0xC0, 0x0A, 0x48, 0xBC, 0x94, 0xB0, 0xB6, 0x65, 0x62, 0xE0, 0xC1, 0x54,
|
||||
0xE5, 0xA3, 0x2A, 0xAD, 0x20, 0xC4, 0xE9, 0xE6, 0xBB, 0xDC, 0xC8, 0xF6,
|
||||
0xB5, 0xC3, 0x32, 0xA3, 0x98, 0xCC, 0x77, 0xA8, 0xE6, 0x79, 0x65, 0x07,
|
||||
0x2B, 0xCB, 0x28, 0xFE, 0x3A, 0x16, 0x52, 0x81, 0xCE, 0x52, 0x0C, 0x2E,
|
||||
0x5F, 0x83, 0xE8, 0xD5, 0x06, 0x33, 0xFB, 0x77, 0x6C, 0xCE, 0x40, 0xEA,
|
||||
0x32, 0x9E, 0x1F, 0x92, 0x5C, 0x41, 0xC1, 0x74, 0x6C, 0x5B, 0x5D, 0x0A,
|
||||
0x5F, 0x33, 0xCC, 0x4D, 0x9F, 0xAC, 0x38, 0xF0, 0x2F, 0x7B, 0x2C, 0x62,
|
||||
0x9D, 0xD9, 0xA3, 0x91, 0x6F, 0x25, 0x1B, 0x2F, 0x90, 0xB1, 0x19, 0x46,
|
||||
0x3D, 0xF6, 0x7E, 0x1B, 0xA6, 0x7A, 0x87, 0xB9, 0xA3, 0x7A, 0x6D, 0x18,
|
||||
0xFA, 0x25, 0xA5, 0x91, 0x87, 0x15, 0xE0, 0xF2, 0x16, 0x2F, 0x58, 0xB0,
|
||||
0x06, 0x2F, 0x2C, 0x68, 0x26, 0xC6, 0x4B, 0x98, 0xCD, 0xDA, 0x9F, 0x0C,
|
||||
0xF9, 0x7F, 0x90, 0xED, 0x43, 0x4A, 0x12, 0x44, 0x4E, 0x6F, 0x73, 0x7A,
|
||||
0x28, 0xEA, 0xA4, 0xAA, 0x6E, 0x7B, 0x4C, 0x7D, 0x87, 0xDD, 0xE0, 0xC9,
|
||||
0x02, 0x44, 0xA7, 0x87, 0xAF, 0xC3, 0x34, 0x5B, 0xB4, 0x42
|
||||
};
|
||||
|
||||
const br_x509_certificate PROGMEM LetsencryptRootCA3_chain[] = {
|
||||
{ (unsigned char *)LetsencryptRootCA3, sizeof LetsencryptRootCA3 }
|
||||
};
|
||||
|
||||
#define LETSENCRYPTROOTCA3LEN 1
|
||||
|
||||
#endif // USE_MQTT_TLS_CA_CERT
|
||||
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
/*********************************************************************************************\
|
||||
* Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117
|
||||
*
|
||||
* https://letsencrypt.org/certificates/
|
||||
* Downloaded from https://www.amazontrust.com/repository/AmazonRootCA1.pem
|
||||
*
|
||||
* to convert do: ‘bearssl chain AmazonRootCA1.pem’
|
||||
* then copy and paste below, chain the generic names to the same as below
|
||||
* remove ‘static’ and add ‘PROGMEM’
|
||||
\*********************************************************************************************/
|
||||
|
||||
const unsigned char PROGMEM AmazonRootCA1[] = {
|
||||
0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 0xA0, 0x03, 0x02, 0x01,
|
||||
0x02, 0x02, 0x13, 0x06, 0x6C, 0x9F, 0xCF, 0x99, 0xBF, 0x8C, 0x0A, 0x39,
|
||||
0xE2, 0xF0, 0x78, 0x8A, 0x43, 0xE6, 0x96, 0x36, 0x5B, 0xCA, 0x30, 0x0D,
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05,
|
||||
0x00, 0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
|
||||
0x13, 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0A, 0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30,
|
||||
0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6D, 0x61, 0x7A,
|
||||
0x6F, 0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31,
|
||||
0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x30, 0x35, 0x32, 0x36, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x33, 0x38, 0x30, 0x31, 0x31,
|
||||
0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x39, 0x31, 0x0B,
|
||||
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
|
||||
0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x06, 0x41, 0x6D,
|
||||
0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04,
|
||||
0x03, 0x13, 0x10, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x20, 0x52, 0x6F,
|
||||
0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30,
|
||||
0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
|
||||
0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02,
|
||||
0x82, 0x01, 0x01, 0x00, 0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3,
|
||||
0x71, 0xAF, 0x47, 0x80, 0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76,
|
||||
0xF4, 0x99, 0x68, 0xF7, 0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F,
|
||||
0xAC, 0x02, 0x2D, 0x86, 0xD3, 0xA0, 0x43, 0x7A, 0x4E, 0xB2, 0xA4, 0xD0,
|
||||
0x36, 0xBA, 0x01, 0xBE, 0x8D, 0xDB, 0x48, 0xC8, 0x07, 0x17, 0x36, 0x4C,
|
||||
0xF4, 0xEE, 0x88, 0x23, 0xC7, 0x3E, 0xEB, 0x37, 0xF5, 0xB5, 0x19, 0xF8,
|
||||
0x49, 0x68, 0xB0, 0xDE, 0xD7, 0xB9, 0x76, 0x38, 0x1D, 0x61, 0x9E, 0xA4,
|
||||
0xFE, 0x82, 0x36, 0xA5, 0xE5, 0x4A, 0x56, 0xE4, 0x45, 0xE1, 0xF9, 0xFD,
|
||||
0xB4, 0x16, 0xFA, 0x74, 0xDA, 0x9C, 0x9B, 0x35, 0x39, 0x2F, 0xFA, 0xB0,
|
||||
0x20, 0x50, 0x06, 0x6C, 0x7A, 0xD0, 0x80, 0xB2, 0xA6, 0xF9, 0xAF, 0xEC,
|
||||
0x47, 0x19, 0x8F, 0x50, 0x38, 0x07, 0xDC, 0xA2, 0x87, 0x39, 0x58, 0xF8,
|
||||
0xBA, 0xD5, 0xA9, 0xF9, 0x48, 0x67, 0x30, 0x96, 0xEE, 0x94, 0x78, 0x5E,
|
||||
0x6F, 0x89, 0xA3, 0x51, 0xC0, 0x30, 0x86, 0x66, 0xA1, 0x45, 0x66, 0xBA,
|
||||
0x54, 0xEB, 0xA3, 0xC3, 0x91, 0xF9, 0x48, 0xDC, 0xFF, 0xD1, 0xE8, 0x30,
|
||||
0x2D, 0x7D, 0x2D, 0x74, 0x70, 0x35, 0xD7, 0x88, 0x24, 0xF7, 0x9E, 0xC4,
|
||||
0x59, 0x6E, 0xBB, 0x73, 0x87, 0x17, 0xF2, 0x32, 0x46, 0x28, 0xB8, 0x43,
|
||||
0xFA, 0xB7, 0x1D, 0xAA, 0xCA, 0xB4, 0xF2, 0x9F, 0x24, 0x0E, 0x2D, 0x4B,
|
||||
0xF7, 0x71, 0x5C, 0x5E, 0x69, 0xFF, 0xEA, 0x95, 0x02, 0xCB, 0x38, 0x8A,
|
||||
0xAE, 0x50, 0x38, 0x6F, 0xDB, 0xFB, 0x2D, 0x62, 0x1B, 0xC5, 0xC7, 0x1E,
|
||||
0x54, 0xE1, 0x77, 0xE0, 0x67, 0xC8, 0x0F, 0x9C, 0x87, 0x23, 0xD6, 0x3F,
|
||||
0x40, 0x20, 0x7F, 0x20, 0x80, 0xC4, 0x80, 0x4C, 0x3E, 0x3B, 0x24, 0x26,
|
||||
0x8E, 0x04, 0xAE, 0x6C, 0x9A, 0xC8, 0xAA, 0x0D, 0x02, 0x03, 0x01, 0x00,
|
||||
0x01, 0xA3, 0x42, 0x30, 0x40, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13,
|
||||
0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0E,
|
||||
0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02,
|
||||
0x01, 0x86, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04,
|
||||
0x14, 0x84, 0x18, 0xCC, 0x85, 0x34, 0xEC, 0xBC, 0x0C, 0x94, 0x94, 0x2E,
|
||||
0x08, 0x59, 0x9C, 0xC7, 0xB2, 0x10, 0x4E, 0x0A, 0x08, 0x30, 0x0D, 0x06,
|
||||
0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
|
||||
0x03, 0x82, 0x01, 0x01, 0x00, 0x98, 0xF2, 0x37, 0x5A, 0x41, 0x90, 0xA1,
|
||||
0x1A, 0xC5, 0x76, 0x51, 0x28, 0x20, 0x36, 0x23, 0x0E, 0xAE, 0xE6, 0x28,
|
||||
0xBB, 0xAA, 0xF8, 0x94, 0xAE, 0x48, 0xA4, 0x30, 0x7F, 0x1B, 0xFC, 0x24,
|
||||
0x8D, 0x4B, 0xB4, 0xC8, 0xA1, 0x97, 0xF6, 0xB6, 0xF1, 0x7A, 0x70, 0xC8,
|
||||
0x53, 0x93, 0xCC, 0x08, 0x28, 0xE3, 0x98, 0x25, 0xCF, 0x23, 0xA4, 0xF9,
|
||||
0xDE, 0x21, 0xD3, 0x7C, 0x85, 0x09, 0xAD, 0x4E, 0x9A, 0x75, 0x3A, 0xC2,
|
||||
0x0B, 0x6A, 0x89, 0x78, 0x76, 0x44, 0x47, 0x18, 0x65, 0x6C, 0x8D, 0x41,
|
||||
0x8E, 0x3B, 0x7F, 0x9A, 0xCB, 0xF4, 0xB5, 0xA7, 0x50, 0xD7, 0x05, 0x2C,
|
||||
0x37, 0xE8, 0x03, 0x4B, 0xAD, 0xE9, 0x61, 0xA0, 0x02, 0x6E, 0xF5, 0xF2,
|
||||
0xF0, 0xC5, 0xB2, 0xED, 0x5B, 0xB7, 0xDC, 0xFA, 0x94, 0x5C, 0x77, 0x9E,
|
||||
0x13, 0xA5, 0x7F, 0x52, 0xAD, 0x95, 0xF2, 0xF8, 0x93, 0x3B, 0xDE, 0x8B,
|
||||
0x5C, 0x5B, 0xCA, 0x5A, 0x52, 0x5B, 0x60, 0xAF, 0x14, 0xF7, 0x4B, 0xEF,
|
||||
0xA3, 0xFB, 0x9F, 0x40, 0x95, 0x6D, 0x31, 0x54, 0xFC, 0x42, 0xD3, 0xC7,
|
||||
0x46, 0x1F, 0x23, 0xAD, 0xD9, 0x0F, 0x48, 0x70, 0x9A, 0xD9, 0x75, 0x78,
|
||||
0x71, 0xD1, 0x72, 0x43, 0x34, 0x75, 0x6E, 0x57, 0x59, 0xC2, 0x02, 0x5C,
|
||||
0x26, 0x60, 0x29, 0xCF, 0x23, 0x19, 0x16, 0x8E, 0x88, 0x43, 0xA5, 0xD4,
|
||||
0xE4, 0xCB, 0x08, 0xFB, 0x23, 0x11, 0x43, 0xE8, 0x43, 0x29, 0x72, 0x62,
|
||||
0xA1, 0xA9, 0x5D, 0x5E, 0x08, 0xD4, 0x90, 0xAE, 0xB8, 0xD8, 0xCE, 0x14,
|
||||
0xC2, 0xD0, 0x55, 0xF2, 0x86, 0xF6, 0xC4, 0x93, 0x43, 0x77, 0x66, 0x61,
|
||||
0xC0, 0xB9, 0xE8, 0x41, 0xD7, 0x97, 0x78, 0x60, 0x03, 0x6E, 0x4A, 0x72,
|
||||
0xAE, 0xA5, 0xD1, 0x7D, 0xBA, 0x10, 0x9E, 0x86, 0x6C, 0x1B, 0x8A, 0xB9,
|
||||
0x59, 0x33, 0xF8, 0xEB, 0xC4, 0x90, 0xBE, 0xF1, 0xB9
|
||||
};
|
||||
|
||||
const br_x509_certificate PROGMEM AmazonRootCA1_chain[] = {
|
||||
{ (unsigned char *)AmazonRootCA1, sizeof AmazonRootCA1 }
|
||||
};
|
||||
|
||||
#define AMAZONROOTCA1_LEN 1
|
||||
|
||||
#endif
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
sonoff_letsencrypt.h - TLS Lets Encrypt certificate for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
/*********************************************************************************************\
|
||||
* LetsEncrypt IdenTrust DST Root CA X3 certificate valid until 20210930
|
||||
*
|
||||
* https://letsencrypt.org/certificates/
|
||||
* Downloaded from https://www.identrust.com/support/downloads
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define MQTT_TLS_CA_CERT_LENGTH 846 // Letsencrypt
|
||||
#define MQTT_TLS_CA_CERT { \
|
||||
0x30, 0x82, 0x03, 0x4a, 0x30, 0x82, 0x02, 0x32, 0xa0, 0x03, 0x02, 0x01, \
|
||||
0x02, 0x02, 0x10, 0x44, 0xaf, 0xb0, 0x80, 0xd6, 0xa3, 0x27, 0xba, 0x89, \
|
||||
0x30, 0x39, 0x86, 0x2e, 0xf8, 0x40, 0x6b, 0x30, 0x0d, 0x06, 0x09, 0x2a, \
|
||||
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x3f, \
|
||||
0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, 0x44, \
|
||||
0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, \
|
||||
0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, \
|
||||
0x6f, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, \
|
||||
0x0e, 0x44, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, \
|
||||
0x20, 0x58, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x39, 0x33, \
|
||||
0x30, 0x32, 0x31, 0x31, 0x32, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x31, \
|
||||
0x30, 0x39, 0x33, 0x30, 0x31, 0x34, 0x30, 0x31, 0x31, 0x35, 0x5a, 0x30, \
|
||||
0x3f, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, \
|
||||
0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69, 0x67, 0x6e, \
|
||||
0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, \
|
||||
0x43, 0x6f, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, \
|
||||
0x13, 0x0e, 0x44, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, \
|
||||
0x41, 0x20, 0x58, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, \
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, \
|
||||
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, \
|
||||
0x00, 0xdf, 0xaf, 0xe9, 0x97, 0x50, 0x08, 0x83, 0x57, 0xb4, 0xcc, 0x62, \
|
||||
0x65, 0xf6, 0x90, 0x82, 0xec, 0xc7, 0xd3, 0x2c, 0x6b, 0x30, 0xca, 0x5b, \
|
||||
0xec, 0xd9, 0xc3, 0x7d, 0xc7, 0x40, 0xc1, 0x18, 0x14, 0x8b, 0xe0, 0xe8, \
|
||||
0x33, 0x76, 0x49, 0x2a, 0xe3, 0x3f, 0x21, 0x49, 0x93, 0xac, 0x4e, 0x0e, \
|
||||
0xaf, 0x3e, 0x48, 0xcb, 0x65, 0xee, 0xfc, 0xd3, 0x21, 0x0f, 0x65, 0xd2, \
|
||||
0x2a, 0xd9, 0x32, 0x8f, 0x8c, 0xe5, 0xf7, 0x77, 0xb0, 0x12, 0x7b, 0xb5, \
|
||||
0x95, 0xc0, 0x89, 0xa3, 0xa9, 0xba, 0xed, 0x73, 0x2e, 0x7a, 0x0c, 0x06, \
|
||||
0x32, 0x83, 0xa2, 0x7e, 0x8a, 0x14, 0x30, 0xcd, 0x11, 0xa0, 0xe1, 0x2a, \
|
||||
0x38, 0xb9, 0x79, 0x0a, 0x31, 0xfd, 0x50, 0xbd, 0x80, 0x65, 0xdf, 0xb7, \
|
||||
0x51, 0x63, 0x83, 0xc8, 0xe2, 0x88, 0x61, 0xea, 0x4b, 0x61, 0x81, 0xec, \
|
||||
0x52, 0x6b, 0xb9, 0xa2, 0xe2, 0x4b, 0x1a, 0x28, 0x9f, 0x48, 0xa3, 0x9e, \
|
||||
0x0c, 0xda, 0x09, 0x8e, 0x3e, 0x17, 0x2e, 0x1e, 0xdd, 0x20, 0xdf, 0x5b, \
|
||||
0xc6, 0x2a, 0x8a, 0xab, 0x2e, 0xbd, 0x70, 0xad, 0xc5, 0x0b, 0x1a, 0x25, \
|
||||
0x90, 0x74, 0x72, 0xc5, 0x7b, 0x6a, 0xab, 0x34, 0xd6, 0x30, 0x89, 0xff, \
|
||||
0xe5, 0x68, 0x13, 0x7b, 0x54, 0x0b, 0xc8, 0xd6, 0xae, 0xec, 0x5a, 0x9c, \
|
||||
0x92, 0x1e, 0x3d, 0x64, 0xb3, 0x8c, 0xc6, 0xdf, 0xbf, 0xc9, 0x41, 0x70, \
|
||||
0xec, 0x16, 0x72, 0xd5, 0x26, 0xec, 0x38, 0x55, 0x39, 0x43, 0xd0, 0xfc, \
|
||||
0xfd, 0x18, 0x5c, 0x40, 0xf1, 0x97, 0xeb, 0xd5, 0x9a, 0x9b, 0x8d, 0x1d, \
|
||||
0xba, 0xda, 0x25, 0xb9, 0xc6, 0xd8, 0xdf, 0xc1, 0x15, 0x02, 0x3a, 0xab, \
|
||||
0xda, 0x6e, 0xf1, 0x3e, 0x2e, 0xf5, 0x5c, 0x08, 0x9c, 0x3c, 0xd6, 0x83, \
|
||||
0x69, 0xe4, 0x10, 0x9b, 0x19, 0x2a, 0xb6, 0x29, 0x57, 0xe3, 0xe5, 0x3d, \
|
||||
0x9b, 0x9f, 0xf0, 0x02, 0x5d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, \
|
||||
0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, \
|
||||
0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, \
|
||||
0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, \
|
||||
0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc4, 0xa7, \
|
||||
0xb1, 0xa4, 0x7b, 0x2c, 0x71, 0xfa, 0xdb, 0xe1, 0x4b, 0x90, 0x75, 0xff, \
|
||||
0xc4, 0x15, 0x60, 0x85, 0x89, 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, \
|
||||
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, \
|
||||
0x01, 0x00, 0xa3, 0x1a, 0x2c, 0x9b, 0x17, 0x00, 0x5c, 0xa9, 0x1e, 0xee, \
|
||||
0x28, 0x66, 0x37, 0x3a, 0xbf, 0x83, 0xc7, 0x3f, 0x4b, 0xc3, 0x09, 0xa0, \
|
||||
0x95, 0x20, 0x5d, 0xe3, 0xd9, 0x59, 0x44, 0xd2, 0x3e, 0x0d, 0x3e, 0xbd, \
|
||||
0x8a, 0x4b, 0xa0, 0x74, 0x1f, 0xce, 0x10, 0x82, 0x9c, 0x74, 0x1a, 0x1d, \
|
||||
0x7e, 0x98, 0x1a, 0xdd, 0xcb, 0x13, 0x4b, 0xb3, 0x20, 0x44, 0xe4, 0x91, \
|
||||
0xe9, 0xcc, 0xfc, 0x7d, 0xa5, 0xdb, 0x6a, 0xe5, 0xfe, 0xe6, 0xfd, 0xe0, \
|
||||
0x4e, 0xdd, 0xb7, 0x00, 0x3a, 0xb5, 0x70, 0x49, 0xaf, 0xf2, 0xe5, 0xeb, \
|
||||
0x02, 0xf1, 0xd1, 0x02, 0x8b, 0x19, 0xcb, 0x94, 0x3a, 0x5e, 0x48, 0xc4, \
|
||||
0x18, 0x1e, 0x58, 0x19, 0x5f, 0x1e, 0x02, 0x5a, 0xf0, 0x0c, 0xf1, 0xb1, \
|
||||
0xad, 0xa9, 0xdc, 0x59, 0x86, 0x8b, 0x6e, 0xe9, 0x91, 0xf5, 0x86, 0xca, \
|
||||
0xfa, 0xb9, 0x66, 0x33, 0xaa, 0x59, 0x5b, 0xce, 0xe2, 0xa7, 0x16, 0x73, \
|
||||
0x47, 0xcb, 0x2b, 0xcc, 0x99, 0xb0, 0x37, 0x48, 0xcf, 0xe3, 0x56, 0x4b, \
|
||||
0xf5, 0xcf, 0x0f, 0x0c, 0x72, 0x32, 0x87, 0xc6, 0xf0, 0x44, 0xbb, 0x53, \
|
||||
0x72, 0x6d, 0x43, 0xf5, 0x26, 0x48, 0x9a, 0x52, 0x67, 0xb7, 0x58, 0xab, \
|
||||
0xfe, 0x67, 0x76, 0x71, 0x78, 0xdb, 0x0d, 0xa2, 0x56, 0x14, 0x13, 0x39, \
|
||||
0x24, 0x31, 0x85, 0xa2, 0xa8, 0x02, 0x5a, 0x30, 0x47, 0xe1, 0xdd, 0x50, \
|
||||
0x07, 0xbc, 0x02, 0x09, 0x90, 0x00, 0xeb, 0x64, 0x63, 0x60, 0x9b, 0x16, \
|
||||
0xbc, 0x88, 0xc9, 0x12, 0xe6, 0xd2, 0x7d, 0x91, 0x8b, 0xf9, 0x3d, 0x32, \
|
||||
0x8d, 0x65, 0xb4, 0xe9, 0x7c, 0xb1, 0x57, 0x76, 0xea, 0xc5, 0xb6, 0x28, \
|
||||
0x39, 0xbf, 0x15, 0x65, 0x1c, 0xc8, 0xf6, 0x77, 0x96, 0x6a, 0x0a, 0x8d, \
|
||||
0x77, 0x0b, 0xd8, 0x91, 0x0b, 0x04, 0x8e, 0x07, 0xdb, 0x29, 0xb6, 0x0a, \
|
||||
0xee, 0x9d, 0x82, 0x35, 0x35, 0x10 }
|
||||
|
||||
#endif // USE_MQTT_TLS_CA_CERT
|
|
@ -46,11 +46,21 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
|||
* Default global defines
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
#include <core_version.h>
|
||||
#ifndef ARDUINO_ESP8266_RELEASE_2_5_2
|
||||
#error "USE_MQTT_AWS_IOT is only supported on core version 2.5.2"
|
||||
// #ifdef USE_MQTT_AWS_IOT
|
||||
// #include <core_version.h>
|
||||
// #ifndef ARDUINO_ESP8266_RELEASE_2_5_2
|
||||
// #error "USE_MQTT_AWS_IOT is only supported on core version 2.5.2"
|
||||
// #endif
|
||||
// #endif
|
||||
|
||||
#ifdef USE_EMULATION_HUE
|
||||
#define USE_EMULATION
|
||||
#endif
|
||||
#ifdef USE_EMULATION_WEMO
|
||||
#define USE_EMULATION
|
||||
#endif
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
#define USE_MQTT_TLS
|
||||
#endif
|
||||
|
||||
#if defined(USE_MQTT_TLS) || defined(USE_MQTT_AWS_IOT)
|
||||
|
@ -59,11 +69,8 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
|||
const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog
|
||||
#endif
|
||||
|
||||
#ifdef USE_EMULATION_HUE
|
||||
#define USE_EMULATION
|
||||
#endif
|
||||
#ifdef USE_EMULATION_WEMO
|
||||
#define USE_EMULATION
|
||||
#if defined(USE_MQTT_TLS) && defined(ARDUINO_ESP8266_RELEASE_2_3_0)
|
||||
#error "TLS is no more supported on Core 2.3.0, use 2.4.2 or higher."
|
||||
#endif
|
||||
|
||||
#ifndef MODULE
|
||||
|
|
|
@ -1759,9 +1759,14 @@ void HandleInformation(void)
|
|||
}
|
||||
WSContentSend_P(PSTR("}1}2 ")); // Empty line
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_HOST "}2%s%s"), Settings.mqtt_user, Settings.mqtt_host);
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_PORT "}2%d"), Settings.mqtt_port);
|
||||
#else
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_HOST "}2%s"), Settings.mqtt_host);
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_PORT "}2%d"), Settings.mqtt_port);
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_USER "}2%s"), Settings.mqtt_user);
|
||||
#endif
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_CLIENT "}2%s"), mqtt_client);
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_TOPIC "}2%s"), Settings.mqtt_topic);
|
||||
WSContentSend_P(PSTR("}1" D_MQTT_GROUP_TOPIC "}2%s"), Settings.mqtt_grptopic);
|
||||
|
|
|
@ -20,13 +20,8 @@
|
|||
#define XDRV_02 2
|
||||
|
||||
#ifdef USE_MQTT_TLS
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
#include "sonoff_letsencrypt.h" // LetsEncrypt certificate
|
||||
#endif
|
||||
WiFiClientSecure EspClient; // Wifi Secure Client
|
||||
#elif defined(USE_MQTT_AWS_IOT)
|
||||
#include "WiFiClientSecureLightBearSSL.h"
|
||||
BearSSL::WiFiClientSecure_light *awsClient;
|
||||
BearSSL::WiFiClientSecure_light *tlsClient;
|
||||
#else
|
||||
WiFiClient EspClient; // Wifi Client
|
||||
#endif
|
||||
|
@ -49,13 +44,35 @@ uint8_t mqtt_initial_connection_state = 2; // MQTT connection messages state
|
|||
bool mqtt_connected = false; // MQTT virtual connection status
|
||||
bool mqtt_allowed = false; // MQTT enabled and parameters valid
|
||||
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
#ifdef USE_MQTT_TLS
|
||||
|
||||
|
||||
// see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c
|
||||
void to_hex(unsigned char * in, size_t insz, char * out, size_t outsz) {
|
||||
unsigned char * pin = in;
|
||||
static const char * hex = "0123456789ABCDEF";
|
||||
char * pout = out;
|
||||
for(; pin < in+insz; pout +=3, pin++){
|
||||
pout[0] = hex[(*pin>>4) & 0xF];
|
||||
pout[1] = hex[ *pin & 0xF];
|
||||
pout[2] = ' ';
|
||||
if (pout + 3 - out > outsz){
|
||||
/* Better to truncate output string than overflow buffer */
|
||||
/* it would be still better to either return a status */
|
||||
/* or ensure the target buffer is large enough and it never happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
pout[-1] = 0;
|
||||
}
|
||||
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
namespace aws_iot_privkey {
|
||||
// this is where the Private Key and Certificate are stored
|
||||
extern const br_ec_private_key *AWS_IoT_Private_Key;
|
||||
extern const br_x509_certificate *AWS_IoT_Client_Certificate;
|
||||
}
|
||||
#endif
|
||||
|
||||
// A typical AWS IoT endpoint is 50 characters long, it does not fit
|
||||
// in MqttHost field (32 chars). We need to concatenate both MqttUser and MqttHost
|
||||
|
@ -73,7 +90,7 @@ bool is_fingerprint_mono_value(uint8_t finger[20], uint8_t value) {
|
|||
return true;
|
||||
}
|
||||
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
#endif // USE_MQTT_TLS
|
||||
|
||||
/*********************************************************************************************\
|
||||
* MQTT driver specific code need to provide the following functions:
|
||||
|
@ -91,7 +108,7 @@ bool is_fingerprint_mono_value(uint8_t finger[20], uint8_t value) {
|
|||
#error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h, increase it to at least 1000"
|
||||
#endif
|
||||
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
#ifdef USE_MQTT_TLS
|
||||
PubSubClient MqttClient;
|
||||
#else
|
||||
PubSubClient MqttClient(EspClient);
|
||||
|
@ -99,24 +116,18 @@ PubSubClient MqttClient(EspClient);
|
|||
|
||||
|
||||
void MqttInit(void) {
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
AWS_endpoint[0] = 0;
|
||||
uint8_t len_user = strlen(Settings.mqtt_user);
|
||||
uint8_t len_host = strlen(Settings.mqtt_host);
|
||||
if (len_user > 0) {
|
||||
strcpy(AWS_endpoint, Settings.mqtt_user);
|
||||
if (('.' != AWS_endpoint[len_user-1]) && ('.' != Settings.mqtt_host[0])) {
|
||||
AWS_endpoint[len_user++] = '.';
|
||||
}
|
||||
strcpy(&AWS_endpoint[len_user], Settings.mqtt_host);
|
||||
}
|
||||
#ifdef USE_MQTT_TLS
|
||||
tlsClient = new BearSSL::WiFiClientSecure_light(1024,1024);
|
||||
|
||||
awsClient = new BearSSL::WiFiClientSecure_light(1024,1024);
|
||||
awsClient->setClientECCert(aws_iot_privkey::AWS_IoT_Client_Certificate,
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
snprintf(AWS_endpoint, sizeof(AWS_endpoint), PSTR("%s%s"), Settings.mqtt_user, Settings.mqtt_host);
|
||||
|
||||
tlsClient->setClientECCert(aws_iot_privkey::AWS_IoT_Client_Certificate,
|
||||
aws_iot_privkey::AWS_IoT_Private_Key,
|
||||
0xFFFF /* all usages, don't care */, 0);
|
||||
#endif
|
||||
|
||||
MqttClient.setClient(*awsClient);
|
||||
MqttClient.setClient(*tlsClient);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -411,67 +422,6 @@ void MqttConnected(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_MQTT_TLS
|
||||
bool MqttCheckTls(void)
|
||||
{
|
||||
char fingerprint1[60];
|
||||
char fingerprint2[60];
|
||||
bool result = false;
|
||||
|
||||
fingerprint1[0] = '\0';
|
||||
fingerprint2[0] = '\0';
|
||||
for (uint8_t i = 0; i < sizeof(Settings.mqtt_fingerprint[0]); i++) {
|
||||
snprintf_P(fingerprint1, sizeof(fingerprint1), PSTR("%s%s%02X"), fingerprint1, (i) ? " " : "", Settings.mqtt_fingerprint[0][i]);
|
||||
snprintf_P(fingerprint2, sizeof(fingerprint2), PSTR("%s%s%02X"), fingerprint2, (i) ? " " : "", Settings.mqtt_fingerprint[1][i]);
|
||||
}
|
||||
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_FINGERPRINT));
|
||||
|
||||
//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1
|
||||
EspClient = WiFiClientSecure(); // Wifi Secure Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
|
||||
//#endif
|
||||
|
||||
if (!EspClient.connect(Settings.mqtt_host, Settings.mqtt_port)) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT D_TLS_CONNECT_FAILED_TO " %s:%d. " D_RETRY_IN " %d " D_UNIT_SECOND), Settings.mqtt_host, Settings.mqtt_port, mqtt_retry_counter);
|
||||
} else {
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
unsigned char tls_ca_cert[] = MQTT_TLS_CA_CERT;
|
||||
if (EspClient.setCACert(tls_ca_cert, MQTT_TLS_CA_CERT_LENGTH)) {
|
||||
if (EspClient.verifyCertChain(Settings.mqtt_host)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "CA"));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (EspClient.verify(fingerprint1, Settings.mqtt_host)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "1"));
|
||||
result = true;
|
||||
}
|
||||
else if (EspClient.verify(fingerprint2, Settings.mqtt_host)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "2"));
|
||||
result = true;
|
||||
}
|
||||
#ifdef MDNS_HOSTNAME
|
||||
// If the hostname is set, check that as well.
|
||||
// This lets certs with the hostname for the CN be used.
|
||||
else if (EspClient.verify(fingerprint1, MDNS_HOSTNAME)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "1"));
|
||||
result = true;
|
||||
}
|
||||
else if (EspClient.verify(fingerprint2, MDNS_HOSTNAME)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "2"));
|
||||
result = true;
|
||||
}
|
||||
#endif // MDNS_HOSTNAME
|
||||
#endif // USE_MQTT_TLS_CA_CERT
|
||||
}
|
||||
if (!result) AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_FAILED));
|
||||
EspClient.stop();
|
||||
yield();
|
||||
return result;
|
||||
}
|
||||
#endif // USE_MQTT_TLS
|
||||
|
||||
void MqttReconnect(void)
|
||||
{
|
||||
char stopic[TOPSZ];
|
||||
|
@ -512,19 +462,13 @@ void MqttReconnect(void)
|
|||
|
||||
if (MqttClient.connected()) { MqttClient.disconnect(); }
|
||||
#ifdef USE_MQTT_TLS
|
||||
EspClient = WiFiClientSecure(); // Wifi Secure Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
|
||||
MqttClient.setClient(EspClient);
|
||||
#elif defined(USE_MQTT_AWS_IOT)
|
||||
awsClient->stop();
|
||||
tlsClient->stop();
|
||||
#else
|
||||
EspClient = WiFiClient(); // Wifi Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
|
||||
MqttClient.setClient(EspClient);
|
||||
#endif
|
||||
|
||||
if (2 == mqtt_initial_connection_state) { // Executed once just after power on and wifi is connected
|
||||
#ifdef USE_MQTT_TLS
|
||||
if (!MqttCheckTls()) return;
|
||||
#endif // USE_MQTT_TLS
|
||||
|
||||
mqtt_initial_connection_state = 1;
|
||||
}
|
||||
|
@ -535,17 +479,9 @@ void MqttReconnect(void)
|
|||
#else
|
||||
MqttClient.setServer(Settings.mqtt_host, Settings.mqtt_port);
|
||||
#endif
|
||||
/*
|
||||
// Skip MQTT host DNS lookup if not needed
|
||||
uint32_t current_hash = GetHash(Settings.mqtt_host, strlen(Settings.mqtt_host));
|
||||
if (mqtt_host_hash != current_hash) {
|
||||
mqtt_host_hash = current_hash;
|
||||
WiFi.hostByName(Settings.mqtt_host, mqtt_host_addr); // Skips DNS lookup if mqtt_host is IP address string as from mDns
|
||||
}
|
||||
MqttClient.setServer(mqtt_host_addr, Settings.mqtt_port);
|
||||
*/
|
||||
uint32_t time = millis();
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
|
||||
#ifdef USE_MQTT_TLS
|
||||
uint32_t mqtt_connect_time = millis();
|
||||
bool allow_all_fingerprints = false;
|
||||
bool learn_fingerprint1 = is_fingerprint_mono_value(Settings.mqtt_fingerprint[0], 0x00);
|
||||
bool learn_fingerprint2 = is_fingerprint_mono_value(Settings.mqtt_fingerprint[1], 0x00);
|
||||
|
@ -553,18 +489,29 @@ void MqttReconnect(void)
|
|||
allow_all_fingerprints |= is_fingerprint_mono_value(Settings.mqtt_fingerprint[1], 0xff);
|
||||
allow_all_fingerprints |= learn_fingerprint1;
|
||||
allow_all_fingerprints |= learn_fingerprint2;
|
||||
awsClient->setPubKeyFingerprint(Settings.mqtt_fingerprint[0], Settings.mqtt_fingerprint[1], allow_all_fingerprints);
|
||||
tlsClient->setPubKeyFingerprint(Settings.mqtt_fingerprint[0], Settings.mqtt_fingerprint[1], allow_all_fingerprints);
|
||||
#endif
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "AWS IoT endpoint: %s"), AWS_endpoint);
|
||||
if (MqttClient.connect(mqtt_client, mqtt_user, mqtt_pwd, nullptr, 0, false, nullptr)) {
|
||||
//if (MqttClient.connect(mqtt_client, nullptr, nullptr, nullptr, 0, false, nullptr)) {
|
||||
if (MqttClient.connect(mqtt_client, nullptr, nullptr, stopic, 1, false, mqtt_data, MQTT_CLEAN_SESSION)) {
|
||||
#else
|
||||
if (MqttClient.connect(mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, true, mqtt_data, MQTT_CLEAN_SESSION)) {
|
||||
#endif
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "AWS IoT connected in %d ms"), millis() - time);
|
||||
#ifdef USE_MQTT_TLS
|
||||
// create a printable version of the fingerprint received
|
||||
char buf_fingerprint[64];
|
||||
to_hex((unsigned char *)tlsClient->getRecvPubKeyFingerprint(), 20, buf_fingerprint, 64);
|
||||
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connected in %d ms"), millis() - mqtt_connect_time);
|
||||
if (!tlsClient->getMFLNStatus()) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR("MFLN not supported by TLS server"));
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "Server fingerprint: %s"), buf_fingerprint);
|
||||
if (learn_fingerprint1 || learn_fingerprint2) {
|
||||
// we potentially need to learn the fingerprint just seen
|
||||
bool fingerprint_matched = false;
|
||||
const uint8_t *recv_fingerprint = awsClient->getRecvPubKeyFingerprint();
|
||||
const uint8_t *recv_fingerprint = tlsClient->getRecvPubKeyFingerprint();
|
||||
if (0 == memcmp(recv_fingerprint, Settings.mqtt_fingerprint[0], 20)) {
|
||||
fingerprint_matched = true;
|
||||
}
|
||||
|
@ -579,14 +526,16 @@ void MqttReconnect(void)
|
|||
if (learn_fingerprint2) {
|
||||
memcpy(Settings.mqtt_fingerprint[1], recv_fingerprint, 20);
|
||||
}
|
||||
restart_flag = 2; // save and restart
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Fingerprint learned: %s"), buf_fingerprint);
|
||||
|
||||
SettingsSaveAll(); // save settings
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // USE_MQTT_TLS
|
||||
MqttConnected();
|
||||
} else {
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "AWS IoT connection error: %d"), awsClient->getLastError());
|
||||
#ifdef USE_MQTT_TLS
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connection error: %d"), tlsClient->getLastError());
|
||||
#endif
|
||||
MqttDisconnected(MqttClient.state()); // status codes are documented here http://pubsubclient.knolleary.net/api.html#state
|
||||
}
|
||||
|
@ -618,6 +567,20 @@ void MqttCheck(void)
|
|||
|
||||
/*********************************************************************************************/
|
||||
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
void setLongMqttHost(const char *mqtt_host) {
|
||||
if (strlen(mqtt_host) <= sizeof(Settings.mqtt_host)) {
|
||||
strlcpy(Settings.mqtt_host, mqtt_host, sizeof(Settings.mqtt_host));
|
||||
Settings.mqtt_user[0] = 0;
|
||||
} else {
|
||||
// need to split in mqtt_user first then mqtt_host
|
||||
strlcpy(Settings.mqtt_user, mqtt_host, sizeof(Settings.mqtt_user));
|
||||
strlcpy(Settings.mqtt_host, &mqtt_host[sizeof(Settings.mqtt_user)-1], sizeof(Settings.mqtt_host));
|
||||
}
|
||||
strlcpy(AWS_endpoint, mqtt_host, sizeof(AWS_endpoint));
|
||||
}
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
|
||||
bool MqttCommand(void)
|
||||
{
|
||||
char command [CMDSZ];
|
||||
|
@ -639,11 +602,19 @@ bool MqttCommand(void)
|
|||
serviced = false; // Unknown command
|
||||
}
|
||||
else if (CMND_MQTTHOST == command_code) {
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
if ((data_len > 0) && (data_len <= sizeof(Settings.mqtt_host) + sizeof(Settings.mqtt_user) - 2)) {
|
||||
setLongMqttHost((SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_HOST : dataBuf);
|
||||
restart_flag = 2;
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, AWS_endpoint);
|
||||
#else
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_host))) {
|
||||
strlcpy(Settings.mqtt_host, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_HOST : dataBuf, sizeof(Settings.mqtt_host));
|
||||
restart_flag = 2;
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_host);
|
||||
#endif
|
||||
}
|
||||
else if (CMND_MQTTPORT == command_code) {
|
||||
if (payload16 > 0) {
|
||||
|
@ -668,7 +639,7 @@ bool MqttCommand(void)
|
|||
}
|
||||
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(index -1));
|
||||
}
|
||||
#if defined(USE_MQTT_TLS) || defined(USE_MQTT_AWS_IOT)
|
||||
#ifdef USE_MQTT_TLS
|
||||
else if ((CMND_MQTTFINGERPRINT == command_code) && (index > 0) && (index <= 2)) {
|
||||
char fingerprint[60];
|
||||
if ((data_len > 0) && (data_len < sizeof(fingerprint))) {
|
||||
|
@ -693,6 +664,7 @@ bool MqttCommand(void)
|
|||
}
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_client);
|
||||
}
|
||||
#ifndef USE_MQTT_AWS_IOT // user and password are diabled with AWS IoT
|
||||
else if (CMND_MQTTUSER == command_code) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_user))) {
|
||||
strlcpy(Settings.mqtt_user, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_USER : dataBuf, sizeof(Settings.mqtt_user));
|
||||
|
@ -709,6 +681,7 @@ bool MqttCommand(void)
|
|||
Response_P(S_JSON_COMMAND_ASTERIX, command);
|
||||
}
|
||||
}
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
else if (CMND_FULLTOPIC == command_code) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_fulltopic))) {
|
||||
MakeValidMqtt(1, dataBuf);
|
||||
|
@ -869,8 +842,10 @@ const char HTTP_FORM_MQTT1[] PROGMEM =
|
|||
"<p><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br><input id='ml' placeholder='" STR(MQTT_PORT) "' value='%d'></p>"
|
||||
"<p><b>" D_CLIENT "</b> (%s)<br><input id='mc' placeholder='%s' value='%s'></p>";
|
||||
const char HTTP_FORM_MQTT2[] PROGMEM =
|
||||
#ifndef USE_MQTT_AWS_IOT // user and password disabled with AWS IoT
|
||||
"<p><b>" D_USER "</b> (" MQTT_USER ")<br><input id='mu' placeholder='" MQTT_USER "' value='%s'></p>"
|
||||
"<p><b>" D_PASSWORD "</b><br><input id='mp' type='password' placeholder='" D_PASSWORD "' value='" D_ASTERISK_PWD "'></p>"
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
"<p><b>" D_TOPIC "</b> = %%topic%% (%s)<br><input id='mt' placeholder='%s' value='%s'></p>"
|
||||
"<p><b>" D_FULL_TOPIC "</b> (%s)<br><input id='mf' placeholder='%s' value='%s'></p>";
|
||||
|
||||
|
@ -891,7 +866,11 @@ void HandleMqttConfiguration(void)
|
|||
WSContentStart_P(S_CONFIGURE_MQTT);
|
||||
WSContentSendStyle();
|
||||
WSContentSend_P(HTTP_FORM_MQTT1,
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
AWS_endpoint,
|
||||
#else
|
||||
Settings.mqtt_host,
|
||||
#endif
|
||||
Settings.mqtt_port,
|
||||
Format(str, MQTT_CLIENT_ID, sizeof(str)), MQTT_CLIENT_ID, Settings.mqtt_client);
|
||||
WSContentSend_P(HTTP_FORM_MQTT2,
|
||||
|
@ -922,17 +901,26 @@ void MqttSaveSettings(void)
|
|||
strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic));
|
||||
strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic));
|
||||
WebGetArg("mh", tmp, sizeof(tmp));
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
setLongMqttHost((!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp);
|
||||
#else
|
||||
strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host));
|
||||
#endif
|
||||
WebGetArg("ml", tmp, sizeof(tmp));
|
||||
Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp);
|
||||
WebGetArg("mc", tmp, sizeof(tmp));
|
||||
strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client));
|
||||
#ifndef USE_MQTT_AWS_IOT
|
||||
WebGetArg("mu", tmp, sizeof(tmp));
|
||||
strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user));
|
||||
WebGetArg("mp", tmp, sizeof(tmp));
|
||||
strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? "" : (!strcmp(tmp, D_ASTERISK_PWD)) ? Settings.mqtt_pwd : tmp, sizeof(Settings.mqtt_pwd));
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"),
|
||||
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_topic, Settings.mqtt_fulltopic);
|
||||
#else // USE_MQTT_AWS_IOT
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"),
|
||||
AWS_endpoint, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_topic, Settings.mqtt_fulltopic);
|
||||
#endif
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
|
@ -946,7 +934,7 @@ bool Xdrv02(uint8_t function)
|
|||
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
switch (function) {
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
#ifdef USE_MQTT_TLS
|
||||
case FUNC_PRE_INIT:
|
||||
MqttInit();
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue