Refactored TLS based on BearSSL - cleaned

This commit is contained in:
Stephan Hadinger 2019-06-10 12:06:03 +02:00
parent 09dcb93489
commit 006462f17e
27 changed files with 15498 additions and 273 deletions

170
include/bearssl/bearssl.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"));
}

236
sonoff/sonoff_ca.ino Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1759,9 +1759,14 @@ void HandleInformation(void)
}
WSContentSend_P(PSTR("}1}2&nbsp;")); // 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);

View File

@ -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;