Add WiFiClientSecure and WifiServerSecure (TLS) support, NTP (#683)
* Add TLS (https) support * Add NTP server * Clean up include path, add BearSSL headers * Allow 2 NTP servers, add ESP8266 compat define * Add MFLN SSL example, free/used/total heap getters * Enable stack thunking * Add tested SSL examples * Add BSSL_validation demo * Add Client Certificate example * Add RP2040 helper docs * Clean up doc errors, missing doc version info * Add WiFiClientSecure documentation * Add NTP docs Fixes #679
This commit is contained in:
parent
53cecae109
commit
c3a580ee89
88 changed files with 21977 additions and 43 deletions
4
.github/workflows/pull-request.yml
vendored
4
.github/workflows/pull-request.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
- name: Run codespell
|
- name: Run codespell
|
||||||
uses: codespell-project/actions-codespell@master
|
uses: codespell-project/actions-codespell@master
|
||||||
with:
|
with:
|
||||||
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS
|
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server
|
||||||
ignore_words_list: ser,dout
|
ignore_words_list: ser,dout
|
||||||
|
|
||||||
# Consistent style
|
# Consistent style
|
||||||
|
|
@ -211,4 +211,4 @@ jobs:
|
||||||
- name: Build Fade Example
|
- name: Build Fade Example
|
||||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
|
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
|
||||||
- name: Build TinyUSB Example
|
- name: Build TinyUSB Example
|
||||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
|
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
|
||||||
|
|
|
||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -25,3 +25,6 @@
|
||||||
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
|
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
|
||||||
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
|
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
|
||||||
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
|
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
|
||||||
|
[submodule "tools/libbearssl/bearssl"]
|
||||||
|
path = tools/libbearssl/bearssl
|
||||||
|
url = https://github.com/earlephilhower/bearssl-esp8266.git
|
||||||
|
|
|
||||||
290
cores/rp2040/PolledTimeout.h
Normal file
290
cores/rp2040/PolledTimeout.h
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
PolledTimeout.h - Encapsulation of a polled Timeout
|
||||||
|
|
||||||
|
Copyright (c) 2018 Daniel Salazar. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits> // std::numeric_limits
|
||||||
|
#include <type_traits> // std::is_unsigned
|
||||||
|
|
||||||
|
#define IRAM_ATTR
|
||||||
|
|
||||||
|
namespace esp8266 {
|
||||||
|
|
||||||
|
|
||||||
|
namespace polledTimeout {
|
||||||
|
|
||||||
|
namespace YieldPolicy {
|
||||||
|
|
||||||
|
struct DoNothing {
|
||||||
|
static void execute() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct YieldOrSkip {
|
||||||
|
static void execute() {} //{esp_yield();}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <unsigned long delayMs>
|
||||||
|
struct YieldAndDelayMs {
|
||||||
|
static void execute() {
|
||||||
|
delay(delayMs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} //YieldPolicy
|
||||||
|
|
||||||
|
namespace TimePolicy {
|
||||||
|
|
||||||
|
struct TimeSourceMillis {
|
||||||
|
// time policy in milli-seconds based on millis()
|
||||||
|
|
||||||
|
using timeType = decltype(millis());
|
||||||
|
static timeType time() {
|
||||||
|
return millis();
|
||||||
|
}
|
||||||
|
static constexpr timeType ticksPerSecond = 1000;
|
||||||
|
static constexpr timeType ticksPerSecondMax = 1000;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TimeSourceCycles {
|
||||||
|
// time policy based on esp_get_cycle_count()
|
||||||
|
// this particular time measurement is intended to be called very often
|
||||||
|
// (every loop, every yield)
|
||||||
|
|
||||||
|
using timeType = decltype(rp2040.getCycleCount());
|
||||||
|
static timeType time() {
|
||||||
|
return rp2040.getCycleCount();
|
||||||
|
}
|
||||||
|
static constexpr timeType ticksPerSecond = F_CPU;
|
||||||
|
static constexpr timeType ticksPerSecondMax = F_CPU;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TimeSourceType, unsigned long long second_th>
|
||||||
|
// "second_th" units of timeType for one second
|
||||||
|
struct TimeUnit {
|
||||||
|
using timeType = typename TimeSourceType::timeType;
|
||||||
|
|
||||||
|
#if __GNUC__ < 5
|
||||||
|
// gcc-4.8 cannot compile the constexpr-only version of this function
|
||||||
|
// using #defines instead luckily works
|
||||||
|
static constexpr timeType computeRangeCompensation() {
|
||||||
|
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
|
||||||
|
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
|
||||||
|
|
||||||
|
return ({
|
||||||
|
fractional == 0 ?
|
||||||
|
1 : // no need for compensation
|
||||||
|
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
||||||
|
});
|
||||||
|
|
||||||
|
#undef number_of_secondTh_in_one_tick
|
||||||
|
#undef fractional
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static constexpr timeType computeRangeCompensation() {
|
||||||
|
return ({
|
||||||
|
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
|
||||||
|
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
|
||||||
|
fractional == 0 ?
|
||||||
|
1 : // no need for compensation
|
||||||
|
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
|
||||||
|
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
|
||||||
|
static constexpr timeType rangeCompensate = computeRangeCompensation();
|
||||||
|
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
|
||||||
|
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
|
||||||
|
static constexpr timeType user2UnitDivider = rangeCompensate;
|
||||||
|
// std::numeric_limits<timeType>::max() is reserved
|
||||||
|
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
|
||||||
|
|
||||||
|
static timeType toTimeTypeUnit(const timeType userUnit) {
|
||||||
|
return (userUnit * user2UnitMultiplier) / user2UnitDivider;
|
||||||
|
}
|
||||||
|
static timeType toUserUnit(const timeType internalUnit) {
|
||||||
|
return (internalUnit * user2UnitDivider) / user2UnitMultiplier;
|
||||||
|
}
|
||||||
|
static timeType time() {
|
||||||
|
return TimeSourceType::time();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >;
|
||||||
|
using TimeFastMillis = TimeUnit< TimeSourceCycles, 1000 >;
|
||||||
|
using TimeFastMicros = TimeUnit< TimeSourceCycles, 1000000 >;
|
||||||
|
using TimeFastNanos = TimeUnit< TimeSourceCycles, 1000000000 >;
|
||||||
|
|
||||||
|
} //TimePolicy
|
||||||
|
|
||||||
|
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
|
||||||
|
class timeoutTemplate {
|
||||||
|
public:
|
||||||
|
using timeType = typename TimePolicyT::timeType;
|
||||||
|
static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
|
||||||
|
|
||||||
|
static constexpr timeType alwaysExpired = 0;
|
||||||
|
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
|
||||||
|
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
|
||||||
|
|
||||||
|
timeoutTemplate(const timeType userTimeout) {
|
||||||
|
reset(userTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool expired() {
|
||||||
|
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
|
||||||
|
if (PeriodicT) { //in case of false: gets optimized away
|
||||||
|
return expiredRetrigger();
|
||||||
|
}
|
||||||
|
return expiredOneShot();
|
||||||
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
operator bool() {
|
||||||
|
return expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canExpire() const {
|
||||||
|
return !_neverExpires;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canWait() const {
|
||||||
|
return _timeout != alwaysExpired;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets, will trigger after this new timeout.
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void reset(const timeType newUserTimeout) {
|
||||||
|
reset();
|
||||||
|
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
|
||||||
|
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets, will trigger after the timeout previously set.
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void reset() {
|
||||||
|
_start = TimePolicyT::time();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets to just expired so that on next poll the check will immediately trigger for the user,
|
||||||
|
// also change timeout (after next immediate trigger).
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void resetAndSetExpired(const timeType newUserTimeout) {
|
||||||
|
reset(newUserTimeout);
|
||||||
|
_start -= _timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets to just expired so that on next poll the check will immediately trigger for the user.
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void resetAndSetExpired() {
|
||||||
|
reset();
|
||||||
|
_start -= _timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetToNeverExpires() {
|
||||||
|
_timeout = alwaysExpired + 1; // because canWait() has precedence
|
||||||
|
_neverExpires = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType getTimeout() const {
|
||||||
|
return TimePolicyT::toUserUnit(_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr timeType timeMax() {
|
||||||
|
return TimePolicyT::timeMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool checkExpired(const timeType internalUnit) const {
|
||||||
|
// canWait() is not checked here
|
||||||
|
// returns "can expire" and "time expired"
|
||||||
|
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool expiredRetrigger() {
|
||||||
|
if (!canWait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType current = TimePolicyT::time();
|
||||||
|
if (checkExpired(current)) {
|
||||||
|
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
|
||||||
|
_start += n * _timeout;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool expiredOneShot() const {
|
||||||
|
// returns "always expired" or "has expired"
|
||||||
|
return !canWait() || checkExpired(TimePolicyT::time());
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType _timeout;
|
||||||
|
timeType _start;
|
||||||
|
bool _neverExpires;
|
||||||
|
};
|
||||||
|
|
||||||
|
// legacy type names, deprecated (unit is milliseconds)
|
||||||
|
|
||||||
|
using oneShot = polledTimeout::timeoutTemplate<false> /*__attribute__((deprecated("use oneShotMs")))*/;
|
||||||
|
using periodic = polledTimeout::timeoutTemplate<true> /*__attribute__((deprecated("use periodicMs")))*/;
|
||||||
|
|
||||||
|
// standard versions (based on millis())
|
||||||
|
// timeMax() is 49.7 days ((2^32)-2 ms)
|
||||||
|
|
||||||
|
using oneShotMs = polledTimeout::timeoutTemplate<false>;
|
||||||
|
using periodicMs = polledTimeout::timeoutTemplate<true>;
|
||||||
|
|
||||||
|
// Time policy based on esp_get_cycle_count(), and intended to be called very often:
|
||||||
|
// "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%)
|
||||||
|
// (cpu cycles for ::expired(): 372 (millis()) vs 52 (esp_get_cycle_count()))
|
||||||
|
// timeMax() values:
|
||||||
|
// Ms: max is 26843 ms (26.8 s)
|
||||||
|
// Us: max is 26843545 us (26.8 s)
|
||||||
|
// Ns: max is 1073741823 ns ( 1.07 s)
|
||||||
|
// (time policy based on esp_get_cycle_count() is intended to be called very often)
|
||||||
|
|
||||||
|
using oneShotFastMs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
|
||||||
|
using periodicFastMs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
|
||||||
|
using oneShotFastUs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
|
||||||
|
using periodicFastUs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
|
||||||
|
using oneShotFastNs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
|
||||||
|
using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
|
||||||
|
|
||||||
|
} //polledTimeout
|
||||||
|
|
||||||
|
|
||||||
|
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
|
||||||
|
using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
|
||||||
|
|
||||||
|
Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}//esp8266
|
||||||
|
|
@ -22,12 +22,13 @@
|
||||||
#include <hardware/irq.h>
|
#include <hardware/irq.h>
|
||||||
#include <hardware/pio.h>
|
#include <hardware/pio.h>
|
||||||
#include <hardware/exception.h>
|
#include <hardware/exception.h>
|
||||||
|
#include <hardware/structs/rosc.h>
|
||||||
#include <hardware/structs/systick.h>
|
#include <hardware/structs/systick.h>
|
||||||
#include <pico/multicore.h>
|
#include <pico/multicore.h>
|
||||||
#include <pico/util/queue.h>
|
#include <pico/util/queue.h>
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
#include "ccount.pio.h"
|
#include "ccount.pio.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
extern "C" volatile bool __otherCoreIdled;
|
extern "C" volatile bool __otherCoreIdled;
|
||||||
|
|
||||||
|
|
@ -141,6 +142,9 @@ extern RP2040 rp2040;
|
||||||
extern "C" void main1();
|
extern "C" void main1();
|
||||||
class PIOProgram;
|
class PIOProgram;
|
||||||
|
|
||||||
|
extern "C" char __StackLimit;
|
||||||
|
extern "C" char __bss_end__;
|
||||||
|
|
||||||
// Wrapper class for PIO programs, abstracting common operations out
|
// Wrapper class for PIO programs, abstracting common operations out
|
||||||
// TODO - Add unload/destructor
|
// TODO - Add unload/destructor
|
||||||
class PIOProgram {
|
class PIOProgram {
|
||||||
|
|
@ -257,6 +261,19 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int getFreeHeap() {
|
||||||
|
return getTotalHeap() - getUsedHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int getUsedHeap() {
|
||||||
|
struct mallinfo m = mallinfo();
|
||||||
|
return m.uordblks;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int getTotalHeap() {
|
||||||
|
return &__StackLimit - &__bss_end__;
|
||||||
|
}
|
||||||
|
|
||||||
void idleOtherCore() {
|
void idleOtherCore() {
|
||||||
fifo.idleOtherCore();
|
fifo.idleOtherCore();
|
||||||
}
|
}
|
||||||
|
|
@ -274,6 +291,29 @@ public:
|
||||||
// Multicore comms FIFO
|
// Multicore comms FIFO
|
||||||
_MFIFO fifo;
|
_MFIFO fifo;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO - Not so great HW random generator. 32-bits wide. Cryptographers somewhere are crying
|
||||||
|
uint32_t hwrand32() {
|
||||||
|
// Try and whiten the HW ROSC bit
|
||||||
|
uint32_t r = 0;
|
||||||
|
for (int k = 0; k < 32; k++) {
|
||||||
|
unsigned long int b;
|
||||||
|
do {
|
||||||
|
b = rosc_hw->randombit & 1;
|
||||||
|
if (b != (rosc_hw->randombit & 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
r <<= 1;
|
||||||
|
r |= b;
|
||||||
|
}
|
||||||
|
// Stir using the cycle count LSBs. In any WiFi use case this will be a random # since the connection time is not cycle-accurate
|
||||||
|
uint64_t rr = (((uint64_t)~r) << 32LL) | r;
|
||||||
|
rr >>= rp2040.getCycleCount() & 32LL;
|
||||||
|
|
||||||
|
return (uint32_t)rr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _SystickHandler() {
|
static void _SystickHandler() {
|
||||||
rp2040._epoch += 1LL << 24;
|
rp2040._epoch += 1LL << 24;
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,13 @@ extern "C" int settimeofday(const struct timeval *tv, const struct timezone *tz)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For NTP
|
||||||
|
extern "C" void __setSystemTime(unsigned long long sec, unsigned long usec) {
|
||||||
|
uint64_t now_us = to_us_since_boot(get_absolute_time());
|
||||||
|
uint64_t newnow_us = sec * 1000000LL + usec;
|
||||||
|
__timedelta_us = newnow_us - now_us;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" int _isatty(int file) {
|
extern "C" int _isatty(int file) {
|
||||||
(void) file;
|
(void) file;
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
|
|
|
||||||
119
docs/bearssl-client-secure-class.rst
Normal file
119
docs/bearssl-client-secure-class.rst
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
:orphan:
|
||||||
|
|
||||||
|
WiFiClientSecure Class
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
`BearSSL::WiFiClientSecure` is the object which actually handles TLS encrypted WiFi connections to a remote server or client. It extends `WiFiClient` and so can be used with minimal changes to code that does unsecured communications.
|
||||||
|
|
||||||
|
Validating X509 Certificates (Am I talking to the server I think I'm talking to?)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Prior to connecting to a server, the `BearSSL::WiFiClientSecure` needs to be told how to verify the identity of the other machine. **By default BearSSL will not validate any connections and will refuse to connect to any server.**
|
||||||
|
|
||||||
|
There are multiple modes to tell BearSSL how to verify the identity of the remote server. See the `BearSSL_Validation` example for real uses of the following methods:
|
||||||
|
|
||||||
|
setInsecure()
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Don't verify any X509 certificates. There is no guarantee that the server connected to is the one you think it is in this case.
|
||||||
|
|
||||||
|
setKnownKey(const BearSSL::PublicKey \*pk)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Assume the server is using the specific public key. This does not verify the identity of the server or the X509 certificate it sends, it simply assumes that its public key is the one given. If the server updates its public key at a later point then connections will fail.
|
||||||
|
|
||||||
|
setFingerprint(const uint8_t fp[20]) / setFingerprint(const char \*fpStr)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Verify the SHA1 fingerprint of the certificate returned matches this one. If the server certificate changes, it will fail. If an array of 20 bytes are sent in, it is assumed they are the binary SHA1 values. If a `char*` string is passed in, it is parsed as a series of human-readable hex values separated by spaces or colons (e.g. `setFingerprint("00:01:02:03:...:1f");`)
|
||||||
|
|
||||||
|
This fingerprint is calculated on the raw X509 certificate served by the server. In very rare cases, these certificates have certain encodings which should be normalized before taking a fingerprint (but in order to preserve memory BearSSL does not do this normalization since it would need RAM for an entire copy of the cert), and the fingerprint BearSSL calculates will not match the fingerprint OpenSSL calculates. In this case, you can enable SSL debugging and get a dump of BearSSL's calculated fingerprint and use that one in your code, or use full certificate validation. See the `original issue and debug here <https://github.com/esp8266/Arduino/issues/6209>`__.
|
||||||
|
|
||||||
|
setTrustAnchors(BearSSL::X509List \*ta)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Use the passed-in certificate(s) as a trust anchor, accepting remote certificates signed by any of these. If you have many trust anchors it may make sense to use a `BearSSL::CertStore` because it will only require RAM for a single trust anchor (while the `setTrustAnchors` call requires memory for all certificates in the list).
|
||||||
|
|
||||||
|
setX509Time(time_t now)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
For `setTrustAnchors` and `CertStore` , the current time (set via SNTP) is used to verify the certificate against the list, so SNTP must be enabled and functioning before the connection is attempted. If you cannot use SNTP for some reason, you can manually set the "present time" that BearSSL will use to validate a certificate with this call where `now` is standard UNIX time.
|
||||||
|
|
||||||
|
Client Certificates (Proving I'm who I say I am to the server)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
TLS servers can request that a client identify themselves with an X509 certificate signed by a trust anchor it honors (i.e. a global TA or a private CA). This is commonly done for applications like MQTT. By default the client doesn't send a certificate, and in cases where a certificate is required the server will disconnect and no connection will be possible.
|
||||||
|
|
||||||
|
setClientRSACert / setClientECCert
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Sets a client certificate to send to a TLS server that requests one. It should be called before `connect()` to add a certificate to the client in case the server requests it. Note that certificates include both a certificate and a private key. Both should be provided to you by your certificate generator. Elliptic Curve (EC) keys require additional information, as shown in the prototype.
|
||||||
|
|
||||||
|
MFLN or Maximum Fragment Length Negotiation (Saving RAM)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Because TLS was developed on systems with many megabytes of memory, they require by default a 16KB buffer for receive and transmit. That's enormous for the ESP8266, which has only around 40KB total heap available.
|
||||||
|
|
||||||
|
We can (and do) minimize the transmission buffer down to slightly more than 512 bytes to save memory, since BearSSL can internally ensure transmissions larger than that are broken up into smaller chunks that do fit. But that still leaves the 16KB receive buffer requirement since we cannot in general guarantee the TLS peer will send in smaller chunks.
|
||||||
|
|
||||||
|
TLS 1.2 added MFLN, which lets a client negotiate smaller buffers with a server and reduce the memory requirements on the ESP8266. Unfortunately, BearSSL needs to know the buffer sizes before it begins connection, so applications that want to use smaller buffers need to check the remote server's support before `connect()` .
|
||||||
|
|
||||||
|
probeMaxFragmentLength(host, port, len)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Use one of these calls **before** connection to determine if a specific fragment length is supported (len must be a power of two from 512 to 4096, per the specification). This does **not** initiate a SSL connection, it simply opens a TCP port and performs a trial handshake to check support.
|
||||||
|
|
||||||
|
setBufferSizes(int recv, int xmit)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Once you have verified (or know beforehand) that MFLN is supported you can use this call to set the size of memory buffers allocated by the connection object. This must be called **before** `connect()` or it will be ignored.
|
||||||
|
|
||||||
|
In certain applications where the TLS server does not support MFLN (not many do as of this writing as it is relatively new to OpenSSL), but you control both the ESP8266 and the server to which it is communicating, you may still be able to `setBufferSizes()` smaller if you guarantee no chunk of data will overflow those buffers.
|
||||||
|
|
||||||
|
bool getMFLNStatus()
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
After a successful connection, this method returns whether or not MFLN negotiation succeeded or not. If it did not succeed, and you reduced the receive buffer with `setBufferSizes` then you may experience reception errors if the server attempts to send messages larger than your receive buffer.
|
||||||
|
|
||||||
|
Sessions (Resuming connections fast)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
setSession(BearSSL::Session &sess)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
If you are connecting to a server repeatedly in a fixed time period (usually 30 or 60 minutes, but normally configurable at the server), a TLS session can be used to cache crypto settings and speed up connections significantly.
|
||||||
|
|
||||||
|
Errors
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
BearSSL can fail in many more unique and interesting ways. Use these calls to get more information when something fails.
|
||||||
|
|
||||||
|
getLastSSLError(char \*dest = NULL, size_t len = 0)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Returns the last BearSSL error code encountered and optionally set a user-allocated buffer to a human-readable form of the error. To only get the last error integer code, just call without any parameters (`int errCode = getLastSSLError();`).
|
||||||
|
|
||||||
|
Limiting Ciphers (New connections faster)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
There is very rarely reason to use these calls, but they are available.
|
||||||
|
|
||||||
|
setCiphers()
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Takes an array (in PROGMEM is valid) or a std::vector of 16-bit BearSSL cipher identifiers and restricts BearSSL to only use them. If the server requires a different cipher, then connection will fail. Generally this is not useful except in cases where you want to connect to servers using a specific cipher. See the BearSSL headers for more information on the supported ciphers.
|
||||||
|
|
||||||
|
setCiphersLessSecure()
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Helper function which essentially limits BearSSL to less secure ciphers than it would natively choose, but they may be helpful and faster if your server depended on specific crypto options.
|
||||||
|
|
||||||
|
Limiting TLS(SSL) Versions
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
By default, BearSSL will connect with TLS 1.0, TLS 1.1, or TLS 1.2 protocols (depending on the request of the remote side). If you want to limit to a subset, use the following call:
|
||||||
|
|
||||||
|
setSSLVersion(uint32_t min, uint32_t max)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Valid values for min and max are `BR_TLS10`, `BR_TLS11`, `BR_TLS12`. Min and max may be set to the same value if only a single TLS version is desired.
|
||||||
64
docs/bearssl-server-secure-class.rst
Normal file
64
docs/bearssl-server-secure-class.rst
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
:orphan:
|
||||||
|
|
||||||
|
WiFiServerSecure Class
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Implements a TLS encrypted server with optional client certificate validation. See `Server Class <server-class.rst>`__ for general information and `BearSSL Secure Client Class <bearssl-client-secure-class.rst>`__ for basic server and BearSSL concepts.
|
||||||
|
|
||||||
|
setBufferSizes(int recv, int xmit)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Similar to the `BearSSL::WiFiClientSecure` method, sets the receive and transmit buffer sizes. Note that servers cannot request a buffer size from the client, so if these are shrunk and the client tries to send a chunk larger than the receive buffer, it will always fail. Needs to be called before `begin()`
|
||||||
|
|
||||||
|
Setting Server Certificates
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
TLS servers require a certificate identifying itself and containing its public key, and a private key they will use to encrypt information with. The application author is responsible for generating this certificate and key, either using a self-signed generator or using a commercial certification authority. **Do not re-use the certificates included in the examples provided.**
|
||||||
|
|
||||||
|
This example command will generate a RSA 2048-bit key and certificate:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days 4096
|
||||||
|
|
||||||
|
Again, it is up to the application author to generate this certificate and key and keep the private key safe and **private.**
|
||||||
|
|
||||||
|
setRSACert(const BearSSL::X509List \*chain, const BearSSL::PrivateKey \*sk)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Sets a RSA certificate and key to be used by the server when connections are received. Needs to be called before `begin()`
|
||||||
|
|
||||||
|
setECCert(const BearSSL::X509List \*chain, unsigned cert_issuer_key_type, const BearSSL::PrivateKey \*sk)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Sets an elliptic curve certificate and key for the server. Needs to be called before `begin()`.
|
||||||
|
|
||||||
|
Client sessions (Resuming connections fast)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The TLS handshake process takes a long time because of all the back and forth between the client and the server. You can shorten it by caching the clients' sessions which will skip a few steps in the TLS handshake. In order for this to work, your client also needs to cache the session. `BearSSL::WiFiClientSecure <bearssl-client-secure-class.rst#sessions-resuming-connections-fast>`__ can do that as well as modern web browsers.
|
||||||
|
|
||||||
|
Here are the kind of performance improvements that you'll be able to see for TLS handshakes with an ESP8266 with it's clock set at 160MHz on a network with fairly low latency:
|
||||||
|
|
||||||
|
* With an EC key of 256 bits, a request taking ~360ms without caching takes ~60ms with caching.
|
||||||
|
* With an RSA key of 2048 bits, a request taking ~1850ms without caching takes ~70ms with caching.
|
||||||
|
|
||||||
|
setCache(BearSSL::ServerSessions \*cache)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Sets the cache for the server's sessions. When choosing the size of the cache, remember that each client session takes 100 bytes. If you setup a cache for 10 sessions, it will take 1000 bytes. Needs to be called before `begin()`
|
||||||
|
|
||||||
|
When creating the cache, you can use any of the 2 available constructors:
|
||||||
|
|
||||||
|
* `BearSSL::ServerSessions(ServerSession *sessions, uint32_t size)`: Creates a cache with the given buffer and number of sessions.
|
||||||
|
* `BearSSL::ServerSessions(uint32_t size)`: Dynamically allocates a cache for the given number of sessions.
|
||||||
|
|
||||||
|
Requiring Client Certificates
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
TLS servers can request the client to identify itself by transmitting a certificate during handshake. If the client cannot transmit the certificate, the connection will be dropped by the server.
|
||||||
|
|
||||||
|
setClientTrustAnchor(const BearSSL::X509List \*client_CA_ta)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Sets the trust anchor (normally a self-signing CA) that all received certificates will be verified against. Needs to be called before `begin()`.
|
||||||
113
docs/bearssl.rst
Normal file
113
docs/bearssl.rst
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
:orphan:
|
||||||
|
|
||||||
|
BearSSL WiFi Classes
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Methods and properties described in this section are specific to the Raspberry Pi Pico W and the ESP8266. They are not covered in `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ documentation. Before they are fully documented please refer to information below.
|
||||||
|
|
||||||
|
The `BearSSL <https://bearssl.org>`__ library (with modifications for ESP8266 compatibility and to use ROM tables whenever possible) is used to perform all cryptography and TLS operations. The main ported repo is available `on GitHub <https://github.com/earlephilhower/bearssl-esp8266>`__.
|
||||||
|
|
||||||
|
CPU Requirements
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
SSL operations take significant CPU cycles to run, so it will connect significantly slower than unprotected connections on the Pico, but the actual data transfer rates once connected are similar.
|
||||||
|
|
||||||
|
See the section on `sessions <#sessions-resuming-connections-fast>`__ and `limiting cryptographic negotiation <#limiting-ciphers-new-connections-faster>`__ for ways of ensuring faster modes are used.
|
||||||
|
|
||||||
|
Memory Requirements
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
BearSSL doesn't perform memory allocations at runtime, but it does require allocation of memory at the beginning of a connection. There are two memory chunks required:
|
||||||
|
. A per-application secondary stack
|
||||||
|
. A per-connection TLS receive/transmit buffer plus overhead
|
||||||
|
|
||||||
|
The per-application secondary stack is approximately 7KB in size and is used for temporary variables during BearSSL processing. Only one stack is required, and it will be allocated whenever any `BearSSL::WiFiClientSecure` or `BearSSL::WiFiServerSecure` are instantiated. So, in the case of a global client or server, the memory will be allocated before `setup()` is called.
|
||||||
|
|
||||||
|
The per-connection buffers are approximately 22KB in size, but in certain circumstances it can be reduced dramatically by using MFLN or limiting message sizes. See the `MLFN section <#mfln-or-maximum-fragment-length-negotiation-saving-ram>`__ below for more information.
|
||||||
|
|
||||||
|
Object Lifetimes
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
There are many configuration options that require passing in a pointer to an object (i.e. a pointer to a private key, or a certificate list). In order to preserve memory, BearSSL does NOT copy the objects passed in via these pointers and as such any pointer passed in to BearSSL needs to be preserved for the life of the client object. For example, the following code is **in error**:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
const char x509CA PROGMEM = ".......";
|
||||||
|
void setup() {
|
||||||
|
BearSSL::X509List x509(x509CA);
|
||||||
|
client.setTrustAnchor(&x509);
|
||||||
|
}
|
||||||
|
void loop() {
|
||||||
|
client.connect("192.168.1.1", 443);
|
||||||
|
}
|
||||||
|
|
||||||
|
Because the pointer to the local object `x509` no longer is valid after setup(), expect to crash in the main `loop()` where it is accessed by the `client` object.
|
||||||
|
|
||||||
|
As a rule, either keep your objects global, use `new` to create them, or ensure that all objects needed live inside the same scope as the client.
|
||||||
|
|
||||||
|
TLS and HTTPS Basics
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The following discussion is only intended to give a rough idea of TLS/HTTPS(which is just HTTP over a TLS connection) and the components an application needs to manage to make a TLS connection. For more detailed information, please check the relevant `RFC 5246 <https://tools.ietf.org/search/rfc5246>`__ and others.
|
||||||
|
|
||||||
|
TLS can be broken into two stages: verifying the identities of server (and potentially client), and then encrypting blocks of data bidirectionally. Verifying the identity of the other partner is handled via keys encoded in X509 certificates, optionally signed by a series of other entities.
|
||||||
|
|
||||||
|
|
||||||
|
Public and Private Keys
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Cryptographic keys are required for many of the BearSSL functions. Both public and private keys are supported, with either Elliptic Curve or RSA key support.
|
||||||
|
|
||||||
|
To generate a public or private key from an existing PEM (ASCII format) or DER (binary format), the simplest method is to use the constructor:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
BearSSL::PublicKey(const char *pemString)
|
||||||
|
... or ...
|
||||||
|
BearSSL::PublicKey(const uint8_t *derArray, size_t derLen)
|
||||||
|
|
||||||
|
Note that `PROGMEM` strings and arrays are natively supported by these constructors and no special `*_P` modes are required. There are additional functions to identify the key type and access the underlying BearSSL proprietary types, but they are not needed by user applications.
|
||||||
|
|
||||||
|
TLS Sessions
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
TLS supports the notion of a session (completely independent and different from HTTP sessions) which allow clients to reconnect to a server without having to renegotiate encryption settings or validate X509 certificates. This can save significant time (3-4 seconds in the case of EC keys) and can help save power by allowing the ESP8266 to sleep for a long time, reconnect and transmit some samples using the SSL session, and then jump back to sleep quicker.
|
||||||
|
|
||||||
|
`BearSSL::Session` is an opaque class. Use the `BearSSL::WiFiClientSecure.setSession(&BearSSLSession)` method to apply it before the first `BearSSL::WiFiClientSecure.connect()` and it will be updated with session parameters during the operation of the connection. After the connection has had `.close()` called on it, serialize the `BearSSL::Session` object to stable storage (EEPROM, RTC RAM, etc.) and restore it before trying to reconnect. See the `BearSSL_Sessions` example for a detailed example.
|
||||||
|
|
||||||
|
`Sessions <#sessions-resuming-connections-fast>`__ contains additional information on the sessions API.
|
||||||
|
|
||||||
|
X.509 Certificate(s)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
X509 certificates are used to identify peers in TLS connections. Normally only the server identifies itself, but the client can also supply an X509 certificate if desired (this is often done in MQTT applications). The certificate contains many fields, but the most interesting in our applications are the name, the public key, and potentially a chain of signing that leads back to a trusted authority (like a global internet CA or a company-wide private certificate authority).
|
||||||
|
|
||||||
|
Any call that takes an X509 certificate can also take a list of X509 certificates, so there is no special `X509` class, simply `BearSSL::X509List` (which may only contain a single certificate).
|
||||||
|
|
||||||
|
Generating a certificate to be used to validate using the constructor
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
BearSSL::X509List(const char *pemX509);
|
||||||
|
...or...
|
||||||
|
BearSSL::X509List(const uint8_t *derCert, size_t derLen);
|
||||||
|
|
||||||
|
If you need to add additional certificates (unlikely in normal operation), the `::append()` operation can be used.
|
||||||
|
|
||||||
|
|
||||||
|
Certificate Stores
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The web browser you're using to read this document keeps a list of 100s of certification authorities (CAs) worldwide that it trusts to attest to the identity of websites.
|
||||||
|
|
||||||
|
In many cases your application will know the specific CA it needs to validate web or MQTT servers against (often just a single, self-signing CA private to your institution). Simply load your private CA in a `BearSSL::X509List` and use that as your trust anchor.
|
||||||
|
|
||||||
|
However, there are cases where you will not know beforehand which CA you will need (i.e. a user enters a website through a keypad), and you need to keep the list of CAs just like your web browser. In those cases, you need to generate a certificate bundle on the PC while compiling your application, upload the `certs.ar` bundle to LittleFS or SD when uploading your application binary, and pass it to a `BearSSL::CertStore()` in order to validate TLS peers.
|
||||||
|
|
||||||
|
See the `BearSSL_CertStore` example for full details.
|
||||||
|
|
||||||
|
Supported Crypto
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Please see the `BearSSL website <https://bearssl.org>`__ for detailed cryptographic information. In general, TLS 1.2, TLS 1.1, and TLS 1.0 are supported with RSA and Elliptic Curve keys and a very rich set of hashing and symmetric encryption codes. Please note that Elliptic Curve (EC) key operations take a significant amount of time.
|
||||||
|
|
||||||
|
|
@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = u'1.0.0'
|
version = u'2.3.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = u'1.0.0'
|
release = u'2.3.0'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,4 @@ Returns the length of the EEPROM (i.e. the value specified in
|
||||||
|
|
||||||
EEPROM Examples
|
EEPROM Examples
|
||||||
---------------
|
---------------
|
||||||
Three EEPROM `examples<https://github.com/earlephilhower/arduino-pico/tree/master/libraries/EEPROM>`_ are included.
|
Three EEPROM `examples <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/EEPROM>`_ are included.
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ the word to fill when no data is available to send to the I2S hardware.
|
||||||
Call before ``I2S::begin()``.
|
Call before ``I2S::begin()``.
|
||||||
|
|
||||||
bool setFrequency(long sampleRate)
|
bool setFrequency(long sampleRate)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Sets the word clock frequency, but does not start the I2S device if not
|
Sets the word clock frequency, but does not start the I2S device if not
|
||||||
already running. May be called after ``I2S::begin()`` to change the
|
already running. May be called after ``I2S::begin()`` to change the
|
||||||
sample rate on-the-fly.
|
sample rate on-the-fly.
|
||||||
|
|
@ -158,17 +158,17 @@ Reads a left and right 8-bit sample and returns ``true`` on success. Will block
|
||||||
until data is available.
|
until data is available.
|
||||||
|
|
||||||
bool read16(int16_t \*l, int16_t \*r)
|
bool read16(int16_t \*l, int16_t \*r)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Reads a left and right 16-bit sample and returns ``true`` on success. Will block
|
Reads a left and right 16-bit sample and returns ``true`` on success. Will block
|
||||||
until data is available.
|
until data is available.
|
||||||
|
|
||||||
bool read24(int32_t \*l, int32_t \*r)
|
bool read24(int32_t \*l, int32_t \*r)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Reads a left and right 24-bit sample and returns ``true`` on success. See note below
|
Reads a left and right 24-bit sample and returns ``true`` on success. See note below
|
||||||
about 24-bit mode. Will block until data is available.
|
about 24-bit mode. Will block until data is available.
|
||||||
|
|
||||||
bool read32(int32_t \*l, int32_t \*r)
|
bool read32(int32_t \*l, int32_t \*r)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Reads a left and right 32-bit sample and returns ``true`` on success. Will block
|
Reads a left and right 32-bit sample and returns ``true`` on success. Will block
|
||||||
until data is available.
|
until data is available.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||||
|
|
||||||
Pin (Re)Assignment <pins>
|
Pin (Re)Assignment <pins>
|
||||||
|
|
||||||
|
RP2040 Helper <rp2040>
|
||||||
|
|
||||||
Analog I/O <analog>
|
Analog I/O <analog>
|
||||||
Digital I/O <digital>
|
Digital I/O <digital>
|
||||||
EEPROM <eeprom>
|
EEPROM <eeprom>
|
||||||
|
|
@ -39,7 +41,14 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||||
|
|
||||||
FreeRTOS SMP (multicore) <freertos>
|
FreeRTOS SMP (multicore) <freertos>
|
||||||
|
|
||||||
WiFi (Raspberry Pi Pico-W Support) <wifi>
|
WiFi (Pico-W Support) <wifi>
|
||||||
|
WiFiClient <wificlient>
|
||||||
|
WiFiServer <wifiserver>
|
||||||
|
WiFiUDP <wifiudp>
|
||||||
|
NTP client <wifintp>
|
||||||
|
BearSSL Encrypted TLS <bearssl>
|
||||||
|
WiFiClientSecure (TLS/SSL/HTTPS) <bearssl-client-secure-class>
|
||||||
|
WiFiServerSecure (TLS/SSL/HTTPS) <bearssl-server-secure-class>
|
||||||
|
|
||||||
Ported/Optimized Libraries <libraries>
|
Ported/Optimized Libraries <libraries>
|
||||||
Using Pico-SDK <sdk>
|
Using Pico-SDK <sdk>
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ When running MalwareBytes antivirus (or others) the scanner may lock the compile
|
||||||
|
|
||||||
Symptoms include:
|
Symptoms include:
|
||||||
|
|
||||||
*Access denied during update in the boards manager - affects the .exe files, because MalwareBytes has locked them.
|
* Access denied during update in the boards manager - affects the .exe files, because MalwareBytes has locked them.
|
||||||
* Access denied during compilation, to one of the .exe files - same reason.
|
* Access denied during compilation, to one of the .exe files - same reason.
|
||||||
* Can't delete the .exe files - they're locked by MalwareBytes.
|
* Can't delete the .exe files - they're locked by MalwareBytes.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,8 @@ uint32_t rp2040.fifo.pop()
|
||||||
|
|
||||||
Reads a value from this core's FIFO. Blocks until one is available.
|
Reads a value from this core's FIFO. Blocks until one is available.
|
||||||
|
|
||||||
bool rp2040.fifo.pop_nb(uint32_t *dest)
|
bool rp2040.fifo.pop_nb(uint32_t \*dest)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Reads a value from this core's FIFO and places it in dest. Will return
|
Reads a value from this core's FIFO and places it in dest. Will return
|
||||||
``true`` if successful, or ``false`` if the pop would block.
|
``true`` if successful, or ``false`` if the pop would block.
|
||||||
|
|
|
||||||
54
docs/rp2040.rst
Normal file
54
docs/rp2040.rst
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
RP2040 Helper Class
|
||||||
|
===================
|
||||||
|
|
||||||
|
Some of the core functionality of the RP2040 chip powering the Raspberry Pi
|
||||||
|
Pico is exposed in the RP2040 class variable ``rp2040``.
|
||||||
|
|
||||||
|
Core Internals
|
||||||
|
--------------
|
||||||
|
|
||||||
|
int rp2040.f_cpu()
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
Returns the current frequency of the core clock. This is read at runtime,
|
||||||
|
versus the constant ``F_CPU`` macro that is also available. This is useful
|
||||||
|
in cases where your code changes the core clock (i.e. low power modes, etc.)
|
||||||
|
|
||||||
|
uint32_t rp2040.getCycleCount()
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Returns a 32-bit cycle count from then the core started running. Because it
|
||||||
|
is only 32-bits, and the Pico runs at 133MHz, this value can loop around
|
||||||
|
in a matter of seconds.
|
||||||
|
|
||||||
|
uint64_t rp2040.getCycleCount64()
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Returns a 64-bit cycle count from then the core started running. This value
|
||||||
|
should never loop around in normal mode (at 133MHz it would take over 4,000
|
||||||
|
years to overflow).
|
||||||
|
|
||||||
|
uint32_t rp2040.hwrand32()
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Returns a 32-bit value derived from the CPU cycle counter and the ROSC
|
||||||
|
oscillator. Because the ROSC bit is not a true random number generator, the
|
||||||
|
values returned may not meet the most stringent random tests. **If your
|
||||||
|
application needs absolute bulletproof random numbers, consider using
|
||||||
|
dedicated external hardware.**
|
||||||
|
|
||||||
|
Memory Information
|
||||||
|
------------------
|
||||||
|
|
||||||
|
int rp2040.getFreeHeap()
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Returns the number of bytes free for heap allocation (i.e. malloc, new). Note
|
||||||
|
that because there is some overhead, and there may be heap fragmentation,
|
||||||
|
this number is an *upper bound* and you generally will only be able to allocate
|
||||||
|
less than this returned number.
|
||||||
|
|
||||||
|
int rp2040.getUsedHeap
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Returns the number of bytes allocated out of the heap.
|
||||||
|
|
||||||
|
int rp2040.getTotalHeap()
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Returns the total heap that was available to this program at compile time (i.e.
|
||||||
|
the Pico RAM size minus things like the ``.data`` and ``.bss`` sections and other
|
||||||
|
overhead).
|
||||||
|
|
@ -28,6 +28,7 @@ The size of the receive FIFO may also be adjusted from the default 32 bytes by
|
||||||
using the ``setFIFOSize`` call prior to calling ``begin()``
|
using the ``setFIFOSize`` call prior to calling ``begin()``
|
||||||
|
|
||||||
.. code:: cpp
|
.. code:: cpp
|
||||||
|
|
||||||
Serial1.setFIFOSize(128);
|
Serial1.setFIFOSize(128);
|
||||||
Serial1.begin(baud);
|
Serial1.begin(baud);
|
||||||
|
|
||||||
|
|
@ -38,6 +39,7 @@ For applications where an IRQ driven serial port is not appropriate, use
|
||||||
``setPollingMode(true)`` before calling ``begin()``
|
``setPollingMode(true)`` before calling ``begin()``
|
||||||
|
|
||||||
.. code:: cpp
|
.. code:: cpp
|
||||||
|
|
||||||
Serial1.setPollingMode(true);
|
Serial1.setPollingMode(true);
|
||||||
Serial1.begin(300)
|
Serial1.begin(300)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,33 +7,43 @@ Enable WiFi support by selecting the `Raspberry Pi Pico W` board in the IDE and
|
||||||
|
|
||||||
Supported Features
|
Supported Features
|
||||||
------------------
|
------------------
|
||||||
* WiFi connection (Open, WPA/WPA2)
|
|
||||||
* Static IP or dynamic DHCP supported
|
|
||||||
* Station Mode (STA, connects to an existing network)
|
|
||||||
* Access Point Mode (AP, creates its own wireless network) with 4 clients
|
|
||||||
* WiFi Scanning and Reporting
|
|
||||||
* See the ``ScanNetworks.ino`` example to better understand the process.
|
|
||||||
* `WiFiClient (TCP/IP client) <wificlient.rst>`__
|
|
||||||
* See the ``WiFiClient.ino`` example which connects the Pico W to a remote internet service and retrieves some data
|
|
||||||
* `WiFiServer (TCP/IP server) <wifiserver.rst>`__
|
|
||||||
* See the ``WiFiServer.ino`` example which implements a frientdy TCP/IP server
|
|
||||||
* `WiFiUDP (UDP packet input/output) <wifiudp.rst>`__
|
|
||||||
* See the ``UDP.ino`` example for a simple send/receive UDP application
|
|
||||||
|
|
||||||
In the near future TLS (SSL/https) encryption is planned, but is not yet implemented.
|
* WiFi connection (Open, WPA/WPA2)
|
||||||
|
|
||||||
|
* Static IP or dynamic DHCP supported
|
||||||
|
|
||||||
|
* Station Mode (STA, connects to an existing network)
|
||||||
|
|
||||||
|
* Access Point Mode (AP, creates its own wireless network) with 4 clients
|
||||||
|
|
||||||
|
* WiFi Scanning and Reporting
|
||||||
|
|
||||||
|
* See the ``ScanNetworks.ino`` example to better understand the process.
|
||||||
|
|
||||||
|
|
||||||
Important Information
|
Important Information
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Please note that WiFi on the Pico W is a work-in-progress and there are some important caveats:
|
Please note that WiFi on the Pico W is a work-in-progress and there are some important caveats:
|
||||||
* Adding WiFi increases flash usage by > 220KB.
|
|
||||||
* There is a binary firmware blob for the WiFi chip (CYW43-series) which the Pico W uses. It's 220KB of code that needs to be included in any Pico W sketch, even one that simply flashes the onboard LED. There are hopes to reduce this via compression (see `this issue <https://github.com/raspberrypi/pico-sdk/issues/909>`__ )
|
* Adding WiFi increases flash usage by over 220KB
|
||||||
|
|
||||||
|
* There is a 220KB binary firmware blob for the WiFi chip (CYW43-series) which the Pico W uses, even to control the onboard LED.
|
||||||
|
|
||||||
* Adding WiFi increases RAM usage by ~40KB.
|
* Adding WiFi increases RAM usage by ~40KB.
|
||||||
|
|
||||||
* LWIP, the TCP/IP driver, requires preallocated buffers to allow it to run in non-polling mode (i.e. packets can be sent and received in the background without the application needing to explicitly do anything).
|
* LWIP, the TCP/IP driver, requires preallocated buffers to allow it to run in non-polling mode (i.e. packets can be sent and received in the background without the application needing to explicitly do anything).
|
||||||
|
|
||||||
* The WiFi driver is a little limited as of now, but fully functional for sending and receiving data
|
* The WiFi driver is a little limited as of now, but fully functional for sending and receiving data
|
||||||
|
|
||||||
* Extensible Authentication Protocol (EAP) is not supported
|
* Extensible Authentication Protocol (EAP) is not supported
|
||||||
|
|
||||||
* Combined STA/AP mode is not supported
|
* Combined STA/AP mode is not supported
|
||||||
|
|
||||||
* Certain WiFi status values (RSSI, BSSID, etc.) are not available.
|
* Certain WiFi status values (RSSI, BSSID, etc.) are not available.
|
||||||
|
|
||||||
* Multicore is supported, but only one core may run ``WiFi`` code.
|
* Multicore is supported, but only one core may run ``WiFi`` code.
|
||||||
|
|
||||||
* FreeRTOS is not yet supported due to the requirement for a very different LWIP implementation. PRs always appreciated!
|
* FreeRTOS is not yet supported due to the requirement for a very different LWIP implementation. PRs always appreciated!
|
||||||
|
|
||||||
The WiFi library borrows much work from the `ESP8266 Arduino Core <https://github.com/esp8266/Arduino>`__ , especially the ``WiFiClient`` and ``WiFiServer`` classes.
|
The WiFi library borrows much work from the `ESP8266 Arduino Core <https://github.com/esp8266/Arduino>`__ , especially the ``WiFiClient`` and ``WiFiServer`` classes.
|
||||||
|
|
@ -42,6 +52,11 @@ Special Thanks
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Special thanks to:
|
Special thanks to:
|
||||||
|
|
||||||
* @todbot for donating one of his Pico W boards to the effort
|
* @todbot for donating one of his Pico W boards to the effort
|
||||||
|
|
||||||
* @d-a-v for much patient explanation about LWIP internals
|
* @d-a-v for much patient explanation about LWIP internals
|
||||||
|
|
||||||
* The whole ESP8266 Arduino team for their network classes
|
* The whole ESP8266 Arduino team for their network classes
|
||||||
|
|
||||||
|
* Adafruit Industries for their kind donation
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
:orphan:
|
.. _HeaderTag:
|
||||||
|
|
||||||
Client Class
|
WiFiClient
|
||||||
------------
|
==========
|
||||||
|
|
||||||
Methods documented for `Client <https://www.arduino.cc/en/Reference/WiFiClientConstructor>`__ in `Arduino <https://github.com/arduino/Arduino>`__
|
Methods documented for `Client <https://www.arduino.cc/en/Reference/WiFiClientConstructor>`__ in `Arduino <https://github.com/arduino/Arduino>`__
|
||||||
|
|
||||||
|
|
|
||||||
41
docs/wifintp.rst
Normal file
41
docs/wifintp.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
Network Time Protocol (NTP)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
NTP allows the Pico to set its internal clock using the internet, and is
|
||||||
|
required for secure connections because the certificates used have valid
|
||||||
|
date stamps.
|
||||||
|
|
||||||
|
After ``WiFi.begin()`` use ``NTP.begin(s1)`` or ``NTP,begin(s1, s2)`` to
|
||||||
|
use one or two NTP servers (common ones are ``pool.ntp.org`` and
|
||||||
|
``time.nist.gov``) .
|
||||||
|
|
||||||
|
.. code :: cpp
|
||||||
|
|
||||||
|
WiFi.begin("ssid", "pass");
|
||||||
|
NTP.begin("pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Either names or ``IPAddress`` may be used to identify the NTP server to
|
||||||
|
use.
|
||||||
|
|
||||||
|
It may take seconds to minutes for the system time to be updated by NTP,
|
||||||
|
depending on the server. It is often useful to check that ``time(NULL)``
|
||||||
|
returns a sane value before continuing a sketch:
|
||||||
|
|
||||||
|
.. code :: cpp
|
||||||
|
|
||||||
|
void setClock() {
|
||||||
|
NTP.begin("pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Serial.print("Waiting for NTP time sync: ");
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
while (now < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&now, &timeinfo);
|
||||||
|
Serial.print("Current time: ");
|
||||||
|
Serial.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
183
include/bearssl/bearssl.h
Normal file
183
include/bearssl/bearssl.h
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \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);
|
||||||
|
|
||||||
|
/* ======================================================================= */
|
||||||
|
|
||||||
|
/** \brief Version feature: support for time callback. */
|
||||||
|
#define BR_FEATURE_X509_TIME_CALLBACK 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
1059
include/bearssl/bearssl_aead.h
Normal file
1059
include/bearssl/bearssl_aead.h
Normal file
File diff suppressed because it is too large
Load diff
2618
include/bearssl/bearssl_block.h
Normal file
2618
include/bearssl/bearssl_block.h
Normal file
File diff suppressed because it is too large
Load diff
967
include/bearssl/bearssl_ec.h
Normal file
967
include/bearssl/bearssl_ec.h
Normal 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 necessarily 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
|
||||||
2
include/bearssl/bearssl_git.h
Normal file
2
include/bearssl/bearssl_git.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile
|
||||||
|
#define BEARSSL_GIT f294aa0
|
||||||
1346
include/bearssl/bearssl_hash.h
Normal file
1346
include/bearssl/bearssl_hash.h
Normal file
File diff suppressed because it is too large
Load diff
241
include/bearssl/bearssl_hmac.h
Normal file
241
include/bearssl/bearssl_hmac.h
Normal 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
|
||||||
284
include/bearssl/bearssl_kdf.h
Normal file
284
include/bearssl/bearssl_kdf.h
Normal 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
|
||||||
294
include/bearssl/bearssl_pem.h
Normal file
294
include/bearssl/bearssl_pem.h
Normal 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
|
||||||
150
include/bearssl/bearssl_prf.h
Normal file
150
include/bearssl/bearssl_prf.h
Normal 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
|
||||||
397
include/bearssl/bearssl_rand.h
Normal file
397
include/bearssl/bearssl_rand.h
Normal 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
|
||||||
1655
include/bearssl/bearssl_rsa.h
Normal file
1655
include/bearssl/bearssl_rsa.h
Normal file
File diff suppressed because it is too large
Load diff
4308
include/bearssl/bearssl_ssl.h
Normal file
4308
include/bearssl/bearssl_ssl.h
Normal file
File diff suppressed because it is too large
Load diff
1669
include/bearssl/bearssl_x509.h
Normal file
1669
include/bearssl/bearssl_x509.h
Normal file
File diff suppressed because it is too large
Load diff
103
include/lwipopts.h
Normal file
103
include/lwipopts.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||||
|
#define _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
|
// Critical section protection
|
||||||
|
extern void noInterrupts();
|
||||||
|
extern void interrupts();
|
||||||
|
#define SYS_ARCH_DECL_PROTECT int
|
||||||
|
#define SYS_ARCH_PROTECT(lev) noInterrupts
|
||||||
|
#define SYS_ARCH_UNPROTECT(lev) interrupts
|
||||||
|
|
||||||
|
// Common settings used in most of the pico_w examples
|
||||||
|
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
|
||||||
|
|
||||||
|
#define NO_SYS 1
|
||||||
|
#define LWIP_SOCKET 0
|
||||||
|
#define MEM_LIBC_MALLOC 0
|
||||||
|
|
||||||
|
#define MEM_ALIGNMENT 4
|
||||||
|
#define MEM_SIZE 4000
|
||||||
|
#define MEMP_NUM_TCP_SEG 32
|
||||||
|
#define MEMP_NUM_ARP_QUEUE 10
|
||||||
|
#define PBUF_POOL_SIZE 24
|
||||||
|
#define LWIP_ARP 1
|
||||||
|
#define LWIP_ETHERNET 1
|
||||||
|
#define LWIP_ICMP 1
|
||||||
|
#define LWIP_RAW 1
|
||||||
|
#define TCP_WND (8 * TCP_MSS)
|
||||||
|
#define TCP_MSS 1460
|
||||||
|
#define TCP_SND_BUF (8 * TCP_MSS)
|
||||||
|
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
|
||||||
|
#define LWIP_NETIF_STATUS_CALLBACK 1
|
||||||
|
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||||
|
#define LWIP_NETIF_HOSTNAME 1
|
||||||
|
#define LWIP_NETCONN 0
|
||||||
|
#define MEM_STATS 0
|
||||||
|
#define SYS_STATS 0
|
||||||
|
#define MEMP_STATS 0
|
||||||
|
#define LINK_STATS 0
|
||||||
|
// #define ETH_PAD_SIZE 2
|
||||||
|
#define LWIP_CHKSUM_ALGORITHM 3
|
||||||
|
#define LWIP_DHCP 1
|
||||||
|
#define LWIP_IPV4 1
|
||||||
|
#define LWIP_TCP 1
|
||||||
|
#define LWIP_UDP 1
|
||||||
|
#define LWIP_DNS 1
|
||||||
|
#define LWIP_TCP_KEEPALIVE 1
|
||||||
|
#define LWIP_NETIF_TX_SINGLE_PBUF 1
|
||||||
|
#define DHCP_DOES_ARP_CHECK 0
|
||||||
|
#define LWIP_DHCP_DOES_ACD_CHECK 0
|
||||||
|
|
||||||
|
// NTP
|
||||||
|
extern void __setSystemTime(unsigned long long sec, unsigned long us);
|
||||||
|
#define SNTP_SET_SYSTEM_TIME_US(sec, us) __setSystemTime(sec, us)
|
||||||
|
#define SNTP_MAX_SERVERS 2
|
||||||
|
//#define SNTP_SERVER_ADDRESS "pool.ntp.org"
|
||||||
|
#define SNTP_SERVER_DNS 1
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define LWIP_DEBUG 1
|
||||||
|
#define LWIP_STATS 1
|
||||||
|
#define LWIP_STATS_DISPLAY 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ETHARP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define NETIF_DEBUG LWIP_DBG_OFF
|
||||||
|
#define PBUF_DEBUG LWIP_DBG_OFF
|
||||||
|
#define API_LIB_DEBUG LWIP_DBG_OFF
|
||||||
|
#define API_MSG_DEBUG LWIP_DBG_OFF
|
||||||
|
#define SOCKETS_DEBUG LWIP_DBG_OFF
|
||||||
|
#define ICMP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define INET_DEBUG LWIP_DBG_OFF
|
||||||
|
#define IP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define IP_REASS_DEBUG LWIP_DBG_OFF
|
||||||
|
#define RAW_DEBUG LWIP_DBG_OFF
|
||||||
|
#define MEM_DEBUG LWIP_DBG_OFF
|
||||||
|
#define MEMP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define SYS_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_RTO_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_CWND_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_WND_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_FR_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCP_RST_DEBUG LWIP_DBG_OFF
|
||||||
|
#define UDP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define TCPIP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define PPP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define SLIP_DEBUG LWIP_DBG_OFF
|
||||||
|
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __LWIPOPTS_H__ */
|
||||||
92
include/tusb_config.h
Normal file
92
include/tusb_config.h
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.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 _TUSB_CONFIG_H_
|
||||||
|
#define _TUSB_CONFIG_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// COMMON CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_MCU
|
||||||
|
#define CFG_TUSB_MCU OPT_MCU_RP2040
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
|
||||||
|
#define CFG_TUSB_OS OPT_OS_PICO
|
||||||
|
|
||||||
|
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||||
|
#ifndef CFG_TUSB_DEBUG
|
||||||
|
#define CFG_TUSB_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||||
|
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||||
|
* into those specific section.
|
||||||
|
* e.g
|
||||||
|
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||||
|
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||||
|
*/
|
||||||
|
#ifndef CFG_TUSB_MEM_SECTION
|
||||||
|
#define CFG_TUSB_MEM_SECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_MEM_ALIGN
|
||||||
|
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// DEVICE CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||||
|
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------- CLASS -------------//
|
||||||
|
#define CFG_TUD_HID (2)
|
||||||
|
#define CFG_TUD_CDC (1)
|
||||||
|
#define CFG_TUD_MSC (0)
|
||||||
|
#define CFG_TUD_MIDI (0)
|
||||||
|
#define CFG_TUD_VENDOR (0)
|
||||||
|
|
||||||
|
#define CFG_TUD_CDC_RX_BUFSIZE (256)
|
||||||
|
#define CFG_TUD_CDC_TX_BUFSIZE (256)
|
||||||
|
|
||||||
|
#define CFG_TUD_MIDI_RX_BUFSIZE (64)
|
||||||
|
#define CFG_TUD_MIDI_TX_BUFSIZE (64)
|
||||||
|
|
||||||
|
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||||
|
#define CFG_TUD_HID_EP_BUFSIZE (64)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _TUSB_CONFIG_H_ */
|
||||||
BIN
lib/libbearssl.a
Normal file
BIN
lib/libbearssl.a
Normal file
Binary file not shown.
BIN
lib/libpico.a
BIN
lib/libpico.a
Binary file not shown.
|
|
@ -1,5 +1,5 @@
|
||||||
-iwithprefixbefore/cores/rp2040/api/deprecated-avr-comp/
|
-iwithprefixbefore/cores/rp2040/api/deprecated-avr-comp/
|
||||||
-iwithprefixbefore/lib/pico_base/
|
-iwithprefixbefore/include/pico_base/
|
||||||
-iwithprefixbefore/pico-sdk/lib/tinyusb/src/
|
-iwithprefixbefore/pico-sdk/lib/tinyusb/src/
|
||||||
-iwithprefixbefore/pico-sdk/src/boards/include
|
-iwithprefixbefore/pico-sdk/src/boards/include
|
||||||
-iwithprefixbefore/pico-sdk/src/common/pico_base/include
|
-iwithprefixbefore/pico-sdk/src/common/pico_base/include
|
||||||
|
|
|
||||||
172
libraries/WiFi/examples/BearSSL_CertStore/BearSSL_CertStore.ino
Normal file
172
libraries/WiFi/examples/BearSSL_CertStore/BearSSL_CertStore.ino
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
// Demonstrate the CertStore object with WiFiClientBearSSL
|
||||||
|
//
|
||||||
|
// Before running, you must download the set of certs using
|
||||||
|
// the script "certs-from-mozilla.py" (no parameters)
|
||||||
|
// and then uploading the generated .AR file to LittleFS or SD.
|
||||||
|
//
|
||||||
|
// You do not need to generate the ".IDX" file listed below,
|
||||||
|
// it is generated automatically when the CertStore object
|
||||||
|
// is created and written to SD or LittleFS by the ESP8266.
|
||||||
|
//
|
||||||
|
// Why would you need a CertStore?
|
||||||
|
//
|
||||||
|
// If you know the exact server being connected to, or you
|
||||||
|
// are generating your own self-signed certificates and aren't
|
||||||
|
// allowing connections to HTTPS/TLS servers out of your
|
||||||
|
// control, then you do NOT want a CertStore. Hardcode the
|
||||||
|
// self-signing CA or the site's x.509 certificate directly.
|
||||||
|
//
|
||||||
|
// However, if you don't know what specific sites the system
|
||||||
|
// will be required to connect to and verify, a
|
||||||
|
// CertStore can allow you to select from among
|
||||||
|
// 10s or 100s of CAs against which you can check the
|
||||||
|
// target's X.509, without taking any more RAM than a single
|
||||||
|
// certificate. This is the same way that standard browsers
|
||||||
|
// and operating systems verify SSL connections.
|
||||||
|
//
|
||||||
|
// About the chosen certs:
|
||||||
|
// The certificates are scraped from the Mozilla.org current
|
||||||
|
// list, but please don't take this as an endorsement or a
|
||||||
|
// requirement: it is up to YOU, the USER, to specify the
|
||||||
|
// certificate authorities you will use as trust bases.
|
||||||
|
//
|
||||||
|
// Mar 2018 by Earle F. Philhower, III
|
||||||
|
// Released to the public domain
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <CertStoreBearSSL.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <FS.h>
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
#ifndef STASSID
|
||||||
|
#define STASSID "your-ssid"
|
||||||
|
#define STAPSK "your-password"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *ssid = STASSID;
|
||||||
|
const char *pass = STAPSK;
|
||||||
|
|
||||||
|
// A single, global CertStore which can be used by all
|
||||||
|
// connections. Needs to stay live the entire time any of
|
||||||
|
// the WiFiClientBearSSLs are present.
|
||||||
|
BearSSL::CertStore certStore;
|
||||||
|
|
||||||
|
// Set time via NTP, as required for x.509 validation
|
||||||
|
void setClock() {
|
||||||
|
NTP.begin("pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Serial.print("Waiting for NTP time sync: ");
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
while (now < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&now, &timeinfo);
|
||||||
|
Serial.print("Current time: ");
|
||||||
|
Serial.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try and connect using a WiFiClientBearSSL to specified host:port and dump URL
|
||||||
|
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
|
||||||
|
if (!path) {
|
||||||
|
path = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Trying: %s:443...", host);
|
||||||
|
client->connect(host, port);
|
||||||
|
if (!client->connected()) {
|
||||||
|
Serial.printf("*** Can't connect. ***\n-------\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.printf("Connected!\n-------\n");
|
||||||
|
client->write("GET ");
|
||||||
|
client->write(path);
|
||||||
|
client->write(" HTTP/1.0\r\nHost: ");
|
||||||
|
client->write(host);
|
||||||
|
client->write("\r\nUser-Agent: Raspberry Pi Pico W\r\n");
|
||||||
|
client->write("\r\n");
|
||||||
|
uint32_t to = millis() + 5000;
|
||||||
|
if (client->connected()) {
|
||||||
|
do {
|
||||||
|
char tmp[32];
|
||||||
|
memset(tmp, 0, 32);
|
||||||
|
int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
|
||||||
|
yield();
|
||||||
|
if (rlen < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Only print out first line up to \r, then abort connection
|
||||||
|
char *nl = strchr(tmp, '\r');
|
||||||
|
if (nl) {
|
||||||
|
*nl = 0;
|
||||||
|
Serial.print(tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.print(tmp);
|
||||||
|
} while (millis() < to);
|
||||||
|
}
|
||||||
|
client->stop();
|
||||||
|
Serial.printf("\n-------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
LittleFS.begin();
|
||||||
|
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
Serial.println("WiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
setClock(); // Required for X.509 validation
|
||||||
|
|
||||||
|
int numCerts = certStore.initCertStore(LittleFS, PSTR("/certs.idx"), PSTR("/certs.ar"));
|
||||||
|
Serial.printf("Number of CA certs read: %d\n", numCerts);
|
||||||
|
if (numCerts == 0) {
|
||||||
|
Serial.printf("No certs found. Did you run certs-from-mozilla.py and upload the LittleFS directory before running?\n");
|
||||||
|
return; // Can't connect to anything w/o certs!
|
||||||
|
}
|
||||||
|
|
||||||
|
BearSSL::WiFiClientSecure *bear = new BearSSL::WiFiClientSecure();
|
||||||
|
// Integrate the cert store with this connection
|
||||||
|
bear->setCertStore(&certStore);
|
||||||
|
Serial.printf("Attempting to fetch https://github.com/...\n");
|
||||||
|
fetchURL(bear, "github.com", 443, "/");
|
||||||
|
delete bear;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Serial.printf("\nPlease enter a website address (www.blah.com) to connect to: ");
|
||||||
|
String site;
|
||||||
|
do {
|
||||||
|
site = Serial.readString();
|
||||||
|
} while (site == "");
|
||||||
|
// Strip newline if present
|
||||||
|
site.replace(String("\r"), "");
|
||||||
|
site.replace(String("\n"), "");
|
||||||
|
Serial.printf("https://%s/\n", site.c_str());
|
||||||
|
|
||||||
|
BearSSL::WiFiClientSecure *bear = new BearSSL::WiFiClientSecure();
|
||||||
|
// Integrate the cert store with this connection
|
||||||
|
bear->setCertStore(&certStore);
|
||||||
|
fetchURL(bear, site.c_str(), 443, "/");
|
||||||
|
delete bear;
|
||||||
|
}
|
||||||
81
libraries/WiFi/examples/BearSSL_CertStore/certs-from-mozilla.py
Executable file
81
libraries/WiFi/examples/BearSSL_CertStore/certs-from-mozilla.py
Executable file
|
|
@ -0,0 +1,81 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# This script pulls the list of Mozilla trusted certificate authorities
|
||||||
|
# from the web at the "mozurl" below, parses the file to grab the PEM
|
||||||
|
# for each cert, and then generates DER files in a new ./data directory
|
||||||
|
# Upload these to an on-chip filesystem and use the CertManager to parse
|
||||||
|
# and use them for your outgoing SSL connections.
|
||||||
|
#
|
||||||
|
# Script by Earle F. Philhower, III. Released to the public domain.
|
||||||
|
from __future__ import print_function
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from shutil import which
|
||||||
|
|
||||||
|
from subprocess import Popen, PIPE, call
|
||||||
|
try:
|
||||||
|
from urllib.request import urlopen
|
||||||
|
except Exception:
|
||||||
|
from urllib2 import urlopen
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except Exception:
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
# check if ar and openssl are available
|
||||||
|
if which('ar') is None and not os.path.isfile('./ar') and not os.path.isfile('./ar.exe'):
|
||||||
|
raise Exception("You need the program 'ar' from xtensa-lx106-elf found here: (esp8266-arduino-core)/hardware/esp8266com/esp8266/tools/xtensa-lx106-elf/xtensa-lx106-elf/bin/ar")
|
||||||
|
if which('openssl') is None and not os.path.isfile('./openssl') and not os.path.isfile('./openssl.exe'):
|
||||||
|
raise Exception("You need to have openssl in PATH, installable from https://www.openssl.org/")
|
||||||
|
|
||||||
|
# Mozilla's URL for the CSV file with included PEM certs
|
||||||
|
mozurl = "https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV"
|
||||||
|
|
||||||
|
# Load the names[] and pems[] array from the URL
|
||||||
|
names = []
|
||||||
|
pems = []
|
||||||
|
response = urlopen(mozurl)
|
||||||
|
csvData = response.read()
|
||||||
|
if sys.version_info[0] > 2:
|
||||||
|
csvData = csvData.decode('utf-8')
|
||||||
|
csvFile = StringIO(csvData)
|
||||||
|
csvReader = csv.reader(csvFile)
|
||||||
|
for row in csvReader:
|
||||||
|
names.append(row[0]+":"+row[1]+":"+row[2])
|
||||||
|
for item in row:
|
||||||
|
if item.startswith("'-----BEGIN CERTIFICATE-----"):
|
||||||
|
pems.append(item)
|
||||||
|
del names[0] # Remove headers
|
||||||
|
del pems[0] # Remove headers
|
||||||
|
|
||||||
|
# Try and make ./data, skip if present
|
||||||
|
try:
|
||||||
|
os.mkdir("data")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
derFiles = []
|
||||||
|
idx = 0
|
||||||
|
# Process the text PEM using openssl into DER files
|
||||||
|
for i in range(0, len(pems)):
|
||||||
|
certName = "data/ca_%03d.der" % (idx);
|
||||||
|
thisPem = pems[i].replace("'", "")
|
||||||
|
print(names[i] + " -> " + certName)
|
||||||
|
ssl = Popen(['openssl','x509','-inform','PEM','-outform','DER','-out', certName], shell = False, stdin = PIPE)
|
||||||
|
pipe = ssl.stdin
|
||||||
|
pipe.write(thisPem.encode('utf-8'))
|
||||||
|
pipe.close()
|
||||||
|
ssl.wait()
|
||||||
|
if os.path.exists(certName):
|
||||||
|
derFiles.append(certName)
|
||||||
|
idx = idx + 1
|
||||||
|
|
||||||
|
if os.path.exists("data/certs.ar"):
|
||||||
|
os.unlink("data/certs.ar");
|
||||||
|
|
||||||
|
arCmd = ['ar', 'q', 'data/certs.ar'] + derFiles;
|
||||||
|
call( arCmd )
|
||||||
|
|
||||||
|
for der in derFiles:
|
||||||
|
os.unlink(der)
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Shows how to use the Maximum Fragment Length option in
|
||||||
|
// BearSSL to reduce SSL memory needs.
|
||||||
|
//
|
||||||
|
// Mar 2018, Jul 2022 by Earle F. Philhower, III
|
||||||
|
// Released to the public domain
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <PolledTimeout.h>
|
||||||
|
|
||||||
|
#ifndef STASSID
|
||||||
|
#define STASSID "your-ssid"
|
||||||
|
#define STAPSK "your-password"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *ssid = STASSID;
|
||||||
|
const char *pass = STAPSK;
|
||||||
|
|
||||||
|
const char *site = "docs.oracle.com";
|
||||||
|
|
||||||
|
void fetch(BearSSL::WiFiClientSecure *client) {
|
||||||
|
client->write("GET / HTTP/1.0\r\nHost: ");
|
||||||
|
client->write(site);
|
||||||
|
client->write("\r\nUser-Agent: Raspberry Pi Pico W\r\n\r\n");
|
||||||
|
client->flush();
|
||||||
|
using oneShot = esp8266::polledTimeout::oneShot;
|
||||||
|
oneShot timeout(5000);
|
||||||
|
do {
|
||||||
|
char tmp[32];
|
||||||
|
int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
|
||||||
|
yield();
|
||||||
|
if (rlen < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rlen == 0) {
|
||||||
|
delay(10); // Give background processes some time
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tmp[rlen] = '\0';
|
||||||
|
Serial.print(tmp);
|
||||||
|
} while (!timeout);
|
||||||
|
client->stop();
|
||||||
|
Serial.printf("\n-------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int fetchNoMaxFragmentLength() {
|
||||||
|
int ret = rp2040.getFreeHeap();
|
||||||
|
|
||||||
|
Serial.printf("\nConnecting to https://%s\n", site);
|
||||||
|
Serial.printf("No MFLN attempted\n");
|
||||||
|
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
client.setInsecure();
|
||||||
|
client.connect(site, 443);
|
||||||
|
if (client.connected()) {
|
||||||
|
Serial.printf("Memory used: %d\n", ret - rp2040.getFreeHeap());
|
||||||
|
ret -= rp2040.getFreeHeap();
|
||||||
|
fetch(&client);
|
||||||
|
} else {
|
||||||
|
Serial.printf("Unable to connect\n");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fetchMaxFragmentLength() {
|
||||||
|
int ret = rp2040.getFreeHeap();
|
||||||
|
|
||||||
|
// Servers which implement RFC6066's Maximum Fragment Length Negotiation
|
||||||
|
// can be configured to limit the size of TLS fragments they transmit.
|
||||||
|
// This lets small clients, like the Pico, use a smaller memory buffer
|
||||||
|
// on the receive end (all the way down to under 1KB). Unfortunately,
|
||||||
|
// as of March 2018, there are not many public HTTPS servers which
|
||||||
|
// implement this option. You can deploy your own HTTPS or MQTT server
|
||||||
|
// with MFLN enabled, of course.
|
||||||
|
//
|
||||||
|
// To determine if MFLN is supported by a server use the
|
||||||
|
// ::probeMaxFragmentLength() method before connecting, and if it
|
||||||
|
// returns true then you can use the ::setBufferSizes(rx, tx) to shrink
|
||||||
|
// the needed BearSSL memory while staying within protocol limits.
|
||||||
|
//
|
||||||
|
// If MFLN is not supported, you may still be able to minimize the buffer
|
||||||
|
// sizes assuming you can ensure the server never transmits fragments larger
|
||||||
|
// than the size (i.e. by using HTTP GET RANGE methods, etc.).
|
||||||
|
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
client.setInsecure();
|
||||||
|
bool mfln = client.probeMaxFragmentLength(site, 443, 512);
|
||||||
|
Serial.printf("\nConnecting to https://%s\n", site);
|
||||||
|
Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
|
||||||
|
if (mfln) {
|
||||||
|
client.setBufferSizes(512, 512);
|
||||||
|
}
|
||||||
|
client.connect(site, 443);
|
||||||
|
if (client.connected()) {
|
||||||
|
Serial.printf("MFLN status: %s\n", client.getMFLNStatus() ? "true" : "false");
|
||||||
|
Serial.printf("Memory used: %d\n", ret - rp2040.getFreeHeap());
|
||||||
|
ret -= rp2040.getFreeHeap();
|
||||||
|
fetch(&client);
|
||||||
|
} else {
|
||||||
|
Serial.printf("Unable to connect\n");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.print(ssid);
|
||||||
|
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
Serial.println("WiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Serial.printf("\n\n\n\n\nFREE MEM: %d TOTAL HEAP:%d\n", rp2040.getFreeHeap(), rp2040.getTotalHeap());
|
||||||
|
|
||||||
|
int a = fetchNoMaxFragmentLength();
|
||||||
|
int b = fetchMaxFragmentLength();
|
||||||
|
|
||||||
|
Serial.printf("\n\n");
|
||||||
|
Serial.printf("Default SSL: %d bytes used\n", a);
|
||||||
|
Serial.printf("512 byte MFLN SSL: %d bytes used\n", b);
|
||||||
|
|
||||||
|
delay(10000);
|
||||||
|
}
|
||||||
237
libraries/WiFi/examples/BearSSL_Server/BearSSL_Server.ino
Normal file
237
libraries/WiFi/examples/BearSSL_Server/BearSSL_Server.ino
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
Demonstrate the usage of WiFiServerBearSSL.
|
||||||
|
By Earle F. Philhower, III
|
||||||
|
|
||||||
|
A simple HTTPS server is implemented with a self-signed
|
||||||
|
certificate for the Pico W.
|
||||||
|
|
||||||
|
This is NOT the best way to implement a HTTPS website on the
|
||||||
|
Pico W. Please see the ESP8266WebServerBearSSL example for
|
||||||
|
a much better way of doing this!
|
||||||
|
|
||||||
|
IMPORTANT NOTES ABOUT SSL CERTIFICATES
|
||||||
|
|
||||||
|
1. USE/GENERATE YOUR OWN CERTIFICATES
|
||||||
|
While a sample, self-signed certificate is included in this example,
|
||||||
|
it is ABSOLUTELY VITAL that you use your own SSL certificate in any
|
||||||
|
real-world deployment. Anyone with the certificate and key may be
|
||||||
|
able to decrypt your traffic, so your own keys should be kept in a
|
||||||
|
safe manner, not accessible on any public network.
|
||||||
|
|
||||||
|
2. HOW TO GENERATE YOUR OWN CERTIFICATE/KEY PAIR
|
||||||
|
It is easy to use OpenSSL to generate a self-signed certificate
|
||||||
|
openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days 4096
|
||||||
|
|
||||||
|
You may also, of course, use a commercial, trusted SSL provider to
|
||||||
|
generate your certificate.
|
||||||
|
|
||||||
|
Included with this example are *SAMPLE* certs and keys. They are NOT
|
||||||
|
SECURE, since they're shared with all copies of the repo, so
|
||||||
|
DO NOT USE THE SAMPLE CERTS, KEYS, OR CAS IN YOUR OWN PROJECT!!!
|
||||||
|
|
||||||
|
Run this example and then try connecting to the server https://IP.
|
||||||
|
|
||||||
|
This example is released into the public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef STASSID
|
||||||
|
#define STASSID "your-ssid"
|
||||||
|
#define STAPSK "your-password"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *ssid = STASSID;
|
||||||
|
const char *pass = STAPSK;
|
||||||
|
|
||||||
|
// The HTTPS server
|
||||||
|
BearSSL::WiFiServerSecure server(443);
|
||||||
|
|
||||||
|
//#define USE_EC // Enable Elliptic Curve signed cert
|
||||||
|
|
||||||
|
#ifndef USE_EC
|
||||||
|
|
||||||
|
// The server's private key which must be kept secret
|
||||||
|
const char server_private_key[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDJblrg47vF3qlE
|
||||||
|
NMRM7uG8QwE6v/AKpxOL+CLb/32s+dW9Psgf+oZKJgzGkYUoJdWpLitTmTZeykAs
|
||||||
|
Sq7Iax5Rq/mGqyAc7oJAUUAupfNRU0KwkD1XqtpQWEFoiqoIqZbOZ4CRX5q8z/MN
|
||||||
|
BH1aPVBMKaL33uwknkgJBzxwZJ2+uGKxRJt8+koj1CXgUCk5lEAEEG5kqE326MjN
|
||||||
|
O/c4gBqulBV8AIoq6/trY3apTS7FEOiN47qh1PVzoBm/oGVwXvoZAZOj7+gGGo91
|
||||||
|
sBC5oHJy5Y2BOcNB3opTNXQTiK3Z80b5wc3iQS+h83qAfHwhs6tfAW22WkAf+jtt
|
||||||
|
x8KdRWFNAgMBAAECggEAPd+jFL9/d1lc/zGCNuuN9YlTgFti/bKyo2UWOCOz1AVu
|
||||||
|
LVJyoLgQtggYFoqur1Vn2y7uaiB+/gD8U16hb7jPuGCuJjq8g4aUBfOvVmTtZ8a+
|
||||||
|
joPQA/TcWJ+zf8xQTJbjVwWeDYmje2oZC5+cbbK1zp9fiuoz+U+RawyI+TE+700i
|
||||||
|
ESCmsKFIHy2Ifruva8HgcPYIPpZ9zLxJj0Dii+WDs7zM9h2dzO4HfImSG/DPmgoV
|
||||||
|
ydo9IcrUE7KoMLa8Uo7u1b2h6BnTn7GfYiMSUsYcYR3CnpDBknBWjZMwrV0uqv9q
|
||||||
|
TbVc4QXt+c1q89HDg7BIJaOAzbCvJfgAfXUqZyqwQQKBgQD5ENFjicUzCqPw7fOy
|
||||||
|
Q5Z8GeUbIJ5urT1MheAq7SPd2kK8TsO3hUjNC0LLNSyKPs6gsYaIiObO3wDGeZZk
|
||||||
|
xeHBhrUVaz2nIjI7TrnCUpMDOrdxcPr4bc+ifV5YT4W3OFBWQ9chQEx3Nm3DbiX4
|
||||||
|
fpno34AiFrJF791JkTPFj9OIUQKBgQDPCgcae1pQr77q+GL5Q2tku3RrE4cWtExf
|
||||||
|
m8DzAb4Vxe3EhPz8bVr+71rqr/KqNfG1uKE3sT0fhB6VMTkHTOQU13jDrvpPUS3W
|
||||||
|
Vg8cVr5/+iiyF0xb+W8LQ+GVdR5xnMPSZHUtXyURvtzT4nnTAlAtN7lEytX9BzbX
|
||||||
|
xhltOOwGPQKBgA/Y/BnDSGLpCGlqGpl7J3YaB7PkLXCJYV8fHZZdpGyXWKu2r0lc
|
||||||
|
F7fEQanAZmcde/RJl2/UlisPkXMPhXxAAw9XTOph+nhJ+rw/VB6DNot8DvQO5kks
|
||||||
|
Y4vJQlmIJc/0q1fx1RxuhO8I7Y8D0TKwi4Z/wh1pKEq+6mul649kiWchAoGAWn8B
|
||||||
|
l9uvIHGRO9eSO23ytTcSrfL9Kzln4KqN7iom0hGP2kRe6F9MVP5+ePKrWSb3Hf0z
|
||||||
|
ysoX83ymeYPob352e32rda04EA9lv7giJrrrzbikrSNt5w3iMcRcCB4HTpW9Kmtq
|
||||||
|
pIhgBZ+tmpf1s/vg28LtoloeqtjKagpW9tzYnekCgYAZFZ84EGqS9SHw5LELgGY4
|
||||||
|
mQLMwbYZ6wBMA2PlqYi/17hoAVWz37mLDjtWDB4ir78QMoGbesQVtK9W/4vzmez4
|
||||||
|
ZLKlffdL5tCtA08Gq9aond1z83Xdnh1UjtwHIJvJPc/AoCFW1r5skv/G6acAk6I2
|
||||||
|
Zs0aiirNGTEymRX4rw26Qg==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
// The server's public certificate which must be shared
|
||||||
|
const char server_cert[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDUTCCAjmgAwIBAgIJAOcfK7c3JQtnMA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV
|
||||||
|
BAYTAkFVMQ0wCwYDVQQIDAROb25lMQ0wCwYDVQQKDAROb25lMRIwEAYDVQQDDAlF
|
||||||
|
U1BTZXJ2ZXIwHhcNMTgwMzE0MTg1NTQ1WhcNMjkwNTMxMTg1NTQ1WjA/MQswCQYD
|
||||||
|
VQQGEwJBVTENMAsGA1UECAwETm9uZTENMAsGA1UECgwETm9uZTESMBAGA1UEAwwJ
|
||||||
|
RVNQU2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyW5a4OO7
|
||||||
|
xd6pRDTETO7hvEMBOr/wCqcTi/gi2/99rPnVvT7IH/qGSiYMxpGFKCXVqS4rU5k2
|
||||||
|
XspALEquyGseUav5hqsgHO6CQFFALqXzUVNCsJA9V6raUFhBaIqqCKmWzmeAkV+a
|
||||||
|
vM/zDQR9Wj1QTCmi997sJJ5ICQc8cGSdvrhisUSbfPpKI9Ql4FApOZRABBBuZKhN
|
||||||
|
9ujIzTv3OIAarpQVfACKKuv7a2N2qU0uxRDojeO6odT1c6AZv6BlcF76GQGTo+/o
|
||||||
|
BhqPdbAQuaBycuWNgTnDQd6KUzV0E4it2fNG+cHN4kEvofN6gHx8IbOrXwFttlpA
|
||||||
|
H/o7bcfCnUVhTQIDAQABo1AwTjAdBgNVHQ4EFgQUBEk8LqgV+sMjdl/gpP1OlcNW
|
||||||
|
14EwHwYDVR0jBBgwFoAUBEk8LqgV+sMjdl/gpP1OlcNW14EwDAYDVR0TBAUwAwEB
|
||||||
|
/zANBgkqhkiG9w0BAQsFAAOCAQEAO1IrqW21KfzrxKmtuDSHdH5YrC3iOhiF/kaK
|
||||||
|
xXbigdtw6KHW/pIhGiA3BY5u+d5eVuHTR5YSwIbbRvOjuoNBATAw/8f5mt5Wa+C3
|
||||||
|
PDpLNxDys561VbCW45RMQ0x5kybvDYi0D1R/grqZ18veuFSfE6QMJ/mzvr575fje
|
||||||
|
8r5Ou0IZOYYF8cyqG5rA4U7BYXEnH44VgwlpkF8pitPsnyUWaAYqE0KnZ0qw0Py4
|
||||||
|
HCkfGJNlNOOamnr6KakVlocwKY0SdxcLoXSs5ogTQvTSrAOjwcm1RA0hOCXr8f/f
|
||||||
|
UsQIIGpPVh1plR1vYNndDeBpRJSFkoJTkgAIrlFzSMwNebU0pg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
#else
|
||||||
|
const char server_cert[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB0zCCAXqgAwIBAgIJALANi2eTiGD/MAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
|
||||||
|
AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
|
||||||
|
aXRzIFB0eSBMdGQwHhcNMTkwNjExMjIyOTU2WhcNMjAwNjEwMjIyOTU2WjBFMQsw
|
||||||
|
CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
|
||||||
|
ZXQgV2lkZ2l0cyBQdHkgTHRkMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExIkZ
|
||||||
|
w7zjk6TGcScff1PAehuEGmKZTf8VfnkjyJH0IbBgZibZ+qwYGBEnkz4KpKv7TkHo
|
||||||
|
W+j7F5EMcLcSrUIpy6NTMFEwHQYDVR0OBBYEFI6A0f+g0HyxUT6xrbVmRU79urbj
|
||||||
|
MB8GA1UdIwQYMBaAFI6A0f+g0HyxUT6xrbVmRU79urbjMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wCgYIKoZIzj0EAwIDRwAwRAIgWvy7ofQTGZMNqxUfe4gjtkU+C9AkQtaOMW2U
|
||||||
|
5xFFSvcCICvcGrQpoi7tRTq8xsXFmr8MYWgQTpVAtj6opXMQct/l
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
// The server's private key which must be kept secret
|
||||||
|
const char server_private_key[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN EC PARAMETERS-----
|
||||||
|
BggqhkjOPQMBBw==
|
||||||
|
-----END EC PARAMETERS-----
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIKyLR9/NT7ZdWM+2rklehveuk+jyIHJ+P8ZUQ392HOYvoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAExIkZw7zjk6TGcScff1PAehuEGmKZTf8VfnkjyJH0IbBgZibZ+qwY
|
||||||
|
GBEnkz4KpKv7TkHoW+j7F5EMcLcSrUIpyw==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CACHE_SIZE 5 // Number of sessions to cache.
|
||||||
|
#define USE_CACHE // Enable SSL session caching.
|
||||||
|
// Caching SSL sessions shortens the length of the SSL handshake.
|
||||||
|
// You can see the performance improvement by looking at the
|
||||||
|
// Network tab of the developer tools of your browser.
|
||||||
|
//#define DYNAMIC_CACHE // Whether to dynamically allocate the cache.
|
||||||
|
|
||||||
|
#if defined(USE_CACHE) && defined(DYNAMIC_CACHE)
|
||||||
|
// Dynamically allocated cache.
|
||||||
|
BearSSL::ServerSessions serverCache(CACHE_SIZE);
|
||||||
|
#elif defined(USE_CACHE)
|
||||||
|
// Statically allocated cache.
|
||||||
|
ServerSession store[CACHE_SIZE];
|
||||||
|
BearSSL::ServerSessions serverCache(store, CACHE_SIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
Serial.println("WiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
// Attach the server private cert/key combo
|
||||||
|
BearSSL::X509List *serverCertList = new BearSSL::X509List(server_cert);
|
||||||
|
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(server_private_key);
|
||||||
|
#ifndef USE_EC
|
||||||
|
server.setRSACert(serverCertList, serverPrivKey);
|
||||||
|
#else
|
||||||
|
server.setECCert(serverCertList, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, serverPrivKey);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set the server's cache
|
||||||
|
#if defined(USE_CACHE)
|
||||||
|
server.setCache(&serverCache);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Actually start accepting connections
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *HTTP_RES = "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"Content-Length: 62\r\n"
|
||||||
|
"Content-Type: text/html; charset=iso-8859-1\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<html>\r\n"
|
||||||
|
"<body>\r\n"
|
||||||
|
"<p>Hello from the Raspberry Pi Pico W!</p>\r\n"
|
||||||
|
"</body>\r\n"
|
||||||
|
"</html>\r\n";
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
static int cnt;
|
||||||
|
BearSSL::WiFiClientSecure incoming = server.accept();
|
||||||
|
if (!incoming) { return; }
|
||||||
|
Serial.printf("Incoming connection...%d\n", cnt++);
|
||||||
|
|
||||||
|
// Ugly way to wait for \r\n (i.e. end of HTTP request which we don't actually parse here)
|
||||||
|
uint32_t timeout = millis() + 1000;
|
||||||
|
int lcwn = 0;
|
||||||
|
for (;;) {
|
||||||
|
unsigned char x = 0;
|
||||||
|
if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) {
|
||||||
|
incoming.stop();
|
||||||
|
Serial.printf("Connection error, closed\n");
|
||||||
|
return;
|
||||||
|
} else if (!x) {
|
||||||
|
yield();
|
||||||
|
continue;
|
||||||
|
} else if (x == 0x0D) {
|
||||||
|
continue;
|
||||||
|
} else if (x == 0x0A) {
|
||||||
|
if (lcwn) { break; }
|
||||||
|
lcwn = 1;
|
||||||
|
} else
|
||||||
|
lcwn = 0;
|
||||||
|
}
|
||||||
|
incoming.write((uint8_t *)HTTP_RES, strlen(HTTP_RES));
|
||||||
|
incoming.flush();
|
||||||
|
incoming.stop();
|
||||||
|
Serial.printf("Connection closed.\n");
|
||||||
|
}
|
||||||
20
libraries/WiFi/examples/BearSSL_Server/cert.pem
Normal file
20
libraries/WiFi/examples/BearSSL_Server/cert.pem
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDUTCCAjmgAwIBAgIJAOcfK7c3JQtnMA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV
|
||||||
|
BAYTAkFVMQ0wCwYDVQQIDAROb25lMQ0wCwYDVQQKDAROb25lMRIwEAYDVQQDDAlF
|
||||||
|
U1BTZXJ2ZXIwHhcNMTgwMzE0MTg1NTQ1WhcNMjkwNTMxMTg1NTQ1WjA/MQswCQYD
|
||||||
|
VQQGEwJBVTENMAsGA1UECAwETm9uZTENMAsGA1UECgwETm9uZTESMBAGA1UEAwwJ
|
||||||
|
RVNQU2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyW5a4OO7
|
||||||
|
xd6pRDTETO7hvEMBOr/wCqcTi/gi2/99rPnVvT7IH/qGSiYMxpGFKCXVqS4rU5k2
|
||||||
|
XspALEquyGseUav5hqsgHO6CQFFALqXzUVNCsJA9V6raUFhBaIqqCKmWzmeAkV+a
|
||||||
|
vM/zDQR9Wj1QTCmi997sJJ5ICQc8cGSdvrhisUSbfPpKI9Ql4FApOZRABBBuZKhN
|
||||||
|
9ujIzTv3OIAarpQVfACKKuv7a2N2qU0uxRDojeO6odT1c6AZv6BlcF76GQGTo+/o
|
||||||
|
BhqPdbAQuaBycuWNgTnDQd6KUzV0E4it2fNG+cHN4kEvofN6gHx8IbOrXwFttlpA
|
||||||
|
H/o7bcfCnUVhTQIDAQABo1AwTjAdBgNVHQ4EFgQUBEk8LqgV+sMjdl/gpP1OlcNW
|
||||||
|
14EwHwYDVR0jBBgwFoAUBEk8LqgV+sMjdl/gpP1OlcNW14EwDAYDVR0TBAUwAwEB
|
||||||
|
/zANBgkqhkiG9w0BAQsFAAOCAQEAO1IrqW21KfzrxKmtuDSHdH5YrC3iOhiF/kaK
|
||||||
|
xXbigdtw6KHW/pIhGiA3BY5u+d5eVuHTR5YSwIbbRvOjuoNBATAw/8f5mt5Wa+C3
|
||||||
|
PDpLNxDys561VbCW45RMQ0x5kybvDYi0D1R/grqZ18veuFSfE6QMJ/mzvr575fje
|
||||||
|
8r5Ou0IZOYYF8cyqG5rA4U7BYXEnH44VgwlpkF8pitPsnyUWaAYqE0KnZ0qw0Py4
|
||||||
|
HCkfGJNlNOOamnr6KakVlocwKY0SdxcLoXSs5ogTQvTSrAOjwcm1RA0hOCXr8f/f
|
||||||
|
UsQIIGpPVh1plR1vYNndDeBpRJSFkoJTkgAIrlFzSMwNebU0pg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
28
libraries/WiFi/examples/BearSSL_Server/key.pem
Normal file
28
libraries/WiFi/examples/BearSSL_Server/key.pem
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDJblrg47vF3qlE
|
||||||
|
NMRM7uG8QwE6v/AKpxOL+CLb/32s+dW9Psgf+oZKJgzGkYUoJdWpLitTmTZeykAs
|
||||||
|
Sq7Iax5Rq/mGqyAc7oJAUUAupfNRU0KwkD1XqtpQWEFoiqoIqZbOZ4CRX5q8z/MN
|
||||||
|
BH1aPVBMKaL33uwknkgJBzxwZJ2+uGKxRJt8+koj1CXgUCk5lEAEEG5kqE326MjN
|
||||||
|
O/c4gBqulBV8AIoq6/trY3apTS7FEOiN47qh1PVzoBm/oGVwXvoZAZOj7+gGGo91
|
||||||
|
sBC5oHJy5Y2BOcNB3opTNXQTiK3Z80b5wc3iQS+h83qAfHwhs6tfAW22WkAf+jtt
|
||||||
|
x8KdRWFNAgMBAAECggEAPd+jFL9/d1lc/zGCNuuN9YlTgFti/bKyo2UWOCOz1AVu
|
||||||
|
LVJyoLgQtggYFoqur1Vn2y7uaiB+/gD8U16hb7jPuGCuJjq8g4aUBfOvVmTtZ8a+
|
||||||
|
joPQA/TcWJ+zf8xQTJbjVwWeDYmje2oZC5+cbbK1zp9fiuoz+U+RawyI+TE+700i
|
||||||
|
ESCmsKFIHy2Ifruva8HgcPYIPpZ9zLxJj0Dii+WDs7zM9h2dzO4HfImSG/DPmgoV
|
||||||
|
ydo9IcrUE7KoMLa8Uo7u1b2h6BnTn7GfYiMSUsYcYR3CnpDBknBWjZMwrV0uqv9q
|
||||||
|
TbVc4QXt+c1q89HDg7BIJaOAzbCvJfgAfXUqZyqwQQKBgQD5ENFjicUzCqPw7fOy
|
||||||
|
Q5Z8GeUbIJ5urT1MheAq7SPd2kK8TsO3hUjNC0LLNSyKPs6gsYaIiObO3wDGeZZk
|
||||||
|
xeHBhrUVaz2nIjI7TrnCUpMDOrdxcPr4bc+ifV5YT4W3OFBWQ9chQEx3Nm3DbiX4
|
||||||
|
fpno34AiFrJF791JkTPFj9OIUQKBgQDPCgcae1pQr77q+GL5Q2tku3RrE4cWtExf
|
||||||
|
m8DzAb4Vxe3EhPz8bVr+71rqr/KqNfG1uKE3sT0fhB6VMTkHTOQU13jDrvpPUS3W
|
||||||
|
Vg8cVr5/+iiyF0xb+W8LQ+GVdR5xnMPSZHUtXyURvtzT4nnTAlAtN7lEytX9BzbX
|
||||||
|
xhltOOwGPQKBgA/Y/BnDSGLpCGlqGpl7J3YaB7PkLXCJYV8fHZZdpGyXWKu2r0lc
|
||||||
|
F7fEQanAZmcde/RJl2/UlisPkXMPhXxAAw9XTOph+nhJ+rw/VB6DNot8DvQO5kks
|
||||||
|
Y4vJQlmIJc/0q1fx1RxuhO8I7Y8D0TKwi4Z/wh1pKEq+6mul649kiWchAoGAWn8B
|
||||||
|
l9uvIHGRO9eSO23ytTcSrfL9Kzln4KqN7iom0hGP2kRe6F9MVP5+ePKrWSb3Hf0z
|
||||||
|
ysoX83ymeYPob352e32rda04EA9lv7giJrrrzbikrSNt5w3iMcRcCB4HTpW9Kmtq
|
||||||
|
pIhgBZ+tmpf1s/vg28LtoloeqtjKagpW9tzYnekCgYAZFZ84EGqS9SHw5LELgGY4
|
||||||
|
mQLMwbYZ6wBMA2PlqYi/17hoAVWz37mLDjtWDB4ir78QMoGbesQVtK9W/4vzmez4
|
||||||
|
ZLKlffdL5tCtA08Gq9aond1z83Xdnh1UjtwHIJvJPc/AoCFW1r5skv/G6acAk6I2
|
||||||
|
Zs0aiirNGTEymRX4rw26Qg==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
Demonstrate the usage of client certificate validation
|
||||||
|
for WiFiServerBearSSL.
|
||||||
|
By Earle F. Philhower, III
|
||||||
|
|
||||||
|
TLS servers can require that a client present it with an X.509
|
||||||
|
certificate signed by a trusted authority. Clients which try
|
||||||
|
and connect without a x.509 key, or with an x.509 key not signed
|
||||||
|
by the trusted authority (which could be a self-signing CA)
|
||||||
|
can not connect.
|
||||||
|
|
||||||
|
This example uses a predefined CA and any number of client
|
||||||
|
certificates. Clients will need both their X.509 cert and their
|
||||||
|
private key, both of which are generated in the signing process.
|
||||||
|
|
||||||
|
To run this example:
|
||||||
|
1. Generate a private certificate-authority certificate and key:
|
||||||
|
openssl genrsa -out ca_key.pem 2048
|
||||||
|
openssl req -x509 -new -nodes -key ca_key.pem -days 4096 -config ca.conf -out ca_cer.pem
|
||||||
|
|
||||||
|
KEEP ca_key.pem ABSOLUTELY SECURE, WITH IT ANYONE CAN MAKE CERTS
|
||||||
|
SIGNED BY YOU!
|
||||||
|
|
||||||
|
DO NOT UPLOAD ca_key.pem TO THE PICO, IT'S NOT NEEDED (SEE BELOW)!
|
||||||
|
|
||||||
|
ca_cer.pem is the Public X.509 certificate for your signing authority
|
||||||
|
and can(must) be shared and included in the server as the trust root.
|
||||||
|
|
||||||
|
2. Generate a private server certificate and key pair (using the
|
||||||
|
self-signed CA or any other CA you'd like)
|
||||||
|
openssl genrsa -out server_key.pem 2048
|
||||||
|
openssl req -out server_req.csr -key server_key.pem -new -config server.conf
|
||||||
|
openssl x509 -req -in server_req.csr -out server_cer.pem -sha256 -CAcreateserial -days 4000 -CA ca_cer.pem -CAkey ca_key.pem
|
||||||
|
|
||||||
|
KEEP server_key.pem SECURE, IT IS YOUR SERVER'S PRIVATE KEY.
|
||||||
|
THIS WILL BE STORED IN THE SERVER ALONE. CLIENTS DO NOT NEED IT!
|
||||||
|
|
||||||
|
server_cer.pem *CAN* BE SHARED WITH CLIENTS, OR THE CLIENTS CAN SIMPLY
|
||||||
|
USE YOUR SELF-SIGNED CA_CER.PEM
|
||||||
|
|
||||||
|
3. Generate any number of private client certificate/key pairs (using the
|
||||||
|
private CA above)
|
||||||
|
openssl genrsa -out client1_key.pem 2048
|
||||||
|
openssl req -out client1_req.csr -key client1_key.pem -new -config client.conf
|
||||||
|
openssl x509 -req -in client1_req.csr -out client1_cer.pem -sha256 -CAcreateserial -days 4000 -CA ca_cer.pem -CAkey ca_key.pem
|
||||||
|
|
||||||
|
Every client should have its own unique certificate generated and
|
||||||
|
a copy of that specific client's private key.
|
||||||
|
|
||||||
|
DO NOT SHARE THE PRIVATE KEY GENERATED ABOVE!
|
||||||
|
|
||||||
|
Included with this example are *SAMPLE* certs and keys. They are NOT
|
||||||
|
SECURE, since they're shared with all copies of the repo, so
|
||||||
|
DO NOT USE THE SAMPLE CERTS, KEYS, OR CAS IN YOUR OWN PROJECT!!!
|
||||||
|
|
||||||
|
Run this example and then try connecting to the server IP:4433.
|
||||||
|
If you don't specify the client cert and key on the WGET command
|
||||||
|
line, you will not get connected.
|
||||||
|
|
||||||
|
ex: wget --quiet -O - --no-check-certificate --certificate=client1_cer.pem --private-key=client1_key.pem https://pico.ip.is.here < /dev/null
|
||||||
|
|
||||||
|
This example is released into the public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef STASSID
|
||||||
|
#define STASSID "your-ssid"
|
||||||
|
#define STAPSK "your-password"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *ssid = STASSID;
|
||||||
|
const char *pass = STAPSK;
|
||||||
|
|
||||||
|
// The server which will require a client cert signed by the trusted CA
|
||||||
|
BearSSL::WiFiServerSecure server(443);
|
||||||
|
|
||||||
|
// The hardcoded certificate authority for this example.
|
||||||
|
// Don't use it on your own apps!!!!!
|
||||||
|
const char ca_cert[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC1TCCAb2gAwIBAgIJAMPt1Ms37+hLMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV
|
||||||
|
BAYTAlVTMRIwEAYDVQQDDAkxMjcuMC4wLjMwHhcNMTgwMzE0MDQyMTU0WhcNMjkw
|
||||||
|
NTMxMDQyMTU0WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAwwJMTI3LjAuMC4zMIIB
|
||||||
|
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxsa4qU/tlzN4YTcnn/I/ffsi
|
||||||
|
jOPc8QRcwClKzasIZNFEye4uThl+LGZWFIFb8X8Dc+xmmBaWlPJbqtphgFKStpar
|
||||||
|
DdduHSW1ud6Y1FVKxljo3UwCMrYm76Q/jNzXJvGs6Z1MDNsVZzGJaoqit2H2Hkvk
|
||||||
|
y+7kk3YbEDlcyVsLOw0zCKL4cd2DSNDyhIZxWo2a8Qn5IdjWAYtsTnW6MvLk/ya4
|
||||||
|
abNeRfSZwi+r37rqi9CIs++NpL5ynqkKKEMrbeLactWgHbWrZeaMyLpuUEL2GF+w
|
||||||
|
MRaAwaj7ERwT5gFJRqYwj6bbfIdx5PC7h7ucbyp272MbrDa6WNBCMwQO222t4wID
|
||||||
|
AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmXfrC42nW
|
||||||
|
IpL3JDkB8YlB2QUvD9JdMp98xxo33+xE69Gov0e6984F1Gluao0p6sS7KF+q3YLS
|
||||||
|
4hjnzuGzF9GJMimIB7NMQ20yXKfKpmKJ7YugMaKTDWDhHn5679mKVbLSQxHCUMEe
|
||||||
|
tEnMT93/UaDbWBjV6zu876q5vjPMYgDHODqO295ySaA71UkijaCn6UwKUT49286T
|
||||||
|
V9ZtzgabNGHXfklHgUPWoShyze+G3g29I1BR0qABoJI63zaNu8ua42v5g1RldxsW
|
||||||
|
X8yKI14mFOGxuvcygG8L2xxysW7Zq+9g+O7gW0Pm6RDYnUQmIwY83h1KFCtYCJdS
|
||||||
|
2PgozwkkUNyP
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
// The server's private key which must be kept secret
|
||||||
|
const char server_private_key[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAsRNVTvqP++YUh8NrbXwE83xVsDqcB3F76xcXNKFDERfVd2P/
|
||||||
|
LvyDovCcoQtT0UCRgPcxRp894EuPH/Ru6Z2Lu85sV//i7ce27tc2WRFSfuhlRxHP
|
||||||
|
LJWHxTl1CEfXp/owkECQ4MB3pw6Ekc16iTEPiezTG+T+mQ/BkiIwcIK6CMlpR9DI
|
||||||
|
eYUTqv0f9NrUfAjdBrqlEO2gpgFvLFrkDEU2ntAIc4aPOP7yDOym/xzfy6TiG8Wo
|
||||||
|
7nlh6M97xTZGfbEPCH9rZDjo5istym1HzF5P+COq+OTSPscjFGXoi978o6hZwa7i
|
||||||
|
zxorg4h5a5lGnshRu2Gl+Ybfa14OwnIrv/yCswIDAQABAoIBAHxwgbsHCriTcEoY
|
||||||
|
Yx6F0VTrQ6ydA5mXfuYvS/eIfIE+pp1IgMScYEXZobjrJPQg1CA1l0NyFSHS97oV
|
||||||
|
JPy34sMQxcLx6KABgeVHCMJ/EeJtnv7a3SUP0GIhhsVS95Lsl8RIG4hWub+EzFVK
|
||||||
|
eZqAB9N9wr4Pp3wZPodbz37B38rb1QPyMFmQOLlHjKTOmoxsXhL2ot+R3+aLYSur
|
||||||
|
oPO1kQo7/d0UAZoy8h9OQN4a2EXvawh4O2EvFGbc5X/yXwAdEQ4NPp9VZhkNIRkV
|
||||||
|
+XZ3FcIqEVOploKtRF/tVBTz3g61/lFz21L9PMmV5y8tvSafr2SpJugGVmp2rrVQ
|
||||||
|
VNyGlIECgYEA10JSI5gmeCU3zK6kvOfBp54hY/5dDrSUpjKkMxpmm7WZQ6Il/k7A
|
||||||
|
hMcLeMzHiriT7WhRIXF8AOr2MoEkHkH3DhVNN4ccieVZx2SE5P5mVkItZGLrrpfU
|
||||||
|
dysR/ARAI1HYegGUiKacZtf9SrRavU0m7fOVOiYwbFRhjyX+MyuteYkCgYEA0pbz
|
||||||
|
4ZosetScP68uZx1sGlTfkcqLl7i15DHk3gnj6jKlfhvC2MjeLMhNDtKeUAuY7rLQ
|
||||||
|
guZ0CCghWAv0Glh5eYdfIiPhgqFfX4P5F3Om4zQHVPYj8xHfHG4ZP7dKQTndrO1Q
|
||||||
|
fLdGDTQLVXabAUSp2YGrijC8J9idSW1pYClvF1sCgYEAjkDn41nzYkbGP1/Swnwu
|
||||||
|
AEWCL4Czoro32jVxScxSrugt5wJLNWp508VukWBTJhugtq3Pn9hNaJXeKbYqVkyl
|
||||||
|
pgrxwpZph7+nuxt0r5hnrO2C7eppcjIoWLB/7BorAKxf8REGReBFT7nBTBMwPBW2
|
||||||
|
el4U6h6+tXh2GJG1Eb/1nnECgYAydVb0THOx7rWNkNUGggc/++why61M6kYy6j2T
|
||||||
|
cj05BW+f2tkCBoctpcTI83BZb53yO8g4RS2yMqNirGKN2XspwmTqEjzbhv0KLt4F
|
||||||
|
X4GyWOoU0nFksXiLIFpOaQWSwWG7KJWrfGJ9kWXR0Xxsfl5QLoDCuNCsn3t4d43T
|
||||||
|
K7phlwKBgHDzF+50+/Wez3YHCy2a/HgSbHCpLQjkknvgwkOh1z7YitYBUm72HP8Z
|
||||||
|
Ge6b4wEfNuBdlZll/y9BQQOZJLFvJTE5t51X9klrkGrOb+Ftwr7eI/H5xgcadI52
|
||||||
|
tPYglR5fjuRF/wnt3oX9JlQ2RtSbs+3naXH8JoherHaqNn8UpH0t
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
// The server's public certificate which must be shared
|
||||||
|
const char server_cert[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDTzCCAjcCCQDPXvMRYOpeuDANBgkqhkiG9w0BAQsFADCBpjESMBAGA1UEAwwJ
|
||||||
|
MTI3LjAuMC4xMQswCQYDVQQGEwJVUzElMCMGA1UECgwcTXkgT3duIENlcnRpZmlj
|
||||||
|
YXRlIEF1dGhvcml0eTEUMBIGA1UECAwLQXJkdWlub0xhbmQxFTATBgNVBAcMDEFy
|
||||||
|
ZHVpbm9WaWxsZTEVMBMGA1UECgwMRVNQODI2NlVzZXJzMRgwFgYDVQQLDA9FU1A4
|
||||||
|
MjY2LUFyZHVpbm8wHhcNMTgwMzE0MDQwMDAwWhcNMjkwMjI0MDQwMDAwWjAsMRYw
|
||||||
|
FAYDVQQKDA1NeSBTZXJ2ZXIgT3JnMRIwEAYDVQQDDAkxMjcuMC4wLjMwggEiMA0G
|
||||||
|
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxE1VO+o/75hSHw2ttfATzfFWwOpwH
|
||||||
|
cXvrFxc0oUMRF9V3Y/8u/IOi8JyhC1PRQJGA9zFGnz3gS48f9G7pnYu7zmxX/+Lt
|
||||||
|
x7bu1zZZEVJ+6GVHEc8slYfFOXUIR9en+jCQQJDgwHenDoSRzXqJMQ+J7NMb5P6Z
|
||||||
|
D8GSIjBwgroIyWlH0Mh5hROq/R/02tR8CN0GuqUQ7aCmAW8sWuQMRTae0Ahzho84
|
||||||
|
/vIM7Kb/HN/LpOIbxajueWHoz3vFNkZ9sQ8If2tkOOjmKy3KbUfMXk/4I6r45NI+
|
||||||
|
xyMUZeiL3vyjqFnBruLPGiuDiHlrmUaeyFG7YaX5ht9rXg7Cciu//IKzAgMBAAEw
|
||||||
|
DQYJKoZIhvcNAQELBQADggEBAEnG+FNyNCOkBvzHiUpHHpScxZqM2f+XDcewJgeS
|
||||||
|
L6HkYEDIZZDNnd5gduSvkHpdJtWgsvJ7dJZL40w7Ba5sxpZHPIgKJGl9hzMkG+aA
|
||||||
|
z5GMkjys9h2xpQZx9KL3q7G6A+C0bll7ODZlwBtY07CFMykT4Mp2oMRrQKRucMSV
|
||||||
|
AB1mKujLAnMRKJ3NM89RQJH4GYiRps9y/HvM5lh7EIK/J0/nEZeJxY5hJngskPKb
|
||||||
|
oPPdmkR97kaQnll4KNsC3owVlHVU2fMftgYkgQLzyeWgzcNa39AF3B6JlcOzNyQY
|
||||||
|
seoK24dHmt6tWmn/sbxX7Aa6TL/4mVlFoOgcaTJyVaY/BrY=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
// Note there are no client certificates required here in the server.
|
||||||
|
// That is because all clients will send a certificate that can be
|
||||||
|
// proven to be signed by the public CA certificate included at the
|
||||||
|
// head of the app.
|
||||||
|
|
||||||
|
// Set time via NTP, as required for x.509 validation
|
||||||
|
void setClock() {
|
||||||
|
NTP.begin("pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Serial.print("Waiting for NTP time sync: ");
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
while (now < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&now, &timeinfo);
|
||||||
|
Serial.print("Current time: ");
|
||||||
|
Serial.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
Serial.println("WiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
setClock(); // Required for X.509 validation
|
||||||
|
|
||||||
|
// Attach the server private cert/key combo
|
||||||
|
BearSSL::X509List *serverCertList = new BearSSL::X509List(server_cert);
|
||||||
|
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(server_private_key);
|
||||||
|
server.setRSACert(serverCertList, serverPrivKey);
|
||||||
|
|
||||||
|
// Require a certificate validated by the trusted CA
|
||||||
|
BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(ca_cert);
|
||||||
|
server.setClientTrustAnchor(serverTrustedCA);
|
||||||
|
|
||||||
|
// Actually start accepting connections
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *HTTP_RES = "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"Content-Length: 59\r\n"
|
||||||
|
"Content-Type: text/html; charset=iso-8859-1\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<html>\r\n"
|
||||||
|
"<body>\r\n"
|
||||||
|
"<p>Hello my friend!</p>\r\n"
|
||||||
|
"</body>\r\n"
|
||||||
|
"</html>\r\n";
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
BearSSL::WiFiClientSecure incoming = server.accept();
|
||||||
|
if (!incoming) { return; }
|
||||||
|
Serial.println("Incoming connection...\n");
|
||||||
|
|
||||||
|
// Ugly way to wait for \r\n (i.e. end of HTTP request which we don't actually parse here)
|
||||||
|
uint32_t timeout = millis() + 1000;
|
||||||
|
int lcwn = 0;
|
||||||
|
for (;;) {
|
||||||
|
unsigned char x = 0;
|
||||||
|
if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) {
|
||||||
|
incoming.stop();
|
||||||
|
Serial.printf("Connection error, closed\n");
|
||||||
|
return;
|
||||||
|
} else if (!x) {
|
||||||
|
yield();
|
||||||
|
continue;
|
||||||
|
} else if (x == 0x0D) {
|
||||||
|
continue;
|
||||||
|
} else if (x == 0x0A) {
|
||||||
|
if (lcwn) { break; }
|
||||||
|
lcwn = 1;
|
||||||
|
} else
|
||||||
|
lcwn = 0;
|
||||||
|
}
|
||||||
|
incoming.write((uint8_t *)HTTP_RES, strlen(HTTP_RES));
|
||||||
|
incoming.flush();
|
||||||
|
incoming.stop();
|
||||||
|
Serial.printf("Connection closed.\n");
|
||||||
|
}
|
||||||
12
libraries/WiFi/examples/BearSSL_ServerClientCert/ca.conf
Normal file
12
libraries/WiFi/examples/BearSSL_ServerClientCert/ca.conf
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
[ req ]
|
||||||
|
prompt = no
|
||||||
|
default_bits = 2048
|
||||||
|
distinguished_name = req_dn
|
||||||
|
x509_extensions = v3_req
|
||||||
|
|
||||||
|
[ req_dn ]
|
||||||
|
C = US
|
||||||
|
CN = 127.0.0.3
|
||||||
|
|
||||||
|
[v3_req]
|
||||||
|
basicConstraints=CA:TRUE
|
||||||
18
libraries/WiFi/examples/BearSSL_ServerClientCert/ca_cer.pem
Normal file
18
libraries/WiFi/examples/BearSSL_ServerClientCert/ca_cer.pem
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC1TCCAb2gAwIBAgIJAMPt1Ms37+hLMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV
|
||||||
|
BAYTAlVTMRIwEAYDVQQDDAkxMjcuMC4wLjMwHhcNMTgwMzE0MDQyMTU0WhcNMjkw
|
||||||
|
NTMxMDQyMTU0WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAwwJMTI3LjAuMC4zMIIB
|
||||||
|
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxsa4qU/tlzN4YTcnn/I/ffsi
|
||||||
|
jOPc8QRcwClKzasIZNFEye4uThl+LGZWFIFb8X8Dc+xmmBaWlPJbqtphgFKStpar
|
||||||
|
DdduHSW1ud6Y1FVKxljo3UwCMrYm76Q/jNzXJvGs6Z1MDNsVZzGJaoqit2H2Hkvk
|
||||||
|
y+7kk3YbEDlcyVsLOw0zCKL4cd2DSNDyhIZxWo2a8Qn5IdjWAYtsTnW6MvLk/ya4
|
||||||
|
abNeRfSZwi+r37rqi9CIs++NpL5ynqkKKEMrbeLactWgHbWrZeaMyLpuUEL2GF+w
|
||||||
|
MRaAwaj7ERwT5gFJRqYwj6bbfIdx5PC7h7ucbyp272MbrDa6WNBCMwQO222t4wID
|
||||||
|
AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmXfrC42nW
|
||||||
|
IpL3JDkB8YlB2QUvD9JdMp98xxo33+xE69Gov0e6984F1Gluao0p6sS7KF+q3YLS
|
||||||
|
4hjnzuGzF9GJMimIB7NMQ20yXKfKpmKJ7YugMaKTDWDhHn5679mKVbLSQxHCUMEe
|
||||||
|
tEnMT93/UaDbWBjV6zu876q5vjPMYgDHODqO295ySaA71UkijaCn6UwKUT49286T
|
||||||
|
V9ZtzgabNGHXfklHgUPWoShyze+G3g29I1BR0qABoJI63zaNu8ua42v5g1RldxsW
|
||||||
|
X8yKI14mFOGxuvcygG8L2xxysW7Zq+9g+O7gW0Pm6RDYnUQmIwY83h1KFCtYCJdS
|
||||||
|
2PgozwkkUNyP
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
A25EB184B01D7FBB
|
||||||
27
libraries/WiFi/examples/BearSSL_ServerClientCert/ca_key.pem
Normal file
27
libraries/WiFi/examples/BearSSL_ServerClientCert/ca_key.pem
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEAxsa4qU/tlzN4YTcnn/I/ffsijOPc8QRcwClKzasIZNFEye4u
|
||||||
|
Thl+LGZWFIFb8X8Dc+xmmBaWlPJbqtphgFKStparDdduHSW1ud6Y1FVKxljo3UwC
|
||||||
|
MrYm76Q/jNzXJvGs6Z1MDNsVZzGJaoqit2H2Hkvky+7kk3YbEDlcyVsLOw0zCKL4
|
||||||
|
cd2DSNDyhIZxWo2a8Qn5IdjWAYtsTnW6MvLk/ya4abNeRfSZwi+r37rqi9CIs++N
|
||||||
|
pL5ynqkKKEMrbeLactWgHbWrZeaMyLpuUEL2GF+wMRaAwaj7ERwT5gFJRqYwj6bb
|
||||||
|
fIdx5PC7h7ucbyp272MbrDa6WNBCMwQO222t4wIDAQABAoIBABP6hzblRLEMyE2l
|
||||||
|
GIN3+q+z3R4iDOPgl13tCIqxZQ+VBP/yw46v+0GFK6O1+MLGDFfLa+hfZNUlotcC
|
||||||
|
Sgh2xC476IdknrmpP6Gl4OB+jhxvdUBA0nu8WR9+97A1xh4w7jswxyMHphgQH4qo
|
||||||
|
0n/yBaW35RAmO60iksfHrC7EytUtahZkWq13xZsN8VNEn3dS/M54XEEQp+BLXZEh
|
||||||
|
WTd4sm5ddK58NZwLvkn0zaMyH38tllF7sezxZxWz+q4yCOB1/Xw0BC3e7dqBLtaC
|
||||||
|
PHrxWedph9sF+HXyDoXXp6S6IfSlXnCwMl0e3xBppIY9BYDnVwZpGxfUAMg26RyH
|
||||||
|
w5UEmPECgYEA51v0bxjZ/3boOH44glEFfmcJCLacoeQud+DZEMWFxmkApEVn9211
|
||||||
|
t1G+N8rnHBiAhi9bDhi3Qs9fvOxXBhqaLw1xV8KGNY8bKiKoUu8y1aeHWPbgmzYp
|
||||||
|
sfrX70mhgHUgJt4i6xzW5esTmXl3ZAqPWxzECavmoLbHnssouPb5YckCgYEA2/Jj
|
||||||
|
LPlP4XN8b4NpOhYlHmMEIwD7utIct5/7ydjtucUQAHqJ+EQ20R4MCHc9zTvjeyZ9
|
||||||
|
H/Rdxo+L0pwpbqSr0JTxOqQ1GzqstT9jVYNs+tRIQoeskd+Ags34sDJwPIbGUPfz
|
||||||
|
rBOfcHLwGfAMMBQzk5zT8frAZQV/8H7ejpCxyEsCgYBIptOnX4J1en2J3/kW0yKK
|
||||||
|
gwiPN+kP3XvKIU2Iur47hBWzgCgZxsHEg2LcWlcgt4EEojJRxukljcFerkjVndz1
|
||||||
|
EZ+aE3fZscqx/JgnEv4/oZAbG8uEcgm93iuY9OJGWIF0MyV79150bNGGzGH1hGto
|
||||||
|
DSxybQzLQxqEfv+WtdeyIQKBgQDPc8GjS8vSQ9EchQAdL4H3NUFTmrvULBW2BInC
|
||||||
|
in8+9uXu7aVwqzZg60xCN+XszA31vAnMt/ozLHWfQne5ykvcQn985iDI/ACmO5F/
|
||||||
|
uKRzuQIm7j0QoZRey9NCrXA7RouLFzOYHDIIKADbFhUIzCURl5w44l/RaOyRc7iL
|
||||||
|
E2L8HQKBgQC8WK5nT2QYtimzuwQrvSWkWyVu8/z/U8AKTusCV71uL9A6OBiUzJO3
|
||||||
|
/3Befn+qt9Nm1ZHqTsJWXIE8LPblhCkvYraq9cJ+KIymWtFVMeR99DN/yTofdyxX
|
||||||
|
Uw58Z3i5HDK4AzJhBzvk14REw5xOZZLsWAqoMHTCM/T+hVqhD+cjAw==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
[ req ]
|
||||||
|
prompt = no
|
||||||
|
default_bits = 2048
|
||||||
|
distinguished_name = req_dn
|
||||||
|
|
||||||
|
[ req_dn ]
|
||||||
|
O = My Client Org
|
||||||
|
CN = 127.0.0.2
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICyTCCAbECCQCiXrGEsB1/uzANBgkqhkiG9w0BAQsFADAhMQswCQYDVQQGEwJV
|
||||||
|
UzESMBAGA1UEAwwJMTI3LjAuMC4zMB4XDTE4MDMxNDA0MjIwNloXDTI5MDIyNDA0
|
||||||
|
MjIwNlowLDEWMBQGA1UECgwNTXkgQ2xpZW50IE9yZzESMBAGA1UEAwwJMTI3LjAu
|
||||||
|
MC4yMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5MW88nCi2tUrf/Tq
|
||||||
|
5w+5IvuqTAusaN4eelwS69sd9yXfM/DEgipw7o4t340oGdLVA4b7h1Qwxttw62ki
|
||||||
|
Z5VecXosg7xbJSjbB4LLLcmvC0pYvCactMWI+k4Na6VA1cS+hMsgnd37Shzo3Gyz
|
||||||
|
2AxrpMrcANsIaLD+o9Ji/00XmbvA/dKW/sG6vK5rWjNV0JE9WVjAW+eek8doIjh5
|
||||||
|
mOKVR7zVeR1cr8wTp48e6LX9oJsv9nfACyIyMGCFp8qa+zQEBNKevohEl9OOi9Vh
|
||||||
|
H50UU6UEo0ZGAzWF8fp+T4ltTFxr/T0PXn5J2Kk2Wl5Zt5XLt0cDBlrMDpz24ZAQ
|
||||||
|
go/CDwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA/6HqENDo5gsxWQIyC+fRFEUIy
|
||||||
|
cJ2lOlGxrf83oc1I5V10A8r6aOcwNoYlMq1Upcu2oAk2Kf5X9pq6EbM7BXuBESm4
|
||||||
|
TYYPawv3lHeiX8uX3iUReasDLBTbj4WycteSjI4JUVPvZv8ILznKkKLr2tGV19ha
|
||||||
|
UfFu/cc3iazMt0jMORd6gznWxkbgY9Qr3V4VNReD0ZUa0s9ANOjnKRIXymRicCRy
|
||||||
|
HNwSXsj/sQR1lbnI1pkyGlTZaigADlqIsH+XJjYuVxdUge5Cz1+D9kcjF9PjF4V1
|
||||||
|
u/lw6sR50qc2k5rC1WK4QLlgoknd5+ZrRiHlZXrJdcj9KnWdh4aGa3jwJpOW
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEA5MW88nCi2tUrf/Tq5w+5IvuqTAusaN4eelwS69sd9yXfM/DE
|
||||||
|
gipw7o4t340oGdLVA4b7h1Qwxttw62kiZ5VecXosg7xbJSjbB4LLLcmvC0pYvCac
|
||||||
|
tMWI+k4Na6VA1cS+hMsgnd37Shzo3Gyz2AxrpMrcANsIaLD+o9Ji/00XmbvA/dKW
|
||||||
|
/sG6vK5rWjNV0JE9WVjAW+eek8doIjh5mOKVR7zVeR1cr8wTp48e6LX9oJsv9nfA
|
||||||
|
CyIyMGCFp8qa+zQEBNKevohEl9OOi9VhH50UU6UEo0ZGAzWF8fp+T4ltTFxr/T0P
|
||||||
|
Xn5J2Kk2Wl5Zt5XLt0cDBlrMDpz24ZAQgo/CDwIDAQABAoIBAAb5eE8z2+MsCI14
|
||||||
|
HAk7U3ubjI+Q84qm6ur0D6edIIa+YtWki3kkbhj3wLJGDWjsIo5e+SAhEvOdEQ48
|
||||||
|
QE5EIYL4JI9HmMfDPRo3hJY6xdlkRNxHmRNxykFHS+VyPk3GF8DYqH/nmpeh1f+S
|
||||||
|
WNFHX6jAfoCQLOt0Ke84pMf/w65uGixdVcXgHRA/n4gKbS84a7nZEl5NqT02wrrA
|
||||||
|
BRY6pRvcsvFHaf4VEPKXpRE5UxXGMJwtyYfl9Mukszepi6g/Hk2WI499tdgDzM55
|
||||||
|
hWLRlW7ZzMILz4aP1LYt7iolKPAEst2rZdSgumIwznZUymIevlo95iYjazX9TWFv
|
||||||
|
K9LKoeECgYEA9Mj569wGYATBSD1SQzPRMQybDpBgoz+T2tfeqaas2aHcUIUK2v8c
|
||||||
|
iR5xe3soFOPTaaQBtUgo3S016SR2OLo9xY0ag71mrJZj+zuY+bPO1YMi+qh0/s5E
|
||||||
|
ZRGMzhAzTmX/5jYQmu6W5ZIAETELMZ4E8p9hW/yG+1oT4Z0csXfP4BkCgYEA70D0
|
||||||
|
Ef7e2os/76X7T2PpcLfA/4VPLS/QIbm57eVuc1GX5U7/YXdnqE4Z1pFhR+yJdId0
|
||||||
|
iqx9NxTpqxK8QTkswZSeltLXnvWxlZWjsW+GdhwzrLjjA8OAuZqk/uiNVVTavl0M
|
||||||
|
vjxTJWAiRU3PF9bLeFvF059HuflnFOqwtiyEWGcCgYBOWMUlKJchxGPYq0fZGoyq
|
||||||
|
Fk7KqotDtOWt9cneoupP/e52Fx8SWPTZLlVEIHcDuKfB+CxTyXTK1d2bcYAlR/bd
|
||||||
|
c/w4jjZ+puP5VWnxAgwBaqeXcrN/mqVpc+SNT8IcJalyFXvbGuJROBmtZvUePGV5
|
||||||
|
Amo29ux9JqeWXqMAakiugQKBgB50MB0SSh+bVfoVMJX8a7xzR1e/CkMAMQf58ha7
|
||||||
|
+4EmQ6Vmls87ObCMsHFFdBKJoz13+HemWRHn0Y57BgdvVakWV9Fu6Q9Mytv1fi6Z
|
||||||
|
uY3TLSixKARUoE//xTzFMShJcsaEZZjZaOP7BqG3s8KfDqs1U0sKnUCo5FwfO3sU
|
||||||
|
04vFAoGALjVG6v0IpvPFZcJBN8wUuu9cLduyCnUiFsMYgfglXDSkynRS51/7Fxqf
|
||||||
|
q0ROTeHrKem3iiJ62j7U3tNni2awczWCgTlUjSQzBQo6Cu1UA52M3/XyqVNmfx/g
|
||||||
|
04dVpDrqFscdIasQcL1UddiwcT2a63RjriBaTETvjegoNVu1XR4=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIICcTCCAVkCAQAwLDEWMBQGA1UECgwNTXkgQ2xpZW50IE9yZzESMBAGA1UEAwwJ
|
||||||
|
MTI3LjAuMC4yMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5MW88nCi
|
||||||
|
2tUrf/Tq5w+5IvuqTAusaN4eelwS69sd9yXfM/DEgipw7o4t340oGdLVA4b7h1Qw
|
||||||
|
xttw62kiZ5VecXosg7xbJSjbB4LLLcmvC0pYvCactMWI+k4Na6VA1cS+hMsgnd37
|
||||||
|
Shzo3Gyz2AxrpMrcANsIaLD+o9Ji/00XmbvA/dKW/sG6vK5rWjNV0JE9WVjAW+ee
|
||||||
|
k8doIjh5mOKVR7zVeR1cr8wTp48e6LX9oJsv9nfACyIyMGCFp8qa+zQEBNKevohE
|
||||||
|
l9OOi9VhH50UU6UEo0ZGAzWF8fp+T4ltTFxr/T0PXn5J2Kk2Wl5Zt5XLt0cDBlrM
|
||||||
|
Dpz24ZAQgo/CDwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAFLPF8/g9IMgQZvk
|
||||||
|
ZXvgPPPUAvANX3e0mcivjZD1BoqQ7CHeBqDpaaqH6i0qZrRQI6oli69IeQczkrXh
|
||||||
|
onhzLvCVoWmS1FH9JyWozRO6LeePEtV0jzxBDxHAd3pmlqTwLEpm0LfpBMkMe0Cb
|
||||||
|
r+3bOvAqW4ILkdSJ5FiAqlubu4+ezSLQTS/EJ+BzLkhuVuERqXFo/tW5KqviYbTL
|
||||||
|
XbvoLRVydNOUVZ+ts9YAtYLsqGoB6Rax6IzoLz5BXe5edw3FAEuotAJaLgWkBh/A
|
||||||
|
283zzb0pIUiZdF+8n61Fg4qFMZYYps4Fll4FXTn4mIzsfbJpkPXYGGuKvla46svH
|
||||||
|
tpAv/so=
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
[ req ]
|
||||||
|
prompt = no
|
||||||
|
default_bits = 2048
|
||||||
|
distinguished_name = req_dn
|
||||||
|
|
||||||
|
[ req_dn ]
|
||||||
|
O = My Server Org
|
||||||
|
CN = 127.0.0.3
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDTzCCAjcCCQDPXvMRYOpeuDANBgkqhkiG9w0BAQsFADCBpjESMBAGA1UEAwwJ
|
||||||
|
MTI3LjAuMC4xMQswCQYDVQQGEwJVUzElMCMGA1UECgwcTXkgT3duIENlcnRpZmlj
|
||||||
|
YXRlIEF1dGhvcml0eTEUMBIGA1UECAwLQXJkdWlub0xhbmQxFTATBgNVBAcMDEFy
|
||||||
|
ZHVpbm9WaWxsZTEVMBMGA1UECgwMRVNQODI2NlVzZXJzMRgwFgYDVQQLDA9FU1A4
|
||||||
|
MjY2LUFyZHVpbm8wHhcNMTgwMzE0MDQwMDAwWhcNMjkwMjI0MDQwMDAwWjAsMRYw
|
||||||
|
FAYDVQQKDA1NeSBTZXJ2ZXIgT3JnMRIwEAYDVQQDDAkxMjcuMC4wLjMwggEiMA0G
|
||||||
|
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxE1VO+o/75hSHw2ttfATzfFWwOpwH
|
||||||
|
cXvrFxc0oUMRF9V3Y/8u/IOi8JyhC1PRQJGA9zFGnz3gS48f9G7pnYu7zmxX/+Lt
|
||||||
|
x7bu1zZZEVJ+6GVHEc8slYfFOXUIR9en+jCQQJDgwHenDoSRzXqJMQ+J7NMb5P6Z
|
||||||
|
D8GSIjBwgroIyWlH0Mh5hROq/R/02tR8CN0GuqUQ7aCmAW8sWuQMRTae0Ahzho84
|
||||||
|
/vIM7Kb/HN/LpOIbxajueWHoz3vFNkZ9sQ8If2tkOOjmKy3KbUfMXk/4I6r45NI+
|
||||||
|
xyMUZeiL3vyjqFnBruLPGiuDiHlrmUaeyFG7YaX5ht9rXg7Cciu//IKzAgMBAAEw
|
||||||
|
DQYJKoZIhvcNAQELBQADggEBAEnG+FNyNCOkBvzHiUpHHpScxZqM2f+XDcewJgeS
|
||||||
|
L6HkYEDIZZDNnd5gduSvkHpdJtWgsvJ7dJZL40w7Ba5sxpZHPIgKJGl9hzMkG+aA
|
||||||
|
z5GMkjys9h2xpQZx9KL3q7G6A+C0bll7ODZlwBtY07CFMykT4Mp2oMRrQKRucMSV
|
||||||
|
AB1mKujLAnMRKJ3NM89RQJH4GYiRps9y/HvM5lh7EIK/J0/nEZeJxY5hJngskPKb
|
||||||
|
oPPdmkR97kaQnll4KNsC3owVlHVU2fMftgYkgQLzyeWgzcNa39AF3B6JlcOzNyQY
|
||||||
|
seoK24dHmt6tWmn/sbxX7Aa6TL/4mVlFoOgcaTJyVaY/BrY=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAsRNVTvqP++YUh8NrbXwE83xVsDqcB3F76xcXNKFDERfVd2P/
|
||||||
|
LvyDovCcoQtT0UCRgPcxRp894EuPH/Ru6Z2Lu85sV//i7ce27tc2WRFSfuhlRxHP
|
||||||
|
LJWHxTl1CEfXp/owkECQ4MB3pw6Ekc16iTEPiezTG+T+mQ/BkiIwcIK6CMlpR9DI
|
||||||
|
eYUTqv0f9NrUfAjdBrqlEO2gpgFvLFrkDEU2ntAIc4aPOP7yDOym/xzfy6TiG8Wo
|
||||||
|
7nlh6M97xTZGfbEPCH9rZDjo5istym1HzF5P+COq+OTSPscjFGXoi978o6hZwa7i
|
||||||
|
zxorg4h5a5lGnshRu2Gl+Ybfa14OwnIrv/yCswIDAQABAoIBAHxwgbsHCriTcEoY
|
||||||
|
Yx6F0VTrQ6ydA5mXfuYvS/eIfIE+pp1IgMScYEXZobjrJPQg1CA1l0NyFSHS97oV
|
||||||
|
JPy34sMQxcLx6KABgeVHCMJ/EeJtnv7a3SUP0GIhhsVS95Lsl8RIG4hWub+EzFVK
|
||||||
|
eZqAB9N9wr4Pp3wZPodbz37B38rb1QPyMFmQOLlHjKTOmoxsXhL2ot+R3+aLYSur
|
||||||
|
oPO1kQo7/d0UAZoy8h9OQN4a2EXvawh4O2EvFGbc5X/yXwAdEQ4NPp9VZhkNIRkV
|
||||||
|
+XZ3FcIqEVOploKtRF/tVBTz3g61/lFz21L9PMmV5y8tvSafr2SpJugGVmp2rrVQ
|
||||||
|
VNyGlIECgYEA10JSI5gmeCU3zK6kvOfBp54hY/5dDrSUpjKkMxpmm7WZQ6Il/k7A
|
||||||
|
hMcLeMzHiriT7WhRIXF8AOr2MoEkHkH3DhVNN4ccieVZx2SE5P5mVkItZGLrrpfU
|
||||||
|
dysR/ARAI1HYegGUiKacZtf9SrRavU0m7fOVOiYwbFRhjyX+MyuteYkCgYEA0pbz
|
||||||
|
4ZosetScP68uZx1sGlTfkcqLl7i15DHk3gnj6jKlfhvC2MjeLMhNDtKeUAuY7rLQ
|
||||||
|
guZ0CCghWAv0Glh5eYdfIiPhgqFfX4P5F3Om4zQHVPYj8xHfHG4ZP7dKQTndrO1Q
|
||||||
|
fLdGDTQLVXabAUSp2YGrijC8J9idSW1pYClvF1sCgYEAjkDn41nzYkbGP1/Swnwu
|
||||||
|
AEWCL4Czoro32jVxScxSrugt5wJLNWp508VukWBTJhugtq3Pn9hNaJXeKbYqVkyl
|
||||||
|
pgrxwpZph7+nuxt0r5hnrO2C7eppcjIoWLB/7BorAKxf8REGReBFT7nBTBMwPBW2
|
||||||
|
el4U6h6+tXh2GJG1Eb/1nnECgYAydVb0THOx7rWNkNUGggc/++why61M6kYy6j2T
|
||||||
|
cj05BW+f2tkCBoctpcTI83BZb53yO8g4RS2yMqNirGKN2XspwmTqEjzbhv0KLt4F
|
||||||
|
X4GyWOoU0nFksXiLIFpOaQWSwWG7KJWrfGJ9kWXR0Xxsfl5QLoDCuNCsn3t4d43T
|
||||||
|
K7phlwKBgHDzF+50+/Wez3YHCy2a/HgSbHCpLQjkknvgwkOh1z7YitYBUm72HP8Z
|
||||||
|
Ge6b4wEfNuBdlZll/y9BQQOZJLFvJTE5t51X9klrkGrOb+Ftwr7eI/H5xgcadI52
|
||||||
|
tPYglR5fjuRF/wnt3oX9JlQ2RtSbs+3naXH8JoherHaqNn8UpH0t
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
143
libraries/WiFi/examples/BearSSL_Sessions/BearSSL_Sessions.ino
Normal file
143
libraries/WiFi/examples/BearSSL_Sessions/BearSSL_Sessions.ino
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
// Example of using SSL sessions to speed up SSL connection initiation
|
||||||
|
//
|
||||||
|
// Note that sessions are a function of individual HTTPS servers, so if you
|
||||||
|
// are connecting to a service through a load abalncer (i.e. Azure, AWS, GitHub)
|
||||||
|
// two connections to the same IP address will generally connect to two
|
||||||
|
// different web servers, meaning that sessions won't work. If you are
|
||||||
|
// connecting to a single server not behind a load balancer/etc., however,
|
||||||
|
// there should be a significant speedup.
|
||||||
|
//
|
||||||
|
// September 2018 by Earle F. Philhower, III
|
||||||
|
// Released to the public domain
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "certs.h"
|
||||||
|
|
||||||
|
#ifndef STASSID
|
||||||
|
#define STASSID "your-ssid"
|
||||||
|
#define STAPSK "your-password"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *ssid = STASSID;
|
||||||
|
const char *pass = STAPSK;
|
||||||
|
|
||||||
|
const char *path = "/";
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.printf("Connecting to %s\n", ssid);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("\nConnected");
|
||||||
|
Serial.println("IP Address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
// Set up time to allow for certificate validation
|
||||||
|
NTP.begin("pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Serial.print("Waiting for NTP time sync: ");
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
while (now < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&now, &timeinfo);
|
||||||
|
Serial.print("Current time: ");
|
||||||
|
Serial.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response
|
||||||
|
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
|
||||||
|
if (!path) {
|
||||||
|
path = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Trying: %s:443...", host);
|
||||||
|
client->connect(host, port);
|
||||||
|
if (!client->connected()) {
|
||||||
|
Serial.printf("*** Can't connect. ***\n-------\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.printf("Connected!\n-------\n");
|
||||||
|
client->write("GET ");
|
||||||
|
client->write(path);
|
||||||
|
client->write(" HTTP/1.0\r\nHost: ");
|
||||||
|
client->write(host);
|
||||||
|
client->write("\r\nUser-Agent: Raspberry Pi Pico W\r\n");
|
||||||
|
client->write("\r\n");
|
||||||
|
uint32_t to = millis() + 5000;
|
||||||
|
if (client->connected()) {
|
||||||
|
do {
|
||||||
|
char tmp[32];
|
||||||
|
memset(tmp, 0, 32);
|
||||||
|
int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
|
||||||
|
yield();
|
||||||
|
if (rlen < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Only print out first line up to \r, then abort connection
|
||||||
|
char *nl = strchr(tmp, '\r');
|
||||||
|
if (nl) {
|
||||||
|
*nl = 0;
|
||||||
|
Serial.print(tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.print(tmp);
|
||||||
|
} while (millis() < to);
|
||||||
|
}
|
||||||
|
client->stop();
|
||||||
|
Serial.printf("\n-------\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
uint32_t start, finish;
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
BearSSL::X509List cert(certForum);
|
||||||
|
const char *host = "esp8266.com";
|
||||||
|
const int port = 443;
|
||||||
|
|
||||||
|
Serial.printf("Connecting without sessions...");
|
||||||
|
start = millis();
|
||||||
|
client.setTrustAnchors(&cert);
|
||||||
|
fetchURL(&client, host, port, path);
|
||||||
|
finish = millis();
|
||||||
|
Serial.printf("Total time: %dms\n", finish - start);
|
||||||
|
|
||||||
|
BearSSL::Session session;
|
||||||
|
client.setSession(&session);
|
||||||
|
Serial.printf("Connecting with an uninitialized session...");
|
||||||
|
start = millis();
|
||||||
|
client.setTrustAnchors(&cert);
|
||||||
|
fetchURL(&client, host, port, path);
|
||||||
|
finish = millis();
|
||||||
|
Serial.printf("Total time: %dms\n", finish - start);
|
||||||
|
|
||||||
|
Serial.printf("Connecting with the just initialized session...");
|
||||||
|
start = millis();
|
||||||
|
client.setTrustAnchors(&cert);
|
||||||
|
fetchURL(&client, host, port, path);
|
||||||
|
finish = millis();
|
||||||
|
Serial.printf("Total time: %dms\n", finish - start);
|
||||||
|
|
||||||
|
Serial.printf("Connecting again with the initialized session...");
|
||||||
|
start = millis();
|
||||||
|
client.setTrustAnchors(&cert);
|
||||||
|
fetchURL(&client, host, port, path);
|
||||||
|
finish = millis();
|
||||||
|
Serial.printf("Total time: %dms\n", finish - start);
|
||||||
|
|
||||||
|
delay(10000); // Avoid DDOSing github
|
||||||
|
}
|
||||||
34
libraries/WiFi/examples/BearSSL_Sessions/certs.h
Normal file
34
libraries/WiFi/examples/BearSSL_Sessions/certs.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
const char certForum [] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||||
|
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||||
|
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||||
|
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
||||||
|
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
||||||
|
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
||||||
|
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
||||||
|
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
||||||
|
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
||||||
|
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
||||||
|
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
||||||
|
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
||||||
|
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
||||||
|
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
||||||
|
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
||||||
|
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
||||||
|
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||||
|
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
||||||
|
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
||||||
|
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
||||||
|
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
||||||
|
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
||||||
|
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
||||||
|
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
||||||
|
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
||||||
|
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
||||||
|
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
||||||
|
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
||||||
|
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
|
@ -0,0 +1,197 @@
|
||||||
|
// Example of the different modes of the X.509 validation options
|
||||||
|
// in the WiFiClientBearSSL object
|
||||||
|
//
|
||||||
|
// Mar 2018 by Earle F. Philhower, III
|
||||||
|
// Released to the public domain
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <StackThunk.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "certs.h"
|
||||||
|
|
||||||
|
#ifndef STASSID
|
||||||
|
#define STASSID "your-ssid"
|
||||||
|
#define STAPSK "your-password"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *ssid = STASSID;
|
||||||
|
const char *pass = STAPSK;
|
||||||
|
|
||||||
|
const char *path = "/";
|
||||||
|
|
||||||
|
// Set time via NTP, as required for x.509 validation
|
||||||
|
void setClock() {
|
||||||
|
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Serial.print("Waiting for NTP time sync: ");
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
while (now < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&now, &timeinfo);
|
||||||
|
Serial.print("Current time: ");
|
||||||
|
Serial.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response
|
||||||
|
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
|
||||||
|
if (!path) {
|
||||||
|
path = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Trying: %s:443...", host);
|
||||||
|
client->connect(host, port);
|
||||||
|
if (!client->connected()) {
|
||||||
|
Serial.printf("*** Can't connect. ***\n-------\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.printf("Connected!\n-------\n");
|
||||||
|
client->write("GET ");
|
||||||
|
client->write(path);
|
||||||
|
client->write(" HTTP/1.0\r\nHost: ");
|
||||||
|
client->write(host);
|
||||||
|
client->write("\r\nUser-Agent: Raspberry Pi Pico W\r\n");
|
||||||
|
client->write("\r\n");
|
||||||
|
uint32_t to = millis() + 5000;
|
||||||
|
if (client->connected()) {
|
||||||
|
do {
|
||||||
|
char tmp[32];
|
||||||
|
memset(tmp, 0, 32);
|
||||||
|
int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
|
||||||
|
yield();
|
||||||
|
if (rlen < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Only print out first line up to \r, then abort connection
|
||||||
|
char *nl = strchr(tmp, '\r');
|
||||||
|
if (nl) {
|
||||||
|
*nl = 0;
|
||||||
|
Serial.print(tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.print(tmp);
|
||||||
|
} while (millis() < to);
|
||||||
|
}
|
||||||
|
client->stop();
|
||||||
|
Serial.printf("BSSL stack used: %d\n-------\n\n", stack_thunk_get_max_usage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchNoConfig() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
If there are no CAs or insecure options specified, BearSSL will not connect.
|
||||||
|
Expect the following call to fail as none have been configured.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
fetchURL(&client, ssl_host, ssl_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchInsecure() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
This is absolutely *insecure*, but you can tell BearSSL not to check the
|
||||||
|
certificate of the server. In this mode it will accept ANY certificate,
|
||||||
|
which is subject to man-in-the-middle (MITM) attacks.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
client.setInsecure();
|
||||||
|
fetchURL(&client, ssl_host, ssl_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchFingerprint() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
The SHA-1 fingerprint of an X.509 certificate can be used to validate it
|
||||||
|
instead of the while certificate. This is not nearly as secure as real
|
||||||
|
X.509 validation, but is better than nothing. Also be aware that these
|
||||||
|
fingerprints will change if anything changes in the certificate chain
|
||||||
|
(i.e. re-generating the certificate for a new end date, any updates to
|
||||||
|
the root authorities, etc.).
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
client.setFingerprint(fingerprint_ssl);
|
||||||
|
fetchURL(&client, ssl_host, ssl_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchSelfSigned() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
It is also possible to accept *any* self-signed certificate. This is
|
||||||
|
absolutely insecure as anyone can make a self-signed certificate.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
Serial.printf("First, try and connect to a badssl.com self-signed website (will fail):\n");
|
||||||
|
fetchURL(&client, "self-signed.badssl.com", 443, "/");
|
||||||
|
Serial.printf("Now we'll enable self-signed certs (will pass)\n");
|
||||||
|
client.allowSelfSignedCerts();
|
||||||
|
fetchURL(&client, "self-signed.badssl.com", 443, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchKnownKey() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
The server certificate can be completely ignored and its public key
|
||||||
|
hardcoded in your application. This should be secure as the public key
|
||||||
|
needs to be paired with the private key of the site, which is obviously
|
||||||
|
private and not shared. A MITM without the private key would not be
|
||||||
|
able to establish communications.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
BearSSL::PublicKey key(pubkey_ssl);
|
||||||
|
client.setKnownKey(&key);
|
||||||
|
fetchURL(&client, ssl_host, ssl_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchCertAuthority() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
A specific certification authority can be passed in and used to validate
|
||||||
|
a chain of certificates from a given server. These will be validated
|
||||||
|
using BearSSL's rules, which do NOT include certificate revocation lists.
|
||||||
|
A specific server's certificate, or your own self-signed root certificate
|
||||||
|
can also be used. Pico W time needs to be valid for checks to pass as
|
||||||
|
BearSSL does verify the notValidBefore/After fields.
|
||||||
|
)EOF");
|
||||||
|
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
BearSSL::X509List cert(cert_CA);
|
||||||
|
client.setTrustAnchors(&cert);
|
||||||
|
Serial.printf("Try validating without setting the time (should fail)\n");
|
||||||
|
fetchURL(&client, ssl_host, ssl_port, path);
|
||||||
|
|
||||||
|
Serial.printf("Try again after setting NTP time (should pass)\n");
|
||||||
|
setClock();
|
||||||
|
fetchURL(&client, ssl_host, ssl_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
Serial.println("WiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
fetchNoConfig();
|
||||||
|
fetchInsecure();
|
||||||
|
fetchFingerprint();
|
||||||
|
fetchSelfSigned();
|
||||||
|
fetchKnownKey();
|
||||||
|
fetchCertAuthority();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Nothing to do here
|
||||||
|
}
|
||||||
47
libraries/WiFi/examples/BearSSL_Validation/certs.h
Normal file
47
libraries/WiFi/examples/BearSSL_Validation/certs.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// certificate chain for www.akamai.com:443
|
||||||
|
|
||||||
|
const char* ssl_host = "www.akamai.com";
|
||||||
|
const uint16_t ssl_port = 443;
|
||||||
|
|
||||||
|
|
||||||
|
const char fingerprint_ssl [] PROGMEM = "48:EF:70:29:41:CE:64:C9:DF:57:A2:46:E8:34:E1:50:0B:70:AE:17";
|
||||||
|
const char pubkey_ssl [] PROGMEM = R"PUBKEY(
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiuc+zlu43bv55+s0Fj6RiBW+olZm
|
||||||
|
c/AkoTP48CFCIGP1DET7Oufx6oe63GIuBzdVfR5D6R2z818b5gY1o2lBxg==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
)PUBKEY";
|
||||||
|
|
||||||
|
const char cert_CA [] PROGMEM = R"CERT(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEvjCCA6agAwIBAgIQBtjZBNVYQ0b2ii+nVCJ+xDANBgkqhkiG9w0BAQsFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaME8xCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBS
|
||||||
|
U0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||||
|
AQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6a
|
||||||
|
qXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddn
|
||||||
|
g9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuW
|
||||||
|
raKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB
|
||||||
|
Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21r
|
||||||
|
eacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBgjCCAX4wEgYDVR0TAQH/BAgwBgEB
|
||||||
|
/wIBADAdBgNVHQ4EFgQUt2ui6qiqhIx56rTaD5iyxZV2ufQwHwYDVR0jBBgwFoAU
|
||||||
|
A95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
|
||||||
|
CCsGAQUFBwMBBggrBgEFBQcDAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGG
|
||||||
|
GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2Nh
|
||||||
|
Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDBCBgNV
|
||||||
|
HR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRH
|
||||||
|
bG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwCwYJYIZIAYb9bAIBMAcGBWeBDAEB
|
||||||
|
MAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IB
|
||||||
|
AQCAMs5eC91uWg0Kr+HWhMvAjvqFcO3aXbMM9yt1QP6FCvrzMXi3cEsaiVi6gL3z
|
||||||
|
ax3pfs8LulicWdSQ0/1s/dCYbbdxglvPbQtaCdB73sRD2Cqk3p5BJl+7j5nL3a7h
|
||||||
|
qG+fh/50tx8bIKuxT8b1Z11dmzzp/2n3YWzW2fP9NsarA4h20ksudYbj/NhVfSbC
|
||||||
|
EXffPgK2fPOre3qGNm+499iTcc+G33Mw+nur7SpZyEKEOxEXGlLzyQ4UfaJbcme6
|
||||||
|
ce1XR2bFuAJKZTRei9AqPCCcUZlM51Ke92sRKw2Sfh3oius2FkOH6ipjv3U/697E
|
||||||
|
A7sKPPcw7+uvTPyLNhBzPvOk
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)CERT";
|
||||||
|
|
@ -13,6 +13,7 @@ WiFiClient KEYWORD1
|
||||||
WiFiSSLClient KEYWORD1
|
WiFiSSLClient KEYWORD1
|
||||||
WiFiServer KEYWORD1
|
WiFiServer KEYWORD1
|
||||||
WiFiUDP KEYWORD1
|
WiFiUDP KEYWORD1
|
||||||
|
NTP KEYWORD1
|
||||||
|
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
|
|
|
||||||
1000
libraries/WiFi/src/BearSSLHelpers.cpp
Normal file
1000
libraries/WiFi/src/BearSSLHelpers.cpp
Normal file
File diff suppressed because it is too large
Load diff
245
libraries/WiFi/src/BearSSLHelpers.h
Normal file
245
libraries/WiFi/src/BearSSLHelpers.h
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
|
||||||
|
- Mostly compatible with Arduino WiFi shield library and standard
|
||||||
|
WiFiClient/ServerSecure (except for certificate handling).
|
||||||
|
|
||||||
|
Copyright (c) 2018 Earle F. Philhower, III
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <bearssl/bearssl.h>
|
||||||
|
//#include <Updater.h>
|
||||||
|
|
||||||
|
// Internal opaque structures, not needed by user applications
|
||||||
|
namespace brssl {
|
||||||
|
class public_key;
|
||||||
|
class private_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace BearSSL {
|
||||||
|
|
||||||
|
// Holds either a single public RSA or EC key for use when BearSSL wants a pubkey.
|
||||||
|
// Copies all associated data so no need to keep input PEM/DER keys.
|
||||||
|
// All inputs can be either in RAM or PROGMEM.
|
||||||
|
class PublicKey {
|
||||||
|
public:
|
||||||
|
PublicKey();
|
||||||
|
PublicKey(const char *pemKey);
|
||||||
|
PublicKey(const uint8_t *derKey, size_t derLen);
|
||||||
|
PublicKey(Stream& stream, size_t size);
|
||||||
|
PublicKey(Stream& stream) : PublicKey(stream, stream.available()) { };
|
||||||
|
~PublicKey();
|
||||||
|
|
||||||
|
bool parse(const char *pemKey);
|
||||||
|
bool parse(const uint8_t *derKey, size_t derLen);
|
||||||
|
|
||||||
|
// Accessors for internal use, not needed by apps
|
||||||
|
bool isRSA() const;
|
||||||
|
bool isEC() const;
|
||||||
|
const br_rsa_public_key *getRSA() const;
|
||||||
|
const br_ec_public_key *getEC() const;
|
||||||
|
|
||||||
|
// Disable the copy constructor, we're pointer based
|
||||||
|
PublicKey(const PublicKey& that) = delete;
|
||||||
|
PublicKey& operator=(const PublicKey& that) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
brssl::public_key *_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Holds either a single private RSA or EC key for use when BearSSL wants a secretkey.
|
||||||
|
// Copies all associated data so no need to keep input PEM/DER keys.
|
||||||
|
// All inputs can be either in RAM or PROGMEM.
|
||||||
|
class PrivateKey {
|
||||||
|
public:
|
||||||
|
PrivateKey();
|
||||||
|
PrivateKey(const char *pemKey);
|
||||||
|
PrivateKey(const uint8_t *derKey, size_t derLen);
|
||||||
|
PrivateKey(Stream& stream, size_t size);
|
||||||
|
PrivateKey(Stream& stream) : PrivateKey(stream, stream.available()) { };
|
||||||
|
~PrivateKey();
|
||||||
|
|
||||||
|
bool parse(const char *pemKey);
|
||||||
|
bool parse(const uint8_t *derKey, size_t derLen);
|
||||||
|
|
||||||
|
// Accessors for internal use, not needed by apps
|
||||||
|
bool isRSA() const;
|
||||||
|
bool isEC() const;
|
||||||
|
const br_rsa_private_key *getRSA() const;
|
||||||
|
const br_ec_private_key *getEC() const;
|
||||||
|
|
||||||
|
// Disable the copy constructor, we're pointer based
|
||||||
|
PrivateKey(const PrivateKey& that) = delete;
|
||||||
|
PrivateKey& operator=(const PrivateKey& that) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
brssl::private_key *_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Holds one or more X.509 certificates and associated trust anchors for
|
||||||
|
// use whenever BearSSL needs a cert or TA. May want to have multiple
|
||||||
|
// certs for things like a series of trusted CAs (but check the CertStore class
|
||||||
|
// for a more memory efficient way).
|
||||||
|
// Copies all associated data so no need to keep input PEM/DER certs.
|
||||||
|
// All inputs can be either in RAM or PROGMEM.
|
||||||
|
class X509List {
|
||||||
|
public:
|
||||||
|
X509List();
|
||||||
|
X509List(const char *pemCert);
|
||||||
|
X509List(const uint8_t *derCert, size_t derLen);
|
||||||
|
X509List(Stream& stream, size_t size);
|
||||||
|
X509List(Stream& stream) : X509List(stream, stream.available()) { };
|
||||||
|
~X509List();
|
||||||
|
|
||||||
|
bool append(const char *pemCert);
|
||||||
|
bool append(const uint8_t *derCert, size_t derLen);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
size_t getCount() const {
|
||||||
|
return _count;
|
||||||
|
}
|
||||||
|
const br_x509_certificate *getX509Certs() const {
|
||||||
|
return _cert;
|
||||||
|
}
|
||||||
|
const br_x509_trust_anchor *getTrustAnchors() const {
|
||||||
|
return _ta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the copy constructor, we're pointer based
|
||||||
|
X509List(const X509List& that) = delete;
|
||||||
|
X509List& operator=(const X509List& that) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t _count;
|
||||||
|
br_x509_certificate *_cert;
|
||||||
|
br_x509_trust_anchor *_ta;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Opaque object which wraps the BearSSL SSL session to make repeated connections
|
||||||
|
// significantly faster. Completely optional.
|
||||||
|
class WiFiClientSecure;
|
||||||
|
|
||||||
|
// Cache for a TLS session with a server
|
||||||
|
// Use with BearSSL::WiFiClientSecure::setSession
|
||||||
|
// to accelerate the TLS handshake
|
||||||
|
class Session {
|
||||||
|
friend class WiFiClientSecureCtx;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Session() {
|
||||||
|
memset(&_session, 0, sizeof(_session));
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
br_ssl_session_parameters *getSession() {
|
||||||
|
return &_session;
|
||||||
|
}
|
||||||
|
// The actual BearSSL session information
|
||||||
|
br_ssl_session_parameters _session;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represents a single server session.
|
||||||
|
// Use with BearSSL::ServerSessions.
|
||||||
|
typedef uint8_t ServerSession[100];
|
||||||
|
|
||||||
|
// Cache for the TLS sessions of multiple clients.
|
||||||
|
// Use with BearSSL::WiFiServerSecure::setCache
|
||||||
|
class ServerSessions {
|
||||||
|
friend class WiFiClientSecureCtx;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Uses the given buffer to cache the given number of sessions and initializes it.
|
||||||
|
ServerSessions(ServerSession *sessions, uint32_t size) : ServerSessions(sessions, size, false) {}
|
||||||
|
|
||||||
|
// Dynamically allocates a cache for the given number of sessions and initializes it.
|
||||||
|
// If the allocation of the buffer wasn't successful, the value
|
||||||
|
// returned by size() will be 0.
|
||||||
|
ServerSessions(uint32_t size) : ServerSessions(size > 0 ? new ServerSession[size] : nullptr, size, true) {}
|
||||||
|
|
||||||
|
~ServerSessions();
|
||||||
|
|
||||||
|
// Returns the number of sessions the cache can hold.
|
||||||
|
uint32_t size() {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ServerSessions(ServerSession *sessions, uint32_t size, bool isDynamic);
|
||||||
|
|
||||||
|
// Returns the cache's vtable or null if the cache has no capacity.
|
||||||
|
const br_ssl_session_cache_class **getCache();
|
||||||
|
|
||||||
|
// Size of the store in sessions.
|
||||||
|
uint32_t _size;
|
||||||
|
// Store where the information for the sessions are stored.
|
||||||
|
ServerSession *_store;
|
||||||
|
// Whether the store is dynamically allocated.
|
||||||
|
// If this is true, the store needs to be freed in the destructor.
|
||||||
|
bool _isDynamic;
|
||||||
|
|
||||||
|
// Cache of the server using the _store.
|
||||||
|
br_ssl_session_cache_lru _cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
// Updater SHA256 hash and signature verification
|
||||||
|
class HashSHA256 : public UpdaterHashClass {
|
||||||
|
public:
|
||||||
|
virtual void begin() override;
|
||||||
|
virtual void add(const void *data, uint32_t len) override;
|
||||||
|
virtual void end() override;
|
||||||
|
virtual int len() override;
|
||||||
|
virtual const void *hash() override;
|
||||||
|
virtual const unsigned char *oid() override;
|
||||||
|
private:
|
||||||
|
br_sha256_context _cc;
|
||||||
|
unsigned char _sha256[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
class SigningVerifier : public UpdaterVerifyClass {
|
||||||
|
public:
|
||||||
|
virtual uint32_t length() override;
|
||||||
|
virtual bool verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SigningVerifier(PublicKey *pubKey) {
|
||||||
|
_pubKey = pubKey;
|
||||||
|
stack_thunk_add_ref();
|
||||||
|
}
|
||||||
|
~SigningVerifier() {
|
||||||
|
stack_thunk_del_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PublicKey *_pubKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stack thunked versions of calls
|
||||||
|
extern "C" unsigned char *thunk_br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||||
|
extern "C" void thunk_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
|
||||||
|
extern "C" unsigned char *thunk_br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||||
|
extern "C" void thunk_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
|
||||||
|
extern "C" unsigned char *thunk_br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||||
|
extern "C" void thunk_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
|
||||||
|
extern "C" unsigned char *thunk_br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||||
|
extern "C" void thunk_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
|
||||||
236
libraries/WiFi/src/CertStoreBearSSL.cpp
Normal file
236
libraries/WiFi/src/CertStoreBearSSL.cpp
Normal file
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
CertStoreBearSSL.cpp - Library for Arduino ESP8266
|
||||||
|
Copyright (c) 2018 Earle F. Philhower, III
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CertStoreBearSSL.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(DEBUG_ESP_SSL) && defined(DEBUG_ESP_PORT)
|
||||||
|
#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DEBUG_BSSL(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace BearSSL {
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// Callback for the x509 decoder
|
||||||
|
static void dn_append(void *ctx, const void *buf, size_t len) {
|
||||||
|
br_sha256_context *sha1 = (br_sha256_context*)ctx;
|
||||||
|
br_sha256_update(sha1, buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CertStore::~CertStore() {
|
||||||
|
free(_indexName);
|
||||||
|
free(_dataName);
|
||||||
|
}
|
||||||
|
|
||||||
|
CertStore::CertInfo CertStore::_preprocessCert(uint32_t length, uint32_t offset, const void *raw) {
|
||||||
|
CertStore::CertInfo ci;
|
||||||
|
|
||||||
|
// Clear the CertInfo
|
||||||
|
memset(&ci, 0, sizeof(ci));
|
||||||
|
|
||||||
|
// Process it using SHA256, same as the hashed_dn
|
||||||
|
br_x509_decoder_context *ctx = new (std::nothrow) br_x509_decoder_context;
|
||||||
|
br_sha256_context *sha256 = new (std::nothrow) br_sha256_context;
|
||||||
|
if (!ctx || !sha256) {
|
||||||
|
if (ctx) {
|
||||||
|
delete ctx;
|
||||||
|
}
|
||||||
|
if (sha256) {
|
||||||
|
delete sha256;
|
||||||
|
}
|
||||||
|
DEBUG_BSSL("CertStore::_preprocessCert: OOM\n");
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
|
|
||||||
|
br_sha256_init(sha256);
|
||||||
|
br_x509_decoder_init(ctx, dn_append, sha256, nullptr, nullptr);
|
||||||
|
br_x509_decoder_push(ctx, (const void*)raw, length);
|
||||||
|
|
||||||
|
// Copy result to structure
|
||||||
|
br_sha256_out(sha256, &ci.sha256);
|
||||||
|
ci.length = length;
|
||||||
|
ci.offset = offset;
|
||||||
|
|
||||||
|
// Clean up allocated memory
|
||||||
|
delete sha256;
|
||||||
|
delete ctx;
|
||||||
|
|
||||||
|
// Return result
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The certs.ar file is a UNIX ar format file, concatenating all the
|
||||||
|
// individual certificates into a single blob in a space-efficient way.
|
||||||
|
int CertStore::initCertStore(fs::FS &fs, const char *indexFileName, const char *dataFileName) {
|
||||||
|
int count = 0;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
|
||||||
|
_fs = &fs;
|
||||||
|
|
||||||
|
// In case initCertStore called multiple times, don't leak old filenames
|
||||||
|
free(_indexName);
|
||||||
|
free(_dataName);
|
||||||
|
|
||||||
|
// No strdup_P, so manually do it
|
||||||
|
_indexName = (char *)malloc(strlen_P(indexFileName) + 1);
|
||||||
|
_dataName = (char *)malloc(strlen_P(dataFileName) + 1);
|
||||||
|
if (!_indexName || !_dataName) {
|
||||||
|
free(_indexName);
|
||||||
|
free(_dataName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy_P(_indexName, indexFileName, strlen_P(indexFileName) + 1);
|
||||||
|
memcpy_P(_dataName, dataFileName, strlen_P(dataFileName) + 1);
|
||||||
|
|
||||||
|
fs::File index = _fs->open(_indexName, "w");
|
||||||
|
if (!index) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::File data = _fs->open(_dataName, "r");
|
||||||
|
if (!data) {
|
||||||
|
index.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t magic[8];
|
||||||
|
if (data.read(magic, sizeof(magic)) != sizeof(magic) ||
|
||||||
|
memcmp(magic, "!<arch>\n", sizeof(magic))) {
|
||||||
|
data.close();
|
||||||
|
index.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
offset += sizeof(magic);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint8_t fileHeader[60];
|
||||||
|
// 0..15 = filename in ASCII
|
||||||
|
// 48...57 = length in decimal ASCII
|
||||||
|
int32_t length;
|
||||||
|
if (data.read(fileHeader, sizeof(fileHeader)) != sizeof(fileHeader)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
offset += sizeof(fileHeader);
|
||||||
|
fileHeader[58] = 0;
|
||||||
|
if (1 != sscanf((char *)(fileHeader + 48), "%ld", &length) || !length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *raw = malloc(length);
|
||||||
|
if (!raw) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (data.read((uint8_t *)raw, length) != length) {
|
||||||
|
free(raw);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the filename starts with "//" then this is a rename file, skip it
|
||||||
|
if (fileHeader[0] != '/' || fileHeader[1] != '/') {
|
||||||
|
CertStore::CertInfo ci = _preprocessCert(length, offset, raw);
|
||||||
|
if (index.write((uint8_t *)&ci, sizeof(ci)) != (ssize_t)sizeof(ci)) {
|
||||||
|
free(raw);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += length;
|
||||||
|
free(raw);
|
||||||
|
if (offset & 1) {
|
||||||
|
uint8_t x;
|
||||||
|
data.read(&x, 1);
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.close();
|
||||||
|
index.close();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CertStore::installCertStore(br_x509_minimal_context *ctx) {
|
||||||
|
br_x509_minimal_set_dynamic(ctx, (void*)this, findHashedTA, freeHashedTA);
|
||||||
|
}
|
||||||
|
|
||||||
|
const br_x509_trust_anchor *CertStore::findHashedTA(void *ctx, void *hashed_dn, size_t len) {
|
||||||
|
CertStore *cs = static_cast<CertStore*>(ctx);
|
||||||
|
CertStore::CertInfo ci;
|
||||||
|
|
||||||
|
if (!cs || len != sizeof(ci.sha256) || !cs->_indexName || !cs->_dataName || !cs->_fs) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::File index = cs->_fs->open(cs->_indexName, "r");
|
||||||
|
if (!index) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index.read((uint8_t *)&ci, sizeof(ci)) == sizeof(ci)) {
|
||||||
|
if (!memcmp(ci.sha256, hashed_dn, sizeof(ci.sha256))) {
|
||||||
|
index.close();
|
||||||
|
uint8_t *der = (uint8_t*)malloc(ci.length);
|
||||||
|
if (!der) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
fs::File data = cs->_fs->open(cs->_dataName, "r");
|
||||||
|
if (!data) {
|
||||||
|
free(der);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!data.seek(ci.offset, fs::SeekSet)) {
|
||||||
|
data.close();
|
||||||
|
free(der);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (data.read(der, ci.length) != (int)ci.length) {
|
||||||
|
free(der);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
data.close();
|
||||||
|
cs->_x509 = new (std::nothrow) X509List(der, ci.length);
|
||||||
|
free(der);
|
||||||
|
if (!cs->_x509) {
|
||||||
|
DEBUG_BSSL("CertStore::findHashedTA: OOM\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
br_x509_trust_anchor *ta = (br_x509_trust_anchor*)cs->_x509->getTrustAnchors();
|
||||||
|
memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256));
|
||||||
|
ta->dn.len = sizeof(ci.sha256);
|
||||||
|
|
||||||
|
return ta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index.close();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CertStore::freeHashedTA(void *ctx, const br_x509_trust_anchor *ta) {
|
||||||
|
CertStore *cs = static_cast<CertStore*>(ctx);
|
||||||
|
(void) ta; // Unused
|
||||||
|
delete cs->_x509;
|
||||||
|
cs->_x509 = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
73
libraries/WiFi/src/CertStoreBearSSL.h
Normal file
73
libraries/WiFi/src/CertStoreBearSSL.h
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
CertStoreBearSSL.h - Library for Arduino ESP8266
|
||||||
|
Copyright (c) 2018 Earle F. Philhower, III
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <BearSSLHelpers.h>
|
||||||
|
#include <bearssl/bearssl.h>
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
// Base class for the certificate stores, which allow use
|
||||||
|
// of a large set of certificates stored on FS or SD card to
|
||||||
|
// be dynamically used when validating a X509 certificate
|
||||||
|
|
||||||
|
namespace BearSSL {
|
||||||
|
|
||||||
|
class CertStoreBase {
|
||||||
|
public:
|
||||||
|
virtual ~CertStoreBase() {}
|
||||||
|
|
||||||
|
// Installs the cert store into the X509 decoder (normally via static function callbacks)
|
||||||
|
virtual void installCertStore(br_x509_minimal_context *ctx) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CertStore: public CertStoreBase {
|
||||||
|
public:
|
||||||
|
CertStore() { };
|
||||||
|
~CertStore();
|
||||||
|
|
||||||
|
// Set the file interface instances, do preprocessing
|
||||||
|
int initCertStore(fs::FS &fs, const char *indexFileName, const char *dataFileName);
|
||||||
|
|
||||||
|
// Installs the cert store into the X509 decoder (normally via static function callbacks)
|
||||||
|
void installCertStore(br_x509_minimal_context *ctx);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
fs::FS *_fs = nullptr;
|
||||||
|
char *_indexName = nullptr;
|
||||||
|
char *_dataName = nullptr;
|
||||||
|
X509List *_x509 = nullptr;
|
||||||
|
|
||||||
|
// These need to be static as they are callbacks from BearSSL C code
|
||||||
|
static const br_x509_trust_anchor *findHashedTA(void *ctx, void *hashed_dn, size_t len);
|
||||||
|
static void freeHashedTA(void *ctx, const br_x509_trust_anchor *ta);
|
||||||
|
|
||||||
|
// The binary format of the index file
|
||||||
|
class CertInfo {
|
||||||
|
public:
|
||||||
|
uint8_t sha256[32];
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
static CertInfo _preprocessCert(uint32_t length, uint32_t offset, const void *raw);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
89
libraries/WiFi/src/StackThunk.cpp
Normal file
89
libraries/WiFi/src/StackThunk.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "StackThunk.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
uint32_t *stack_thunk_ptr = NULL;
|
||||||
|
uint32_t *stack_thunk_top = NULL;
|
||||||
|
uint32_t *stack_thunk_save = NULL; /* Saved A1 while in BearSSL */
|
||||||
|
uint32_t stack_thunk_refcnt = 0;
|
||||||
|
|
||||||
|
/* Largest stack usage seen in the wild at 6120 */
|
||||||
|
#define _stackSize (6400/4)
|
||||||
|
#define _stackPaint 0xdeadbeef
|
||||||
|
|
||||||
|
/* Add a reference, and allocate the stack if necessary */
|
||||||
|
void stack_thunk_add_ref() {
|
||||||
|
stack_thunk_refcnt++;
|
||||||
|
if (stack_thunk_refcnt == 1) {
|
||||||
|
// The stack must be in DRAM, or an Soft WDT will follow. Not sure why,
|
||||||
|
// maybe too much time is consumed with the non32-bit exception handler.
|
||||||
|
// Also, interrupt handling on an IRAM stack would be very slow.
|
||||||
|
// Strings on the stack would be very slow to access as well.
|
||||||
|
stack_thunk_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
|
||||||
|
if (!stack_thunk_ptr) {
|
||||||
|
// This is a fatal error, stop the sketch
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
stack_thunk_top = stack_thunk_ptr + _stackSize - 1;
|
||||||
|
stack_thunk_save = NULL;
|
||||||
|
stack_thunk_repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drop a reference, and free stack if no more in use */
|
||||||
|
void stack_thunk_del_ref() {
|
||||||
|
if (stack_thunk_refcnt == 0) {
|
||||||
|
/* Error! */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stack_thunk_refcnt--;
|
||||||
|
if (!stack_thunk_refcnt) {
|
||||||
|
free(stack_thunk_ptr);
|
||||||
|
stack_thunk_ptr = NULL;
|
||||||
|
stack_thunk_top = NULL;
|
||||||
|
stack_thunk_save = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stack_thunk_repaint() {
|
||||||
|
for (int i = 0; i < _stackSize; i++) {
|
||||||
|
stack_thunk_ptr[i] = _stackPaint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple accessor functions used by postmortem */
|
||||||
|
uint32_t stack_thunk_get_refcnt() {
|
||||||
|
return stack_thunk_refcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_thunk_get_stack_top() {
|
||||||
|
return (uint32_t)stack_thunk_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_thunk_get_stack_bot() {
|
||||||
|
return (uint32_t)stack_thunk_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_thunk_get_cont_sp() {
|
||||||
|
return (uint32_t)stack_thunk_save;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of bytes ever used since the stack was created */
|
||||||
|
uint32_t stack_thunk_get_max_usage() {
|
||||||
|
uint32_t cnt = 0;
|
||||||
|
|
||||||
|
/* No stack == no usage by definition! */
|
||||||
|
if (!stack_thunk_ptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cnt = 0; (cnt < _stackSize) && (stack_thunk_ptr[cnt] == _stackPaint); cnt++) {
|
||||||
|
/* Noop, all work done in for() */
|
||||||
|
}
|
||||||
|
return 4 * (_stackSize - cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
48
libraries/WiFi/src/StackThunk.h
Normal file
48
libraries/WiFi/src/StackThunk.h
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void stack_thunk_add_ref();
|
||||||
|
extern void stack_thunk_del_ref();
|
||||||
|
extern void stack_thunk_repaint();
|
||||||
|
|
||||||
|
extern uint32_t stack_thunk_get_refcnt();
|
||||||
|
extern uint32_t stack_thunk_get_stack_top();
|
||||||
|
extern uint32_t stack_thunk_get_stack_bot();
|
||||||
|
extern uint32_t stack_thunk_get_cont_sp();
|
||||||
|
extern uint32_t stack_thunk_get_max_usage();
|
||||||
|
extern void stack_thunk_dump_stack();
|
||||||
|
extern void stack_thunk_fatal_overflow();
|
||||||
|
|
||||||
|
// Globals required for thunking operation
|
||||||
|
extern uint32_t *stack_thunk_ptr;
|
||||||
|
extern uint32_t *stack_thunk_top;
|
||||||
|
extern uint32_t *stack_thunk_save;
|
||||||
|
extern uint32_t stack_thunk_refcnt;
|
||||||
|
|
||||||
|
#define make_stack_thunk_void(fcnToThunk, proto, params) \
|
||||||
|
extern "C" void thunk_##fcnToThunk proto { \
|
||||||
|
register uint32_t* sp asm("sp"); \
|
||||||
|
stack_thunk_save = sp; \
|
||||||
|
sp = stack_thunk_top; \
|
||||||
|
fcnToThunk params; \
|
||||||
|
sp = stack_thunk_save; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define make_stack_thunk_unsigned_char_ptr(fcnToThunk, proto, params) \
|
||||||
|
extern "C" unsigned char * thunk_##fcnToThunk proto { \
|
||||||
|
register uint32_t* sp asm("sp"); \
|
||||||
|
stack_thunk_save = sp; \
|
||||||
|
sp = stack_thunk_top; \
|
||||||
|
auto x = fcnToThunk params; \
|
||||||
|
sp = stack_thunk_save; \
|
||||||
|
return x; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
#include "WiFiClass.h"
|
#include "WiFiClass.h"
|
||||||
#include "WiFiClient.h"
|
#include "WiFiClient.h"
|
||||||
#include "WiFiServer.h"
|
#include "WiFiServer.h"
|
||||||
//#include "WiFiClientSecure.h"
|
#include "WiFiClientSecure.h"
|
||||||
//#include "WiFiServerSecure.h"
|
#include "WiFiServerSecure.h"
|
||||||
#include "WiFiUdp.h"
|
#include "WiFiUdp.h"
|
||||||
|
|
||||||
|
#include "WiFiNTP.h"
|
||||||
|
|
|
||||||
25
libraries/WiFi/src/WiFiClientSecure.h
Normal file
25
libraries/WiFi/src/WiFiClientSecure.h
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
WiFiClientSecure.h - Variant of WiFiClient with TLS support
|
||||||
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "WiFiClient.h"
|
||||||
|
#include "WiFiClientSecureBearSSL.h"
|
||||||
|
|
||||||
|
using namespace BearSSL;
|
||||||
1663
libraries/WiFi/src/WiFiClientSecureBearSSL.cpp
Normal file
1663
libraries/WiFi/src/WiFiClientSecureBearSSL.cpp
Normal file
File diff suppressed because it is too large
Load diff
465
libraries/WiFi/src/WiFiClientSecureBearSSL.h
Normal file
465
libraries/WiFi/src/WiFiClientSecureBearSSL.h
Normal file
|
|
@ -0,0 +1,465 @@
|
||||||
|
/*
|
||||||
|
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
|
||||||
|
- Mostly compatible with Arduino WiFi shield library and standard
|
||||||
|
WiFiClient/ServerSecure (except for certificate handling).
|
||||||
|
|
||||||
|
Copyright (c) 2018 Earle F. Philhower, III
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "WiFiClient.h"
|
||||||
|
#include <bearssl/bearssl.h>
|
||||||
|
#include "BearSSLHelpers.h"
|
||||||
|
#include "CertStoreBearSSL.h"
|
||||||
|
|
||||||
|
namespace BearSSL {
|
||||||
|
|
||||||
|
class WiFiClientSecureCtx : public WiFiClient {
|
||||||
|
public:
|
||||||
|
WiFiClientSecureCtx();
|
||||||
|
WiFiClientSecureCtx(const WiFiClientSecureCtx &rhs) = delete;
|
||||||
|
~WiFiClientSecureCtx() override;
|
||||||
|
|
||||||
|
WiFiClientSecureCtx& operator=(const WiFiClientSecureCtx&) = delete;
|
||||||
|
|
||||||
|
// TODO: usage is invalid b/c of deleted copy, but this will only trigger an error when it is actually used by something
|
||||||
|
// TODO: don't remove just yet to avoid including the WiFiClient default implementation and unintentionally causing
|
||||||
|
// a 'slice' that this method tries to avoid in the first place
|
||||||
|
std::unique_ptr<WiFiClient> clone() const override {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
size_t write(const uint8_t *buf, size_t size) override;
|
||||||
|
// size_t write_P(PGM_P buf, size_t size) override;
|
||||||
|
size_t write(Stream& stream); // Note this is not virtual
|
||||||
|
int read(uint8_t *buf, size_t size) override;
|
||||||
|
int read(char *buf, size_t size) {
|
||||||
|
return read((uint8_t*)buf, size);
|
||||||
|
}
|
||||||
|
int available() override;
|
||||||
|
int read() override;
|
||||||
|
int peek() override;
|
||||||
|
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
||||||
|
bool flush(unsigned int maxWaitMs);
|
||||||
|
bool stop(unsigned int maxWaitMs);
|
||||||
|
void flush() override {
|
||||||
|
(void)flush(0);
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
(void)stop(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableForWrite() override;
|
||||||
|
|
||||||
|
// Allow sessions to be saved/restored automatically to a memory area
|
||||||
|
void setSession(Session *session) {
|
||||||
|
_session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't validate the chain, just accept whatever is given. VERY INSECURE!
|
||||||
|
void setInsecure() {
|
||||||
|
_clearAuthenticationSettings();
|
||||||
|
_use_insecure = true;
|
||||||
|
}
|
||||||
|
// Assume a given public key, don't validate or use cert info at all
|
||||||
|
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) {
|
||||||
|
_clearAuthenticationSettings();
|
||||||
|
_knownkey = pk;
|
||||||
|
_knownkey_usages = usages;
|
||||||
|
}
|
||||||
|
// Only check SHA1 fingerprint of certificate
|
||||||
|
bool setFingerprint(const uint8_t fingerprint[20]) {
|
||||||
|
_clearAuthenticationSettings();
|
||||||
|
_use_fingerprint = true;
|
||||||
|
memcpy_P(_fingerprint, fingerprint, 20);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool setFingerprint(const char *fpStr);
|
||||||
|
// Accept any certificate that's self-signed
|
||||||
|
void allowSelfSignedCerts() {
|
||||||
|
_clearAuthenticationSettings();
|
||||||
|
_use_self_signed = true;
|
||||||
|
}
|
||||||
|
// Install certificates of trusted CAs or specific site
|
||||||
|
void setTrustAnchors(const X509List *ta) {
|
||||||
|
_clearAuthenticationSettings();
|
||||||
|
_ta = ta;
|
||||||
|
}
|
||||||
|
// In cases when NTP is not used, app must set a time manually to check cert validity
|
||||||
|
void setX509Time(time_t now) {
|
||||||
|
_now = now;
|
||||||
|
}
|
||||||
|
// Install a client certificate for this connection, in case the server requires it (i.e. MQTT)
|
||||||
|
void setClientRSACert(const X509List *cert, const PrivateKey *sk);
|
||||||
|
void setClientECCert(const X509List *cert, const PrivateKey *sk,
|
||||||
|
unsigned allowed_usages, unsigned cert_issuer_key_type);
|
||||||
|
|
||||||
|
// Sets the requested buffer size for transmit and receive
|
||||||
|
void setBufferSizes(int recv, int xmit);
|
||||||
|
|
||||||
|
// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
|
||||||
|
int getMFLNStatus() {
|
||||||
|
return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an error code and possibly a text string in a passed-in buffer with last SSL failure
|
||||||
|
int getLastSSLError(char *dest = NULL, size_t len = 0);
|
||||||
|
|
||||||
|
// Attach a preconfigured certificate store
|
||||||
|
void setCertStore(CertStoreBase *certStore) {
|
||||||
|
_certStore = certStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select specific ciphers (i.e. optimize for speed over security)
|
||||||
|
// These may be in PROGMEM or RAM, either will run properly
|
||||||
|
bool setCiphers(const uint16_t *cipherAry, int cipherCount);
|
||||||
|
bool setCiphers(const std::vector<uint16_t>& list);
|
||||||
|
bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
|
||||||
|
|
||||||
|
// Limit the TLS versions BearSSL will connect with. Default is
|
||||||
|
// BR_TLS10...BR_TLS12
|
||||||
|
bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12);
|
||||||
|
#if 0
|
||||||
|
// peek buffer API is present
|
||||||
|
virtual bool hasPeekBufferAPI() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return number of byte accessible by peekBuffer()
|
||||||
|
virtual size_t peekAvailable() override {
|
||||||
|
return WiFiClientSecureCtx::available();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a pointer to available data buffer (size = peekAvailable())
|
||||||
|
// semantic forbids any kind of read() before calling peekConsume()
|
||||||
|
virtual const char* peekBuffer() override;
|
||||||
|
|
||||||
|
// consume bytes after use (see peekBuffer)
|
||||||
|
virtual void peekConsume(size_t consume) override;
|
||||||
|
#endif
|
||||||
|
protected:
|
||||||
|
bool _connectSSL(const char *hostName); // Do initial SSL handshake
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _clear();
|
||||||
|
void _clearAuthenticationSettings();
|
||||||
|
// Only one of the following two should ever be != nullptr!
|
||||||
|
std::shared_ptr<br_ssl_client_context> _sc;
|
||||||
|
std::shared_ptr<br_ssl_server_context> _sc_svr;
|
||||||
|
inline bool ctx_present() {
|
||||||
|
return (_sc != nullptr) || (_sc_svr != nullptr);
|
||||||
|
}
|
||||||
|
br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
|
||||||
|
std::shared_ptr<br_x509_minimal_context> _x509_minimal;
|
||||||
|
std::shared_ptr<struct br_x509_insecure_context> _x509_insecure;
|
||||||
|
std::shared_ptr<br_x509_knownkey_context> _x509_knownkey;
|
||||||
|
std::shared_ptr<unsigned char> _iobuf_in;
|
||||||
|
std::shared_ptr<unsigned char> _iobuf_out;
|
||||||
|
time_t _now;
|
||||||
|
const X509List *_ta;
|
||||||
|
CertStoreBase *_certStore;
|
||||||
|
int _iobuf_in_size;
|
||||||
|
int _iobuf_out_size;
|
||||||
|
bool _handshake_done;
|
||||||
|
bool _oom_err;
|
||||||
|
|
||||||
|
// Optional storage space pointer for session parameters
|
||||||
|
// Will be used on connect and updated on close
|
||||||
|
Session *_session;
|
||||||
|
|
||||||
|
bool _use_insecure;
|
||||||
|
bool _use_fingerprint;
|
||||||
|
uint8_t _fingerprint[20];
|
||||||
|
bool _use_self_signed;
|
||||||
|
const PublicKey *_knownkey;
|
||||||
|
unsigned _knownkey_usages;
|
||||||
|
|
||||||
|
// Custom cipher list pointer or NULL if default
|
||||||
|
std::shared_ptr<uint16_t> _cipher_list;
|
||||||
|
uint8_t _cipher_cnt;
|
||||||
|
|
||||||
|
// TLS ciphers allowed
|
||||||
|
uint32_t _tls_min;
|
||||||
|
uint32_t _tls_max;
|
||||||
|
|
||||||
|
unsigned char *_recvapp_buf;
|
||||||
|
size_t _recvapp_len;
|
||||||
|
|
||||||
|
bool _clientConnected(); // Is the underlying socket alive?
|
||||||
|
std::shared_ptr<unsigned char> _alloc_iobuf(size_t sz);
|
||||||
|
void _freeSSL();
|
||||||
|
int _run_until(unsigned target, bool blocking = true);
|
||||||
|
size_t _write(const uint8_t *buf, size_t size, bool pmem);
|
||||||
|
bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting
|
||||||
|
|
||||||
|
// Optional client certificate
|
||||||
|
const X509List *_chain;
|
||||||
|
const PrivateKey *_sk;
|
||||||
|
unsigned _allowed_usages;
|
||||||
|
unsigned _cert_issuer_key_type;
|
||||||
|
|
||||||
|
// Methods for handling server.available() call which returns a client connection.
|
||||||
|
friend class WiFiClientSecure; // access to private context constructors
|
||||||
|
WiFiClientSecureCtx(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type,
|
||||||
|
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
|
||||||
|
const X509List *client_CA_ta, int tls_min, int tls_max);
|
||||||
|
WiFiClientSecureCtx(ClientContext* client, const X509List *chain, const PrivateKey *sk,
|
||||||
|
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
|
||||||
|
const X509List *client_CA_ta, int tls_min, int tls_max);
|
||||||
|
|
||||||
|
// RSA keyed server
|
||||||
|
bool _connectSSLServerRSA(const X509List *chain, const PrivateKey *sk,
|
||||||
|
ServerSessions *cache, const X509List *client_CA_ta);
|
||||||
|
// EC keyed server
|
||||||
|
bool _connectSSLServerEC(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk,
|
||||||
|
ServerSessions *cache, const X509List *client_CA_ta);
|
||||||
|
|
||||||
|
// X.509 validators differ from server to client
|
||||||
|
bool _installClientX509Validator(); // Set up X509 validator for a client conn.
|
||||||
|
bool _installServerX509Validator(const X509List *client_CA_ta); // Setup X509 client cert validation, if supplied
|
||||||
|
|
||||||
|
uint8_t *_streamLoad(Stream& stream, size_t size);
|
||||||
|
}; // class WiFiClientSecureCtx
|
||||||
|
|
||||||
|
|
||||||
|
class WiFiClientSecure : public WiFiClient {
|
||||||
|
|
||||||
|
// WiFiClient's "ClientContext* _client" is always nullptr in this class.
|
||||||
|
// Instead, all virtual functions call their counterpart in "WiFiClientecureCtx* _ctx"
|
||||||
|
// which also derives from WiFiClient (this parent is the one which is eventually used)
|
||||||
|
|
||||||
|
// TODO: notice that this complicates the implementation by having two distinct ways the client connection is managed, consider:
|
||||||
|
// - implementing the secure connection details in the ClientContext
|
||||||
|
// (i.e. delegate the write & read functions there)
|
||||||
|
// - simplify the inheritance chain by implementing base wificlient class and inherit the original wificlient and wificlientsecure from it
|
||||||
|
// - abstract internals so it's possible to seamlessly =default copy and move with the instance *without* resorting to manual copy and initialization of each member
|
||||||
|
|
||||||
|
// TODO: prefer implementing virtual overrides in the .cpp (or, at least one of them)
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
WiFiClientSecure(): _ctx(new WiFiClientSecureCtx()) {
|
||||||
|
_owned = _ctx.get();
|
||||||
|
}
|
||||||
|
WiFiClientSecure(const WiFiClientSecure &rhs): WiFiClient(), _ctx(rhs._ctx) {
|
||||||
|
if (_ctx) {
|
||||||
|
_owned = _ctx.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~WiFiClientSecure() override {
|
||||||
|
_ctx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientSecure& operator=(const WiFiClientSecure&) = default;
|
||||||
|
|
||||||
|
std::unique_ptr<WiFiClient> clone() const override {
|
||||||
|
return std::unique_ptr<WiFiClient>(new WiFiClientSecure(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t status() override {
|
||||||
|
return _ctx->status();
|
||||||
|
}
|
||||||
|
int connect(IPAddress ip, uint16_t port) override {
|
||||||
|
return _ctx->connect(ip, port);
|
||||||
|
}
|
||||||
|
int connect(const String& host, uint16_t port) override {
|
||||||
|
return _ctx->connect(host, port);
|
||||||
|
}
|
||||||
|
int connect(const char* name, uint16_t port) override {
|
||||||
|
return _ctx->connect(name, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t connected() override {
|
||||||
|
return _ctx->connected();
|
||||||
|
}
|
||||||
|
size_t write(const uint8_t *buf, size_t size) override {
|
||||||
|
return _ctx->write(buf, size);
|
||||||
|
}
|
||||||
|
//size_t write_P(PGM_P buf, size_t size) override { return _ctx->write_P(buf, size); }
|
||||||
|
size_t write(const char *buf) {
|
||||||
|
return write((const uint8_t*)buf, strlen(buf));
|
||||||
|
}
|
||||||
|
// size_t write_P(const char *buf) { return write_P((PGM_P)buf, strlen_P(buf)); }
|
||||||
|
size_t write(Stream& stream) { /* Note this is not virtual */
|
||||||
|
return _ctx->write(stream);
|
||||||
|
}
|
||||||
|
int read(uint8_t *buf, size_t size) override {
|
||||||
|
return _ctx->read(buf, size);
|
||||||
|
}
|
||||||
|
int available() override {
|
||||||
|
return _ctx->available();
|
||||||
|
}
|
||||||
|
int availableForWrite() override {
|
||||||
|
return _ctx->availableForWrite();
|
||||||
|
}
|
||||||
|
int read() override {
|
||||||
|
return _ctx->read();
|
||||||
|
}
|
||||||
|
int peek() override {
|
||||||
|
return _ctx->peek();
|
||||||
|
}
|
||||||
|
size_t peekBytes(uint8_t *buffer, size_t length) override {
|
||||||
|
return _ctx->peekBytes(buffer, length);
|
||||||
|
}
|
||||||
|
bool flush(unsigned int maxWaitMs) {
|
||||||
|
return _ctx->flush(maxWaitMs);
|
||||||
|
}
|
||||||
|
bool stop(unsigned int maxWaitMs) {
|
||||||
|
return _ctx->stop(maxWaitMs);
|
||||||
|
}
|
||||||
|
void flush() override {
|
||||||
|
(void)flush(0);
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
(void)stop(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow sessions to be saved/restored automatically to a memory area
|
||||||
|
void setSession(Session *session) {
|
||||||
|
_ctx->setSession(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't validate the chain, just accept whatever is given. VERY INSECURE!
|
||||||
|
void setInsecure() {
|
||||||
|
_ctx->setInsecure();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume a given public key, don't validate or use cert info at all
|
||||||
|
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) {
|
||||||
|
_ctx->setKnownKey(pk, usages);
|
||||||
|
}
|
||||||
|
// Only check SHA1 fingerprint of certificate
|
||||||
|
bool setFingerprint(const uint8_t fingerprint[20]) {
|
||||||
|
return _ctx->setFingerprint(fingerprint);
|
||||||
|
}
|
||||||
|
bool setFingerprint(const char *fpStr) {
|
||||||
|
return _ctx->setFingerprint(fpStr);
|
||||||
|
}
|
||||||
|
// Accept any certificate that's self-signed
|
||||||
|
void allowSelfSignedCerts() {
|
||||||
|
_ctx->allowSelfSignedCerts();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install certificates of trusted CAs or specific site
|
||||||
|
void setTrustAnchors(const X509List *ta) {
|
||||||
|
_ctx->setTrustAnchors(ta);
|
||||||
|
}
|
||||||
|
// In cases when NTP is not used, app must set a time manually to check cert validity
|
||||||
|
void setX509Time(time_t now) {
|
||||||
|
_ctx->setX509Time(now);
|
||||||
|
}
|
||||||
|
// Install a client certificate for this connection, in case the server requires it (i.e. MQTT)
|
||||||
|
void setClientRSACert(const X509List *cert, const PrivateKey *sk) {
|
||||||
|
_ctx->setClientRSACert(cert, sk);
|
||||||
|
}
|
||||||
|
void setClientECCert(const X509List *cert, const PrivateKey *sk,
|
||||||
|
unsigned allowed_usages, unsigned cert_issuer_key_type) {
|
||||||
|
_ctx->setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the requested buffer size for transmit and receive
|
||||||
|
void setBufferSizes(int recv, int xmit) {
|
||||||
|
_ctx->setBufferSizes(recv, xmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
|
||||||
|
int getMFLNStatus() {
|
||||||
|
return _ctx->getMFLNStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an error code and possibly a text string in a passed-in buffer with last SSL failure
|
||||||
|
int getLastSSLError(char *dest = NULL, size_t len = 0) {
|
||||||
|
return _ctx->getLastSSLError(dest, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach a preconfigured certificate store
|
||||||
|
void setCertStore(CertStoreBase *certStore) {
|
||||||
|
_ctx->setCertStore(certStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select specific ciphers (i.e. optimize for speed over security)
|
||||||
|
// These may be in PROGMEM or RAM, either will run properly
|
||||||
|
bool setCiphers(const uint16_t *cipherAry, int cipherCount) {
|
||||||
|
return _ctx->setCiphers(cipherAry, cipherCount);
|
||||||
|
}
|
||||||
|
bool setCiphers(const std::vector<uint16_t> list) {
|
||||||
|
return _ctx->setCiphers(list);
|
||||||
|
}
|
||||||
|
bool setCiphersLessSecure() {
|
||||||
|
return _ctx->setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit the TLS versions BearSSL will connect with. Default is
|
||||||
|
// BR_TLS10...BR_TLS12. Allowed values are: BR_TLS10, BR_TLS11, BR_TLS12
|
||||||
|
bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12) {
|
||||||
|
return _ctx->setSSLVersion(min, max);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for Maximum Fragment Length support for given len before connection (possibly insecure)
|
||||||
|
static bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len);
|
||||||
|
static bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len);
|
||||||
|
static bool probeMaxFragmentLength(const String& host, uint16_t port, uint16_t len);
|
||||||
|
#if 0
|
||||||
|
// peek buffer API is present
|
||||||
|
virtual bool hasPeekBufferAPI() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return number of byte accessible by peekBuffer()
|
||||||
|
virtual size_t peekAvailable() override {
|
||||||
|
return _ctx->available();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a pointer to available data buffer (size = peekAvailable())
|
||||||
|
// semantic forbids any kind of read() before calling peekConsume()
|
||||||
|
virtual const char* peekBuffer() override {
|
||||||
|
return _ctx->peekBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume bytes after use (see peekBuffer)
|
||||||
|
virtual void peekConsume(size_t consume) override {
|
||||||
|
return _ctx->peekConsume(consume);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
private:
|
||||||
|
std::shared_ptr<WiFiClientSecureCtx> _ctx;
|
||||||
|
|
||||||
|
// Methods for handling server.available() call which returns a client connection.
|
||||||
|
friend class WiFiServerSecure; // Server needs to access these constructors
|
||||||
|
WiFiClientSecure(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type,
|
||||||
|
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
|
||||||
|
const X509List *client_CA_ta, int tls_min, int tls_max):
|
||||||
|
_ctx(new WiFiClientSecureCtx(client, chain, cert_issuer_key_type, sk, iobuf_in_size, iobuf_out_size, cache, client_CA_ta, tls_min, tls_max)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientSecure(ClientContext* client, const X509List *chain, const PrivateKey *sk,
|
||||||
|
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
|
||||||
|
const X509List *client_CA_ta, int tls_min, int tls_max):
|
||||||
|
_ctx(new WiFiClientSecureCtx(client, chain, sk, iobuf_in_size, iobuf_out_size, cache, client_CA_ta, tls_min, tls_max)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // class WiFiClientSecure
|
||||||
|
|
||||||
|
}; // namespace BearSSL
|
||||||
22
libraries/WiFi/src/WiFiNTP.cpp
Normal file
22
libraries/WiFi/src/WiFiNTP.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
WiFiNTP.h - Simple NTP wrapper for LWIP
|
||||||
|
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "WiFi.h"
|
||||||
|
|
||||||
|
NTPClass NTP;
|
||||||
78
libraries/WiFi/src/WiFiNTP.h
Normal file
78
libraries/WiFi/src/WiFiNTP.h
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
WiFiNTP.h - Simple NTP wrapper for LWIP
|
||||||
|
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <lwip/apps/sntp.h>
|
||||||
|
|
||||||
|
class NTPClass {
|
||||||
|
public:
|
||||||
|
NTPClass() { }
|
||||||
|
|
||||||
|
~NTPClass() {
|
||||||
|
sntp_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void begin(IPAddress server, int timeout = 3600) {
|
||||||
|
(void) timeout;
|
||||||
|
sntp_stop();
|
||||||
|
if (server.isSet()) {
|
||||||
|
sntp_setserver(0, server);
|
||||||
|
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||||
|
sntp_init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void begin(IPAddress s1, IPAddress s2, int timeout = 3600) {
|
||||||
|
(void) timeout;
|
||||||
|
sntp_stop();
|
||||||
|
if (s1.isSet()) {
|
||||||
|
sntp_setserver(0, s1);
|
||||||
|
}
|
||||||
|
if (s2.isSet()) {
|
||||||
|
sntp_setserver(1, s2);
|
||||||
|
}
|
||||||
|
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||||
|
sntp_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void begin(const char *server, int timeout = 3600) {
|
||||||
|
IPAddress addr;
|
||||||
|
if (WiFi.hostByName(server, addr)) {
|
||||||
|
begin(addr, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void begin(const char *s1, const char *s2, int timeout = 3600) {
|
||||||
|
IPAddress a1, a2;
|
||||||
|
if (WiFi.hostByName(s1, a1)) {
|
||||||
|
if (WiFi.hostByName(s2, a2)) {
|
||||||
|
begin(a1, a2, timeout);
|
||||||
|
} else {
|
||||||
|
begin(a1, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ESP8266 compat
|
||||||
|
#define configTime(timeout, tzoffsec, server1, server2) NTP.begin(server1, server2, timeout)
|
||||||
|
|
||||||
|
extern NTPClass NTP;
|
||||||
23
libraries/WiFi/src/WiFiServerSecure.h
Normal file
23
libraries/WiFi/src/WiFiServerSecure.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
WiFiServerSecure.h - Library for Arduino ESP8266
|
||||||
|
Copyright (c) 2017 Earle F. Philhower, III
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WiFiClientSecure.h"
|
||||||
|
#include "WiFiServerSecureBearSSL.h"
|
||||||
118
libraries/WiFi/src/WiFiServerSecureBearSSL.cpp
Normal file
118
libraries/WiFi/src/WiFiServerSecureBearSSL.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
WiFiServerBearSSL.cpp - SSL server for esp8266, mostly compatible
|
||||||
|
with Arduino WiFi shield library
|
||||||
|
|
||||||
|
Copyright (c) 2018 Earle F. Philhower, III
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
//extern "C" {
|
||||||
|
//#include "osapi.h"
|
||||||
|
//#include "ets_sys.h"
|
||||||
|
//}
|
||||||
|
|
||||||
|
#include "StackThunk.h"
|
||||||
|
//#include "debug.h"
|
||||||
|
#include "WiFi.h"
|
||||||
|
#include "WiFiClient.h"
|
||||||
|
#include "WiFiServer.h"
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
#include <include/ClientContext.h>
|
||||||
|
#include "WiFiServerSecureBearSSL.h"
|
||||||
|
#define DBG_MMU_PRINTF(x)
|
||||||
|
|
||||||
|
namespace BearSSL {
|
||||||
|
|
||||||
|
// Only need to call the standard server constructor
|
||||||
|
WiFiServerSecure::WiFiServerSecure(IPAddress addr, uint16_t port) : WiFiServer(addr, port) {
|
||||||
|
stack_thunk_add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only need to call the standard server constructor
|
||||||
|
WiFiServerSecure::WiFiServerSecure(uint16_t port) : WiFiServer(port) {
|
||||||
|
stack_thunk_add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerSecure::WiFiServerSecure(const WiFiServerSecure &rhs) : WiFiServer(rhs) {
|
||||||
|
*this = rhs;
|
||||||
|
stack_thunk_add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerSecure::~WiFiServerSecure() {
|
||||||
|
stack_thunk_del_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify a RSA-signed certificate and key for the server. Only copies the pointer, the
|
||||||
|
// caller needs to preserve this chain and key for the life of the object.
|
||||||
|
void WiFiServerSecure::setRSACert(const X509List *chain, const PrivateKey *sk) {
|
||||||
|
_chain = chain;
|
||||||
|
_sk = sk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify a EC-signed certificate and key for the server. Only copies the pointer, the
|
||||||
|
// caller needs to preserve this chain and key for the life of the object.
|
||||||
|
void WiFiServerSecure::setECCert(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk) {
|
||||||
|
_chain = chain;
|
||||||
|
_cert_issuer_key_type = cert_issuer_key_type;
|
||||||
|
_sk = sk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a client if there's an available connection waiting. If one is returned,
|
||||||
|
// then any validation (i.e. client cert checking) will have succeeded.
|
||||||
|
WiFiClientSecure WiFiServerSecure::available(uint8_t* status) {
|
||||||
|
(void) status; // Unused
|
||||||
|
return accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientSecure WiFiServerSecure::accept() {
|
||||||
|
if (_unclaimed) {
|
||||||
|
if (_sk && _sk->isRSA()) {
|
||||||
|
WiFiClientSecure result(_unclaimed, _chain, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta, _tls_min, _tls_max);
|
||||||
|
_unclaimed = _unclaimed->next();
|
||||||
|
result.setNoDelay(_noDelay);
|
||||||
|
DEBUGV("WS:av\r\n");
|
||||||
|
return result;
|
||||||
|
} else if (_sk && _sk->isEC()) {
|
||||||
|
WiFiClientSecure result(_unclaimed, _chain, _cert_issuer_key_type, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta, _tls_min, _tls_max);
|
||||||
|
_unclaimed = _unclaimed->next();
|
||||||
|
result.setNoDelay(_noDelay);
|
||||||
|
DEBUGV("WS:av\r\n");
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
// No key was defined, so we can't actually accept and attempt accept() and SSL handshake.
|
||||||
|
DEBUGV("WS:nokey\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something weird, return a no-op object
|
||||||
|
// optimistic_yield(1000);
|
||||||
|
return WiFiClientSecure();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiServerSecure::setSSLVersion(uint32_t min, uint32_t max) {
|
||||||
|
if (((min != BR_TLS10) && (min != BR_TLS11) && (min != BR_TLS12)) ||
|
||||||
|
((max != BR_TLS10) && (max != BR_TLS11) && (max != BR_TLS12)) ||
|
||||||
|
(max < min)) {
|
||||||
|
return false; // Invalid options
|
||||||
|
}
|
||||||
|
_tls_min = min;
|
||||||
|
_tls_max = max;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
88
libraries/WiFi/src/WiFiServerSecureBearSSL.h
Normal file
88
libraries/WiFi/src/WiFiServerSecureBearSSL.h
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
WiFiServerBearSSL.h - Library for Arduino ESP8266
|
||||||
|
Copyright (c) 2018 Earle F. Philhower, III
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WiFiServer.h"
|
||||||
|
#include "WiFiClientSecureBearSSL.h"
|
||||||
|
#include "BearSSLHelpers.h"
|
||||||
|
#include <bearssl/bearssl.h>
|
||||||
|
|
||||||
|
namespace BearSSL {
|
||||||
|
|
||||||
|
class WiFiClientSecure;
|
||||||
|
|
||||||
|
class WiFiServerSecure : public WiFiServer {
|
||||||
|
public:
|
||||||
|
WiFiServerSecure(IPAddress addr, uint16_t port);
|
||||||
|
WiFiServerSecure(uint16_t port);
|
||||||
|
WiFiServerSecure(const WiFiServerSecure &rhs);
|
||||||
|
virtual ~WiFiServerSecure();
|
||||||
|
|
||||||
|
// Override the default buffer sizes, if you know what you're doing...
|
||||||
|
void setBufferSizes(int recv, int xmit) {
|
||||||
|
_iobuf_in_size = recv;
|
||||||
|
_iobuf_out_size = xmit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the server's cache to the given one.
|
||||||
|
void setCache(ServerSessions *cache) {
|
||||||
|
_cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the server's RSA key and x509 certificate (required, pick one).
|
||||||
|
// Caller needs to preserve the chain and key throughout the life of the server.
|
||||||
|
void setRSACert(const X509List *chain, const PrivateKey *sk);
|
||||||
|
// Set the server's EC key and x509 certificate (required, pick one)
|
||||||
|
// Caller needs to preserve the chain and key throughout the life of the server.
|
||||||
|
void setECCert(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk);
|
||||||
|
|
||||||
|
// Require client certificates validated against the passed in x509 trust anchor
|
||||||
|
// Caller needs to preserve the cert throughout the life of the server.
|
||||||
|
void setClientTrustAnchor(const X509List *client_CA_ta) {
|
||||||
|
_client_CA_ta = client_CA_ta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit the TLS versions BearSSL will connect with. Default is
|
||||||
|
// BR_TLS10...BR_TLS12
|
||||||
|
bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12);
|
||||||
|
|
||||||
|
// If awaiting connection available and authenticated (i.e. client cert), return it.
|
||||||
|
WiFiClientSecure accept(); // https://www.arduino.cc/en/Reference/EthernetServerAccept
|
||||||
|
WiFiClientSecure available(uint8_t* status = NULL) __attribute__((deprecated("Renamed to accept().")));
|
||||||
|
|
||||||
|
WiFiServerSecure& operator=(const WiFiServerSecure&) = default;
|
||||||
|
|
||||||
|
using ClientType = WiFiClientSecure;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const X509List *_chain = nullptr;
|
||||||
|
unsigned _cert_issuer_key_type = 0;
|
||||||
|
const PrivateKey *_sk = nullptr;
|
||||||
|
int _iobuf_in_size = BR_SSL_BUFSIZE_INPUT;
|
||||||
|
int _iobuf_out_size = 837;
|
||||||
|
const X509List *_client_CA_ta = nullptr;
|
||||||
|
ServerSessions *_cache = nullptr;
|
||||||
|
|
||||||
|
// TLS ciphers allowed
|
||||||
|
uint32_t _tls_min = BR_TLS10;
|
||||||
|
uint32_t _tls_max = BR_TLS12;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
@ -43,10 +43,11 @@ compiler.warning_flags.all=-Wall -Wextra -Werror=return-type -Wno-ignored-qualif
|
||||||
|
|
||||||
compiler.netdefines=-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_LWIP=0 -DLWIP_IPV6=1 -DLWIP_IPV4=1 -DLWIP_IGMP=1 -DLWIP_CHECKSUM_CTRL_PER_NETIF=1
|
compiler.netdefines=-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_LWIP=0 -DLWIP_IPV6=1 -DLWIP_IPV4=1 -DLWIP_IGMP=1 -DLWIP_CHECKSUM_CTRL_PER_NETIF=1
|
||||||
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines}
|
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines}
|
||||||
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt" "-I{runtime.platform.path}/tools/libpico"
|
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt" "-I{runtime.platform.path}/include"
|
||||||
compiler.flags=-march=armv6-m -mcpu=cortex-m0plus -mthumb -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect}
|
compiler.flags=-march=armv6-m -mcpu=cortex-m0plus -mthumb -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect}
|
||||||
compiler.wrap="@{runtime.platform.path}/lib/platform_wrap.txt"
|
compiler.wrap="@{runtime.platform.path}/lib/platform_wrap.txt"
|
||||||
compiler.libpico="{runtime.platform.path}/lib/libpico.a"
|
compiler.libpico="{runtime.platform.path}/lib/libpico.a"
|
||||||
|
compiler.libbearssl="{runtime.platform.path}/lib/libbearssl.a"
|
||||||
|
|
||||||
compiler.c.cmd=arm-none-eabi-gcc
|
compiler.c.cmd=arm-none-eabi-gcc
|
||||||
compiler.c.flags=-c {compiler.warning_flags} {compiler.defines} {compiler.flags} -MMD {compiler.includes} -std=gnu17 -g
|
compiler.c.flags=-c {compiler.warning_flags} {compiler.defines} {compiler.flags} -MMD {compiler.includes} -std=gnu17 -g
|
||||||
|
|
@ -122,7 +123,7 @@ recipe.hooks.linking.prelink.1.pattern="{runtime.tools.pqt-python3.path}/python3
|
||||||
recipe.hooks.linking.prelink.2.pattern="{compiler.path}{compiler.S.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -c "{runtime.platform.path}/boot2/{build.boot2}.S" "-I{runtime.platform.path}/pico-sdk/src/rp2040/hardware_regs/include/" "-I{runtime.platform.path}/pico-sdk/src/common/pico_binary_info/include" -o "{build.path}/boot2.o"
|
recipe.hooks.linking.prelink.2.pattern="{compiler.path}{compiler.S.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -c "{runtime.platform.path}/boot2/{build.boot2}.S" "-I{runtime.platform.path}/pico-sdk/src/rp2040/hardware_regs/include/" "-I{runtime.platform.path}/pico-sdk/src/common/pico_binary_info/include" -o "{build.path}/boot2.o"
|
||||||
|
|
||||||
## Combine gc-sections, archives, and objects
|
## Combine gc-sections, archives, and objects
|
||||||
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} {compiler.ldflags} "-Wl,--script={build.path}/memmap_default.ld" "-Wl,-Map,{build.path}/{build.project_name}.map" -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/{archive_file}" "{build.path}/boot2.o" {compiler.libraries.ldflags} {compiler.libpico} -lm -lc {build.flags.libstdcpp} -lc -Wl,--end-group
|
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} {compiler.ldflags} "-Wl,--script={build.path}/memmap_default.ld" "-Wl,-Map,{build.path}/{build.project_name}.map" -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/{archive_file}" "{build.path}/boot2.o" {compiler.libraries.ldflags} {compiler.libpico} {compiler.libbearssl} -lm -lc {build.flags.libstdcpp} -lc -Wl,--end-group
|
||||||
|
|
||||||
## Create output (UF2 file)
|
## Create output (UF2 file)
|
||||||
recipe.objcopy.uf2.pattern="{runtime.tools.pqt-elf2uf2.path}/elf2uf2" "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.uf2"
|
recipe.objcopy.uf2.pattern="{runtime.tools.pqt-elf2uf2.path}/elf2uf2" "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.uf2"
|
||||||
|
|
|
||||||
29
tools/libbearssl/Makefile
Normal file
29
tools/libbearssl/Makefile
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
|
||||||
|
VER_H=../../include/bearssl/bearssl_git.h
|
||||||
|
|
||||||
|
all T0 clean: bearssl/README.txt
|
||||||
|
PATH="$(PATH):$(PWD)/../../system/arm-none-eabi/bin/" && cd bearssl && $(MAKE) CONF=pico $@
|
||||||
|
|
||||||
|
install: all version-header
|
||||||
|
cp bearssl/pico/libbearssl.a ../../lib/.
|
||||||
|
ar d ../../lib/libbearssl.a `ar t ../../lib/libbearssl.a | egrep 'x86|sse|pwr8|i62|m32|m62|m64|ct64|ctmul64'` # Remove unneeded objects
|
||||||
|
cp bearssl/inc/bearssl*.h ../../include/bearssl/.
|
||||||
|
|
||||||
|
bearssl/README.txt:
|
||||||
|
git submodule update --init --recursive bearssl
|
||||||
|
cd bearssl && (git remote add bearssl https://www.bearssl.org/git/BearSSL || true)
|
||||||
|
|
||||||
|
merge-upstream:
|
||||||
|
cd bearssl && git pull bearssl master
|
||||||
|
|
||||||
|
version-header:
|
||||||
|
echo "// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile" > $(VER_H)
|
||||||
|
echo -n "#define BEARSSL_GIT " >> $(VER_H)
|
||||||
|
cd bearssl && git rev-parse --short HEAD >> ../$(VER_H)
|
||||||
|
|
||||||
|
native: bearssl/README.txt
|
||||||
|
cd bearssl && make
|
||||||
|
|
||||||
|
native32: bearssl/README.txt
|
||||||
|
cd bearssl && make CONF=Unix32
|
||||||
45
tools/libbearssl/README.md
Normal file
45
tools/libbearssl/README.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# BearSSL ESP8266 builder
|
||||||
|
|
||||||
|
This directory contains the git submodule for the ESP8266 ported bearssl low-level library, a port of [BearSSL](https://www.bearssl.org)
|
||||||
|
|
||||||
|
If you are only working on the `BearSSL::` namespace functions in the
|
||||||
|
Arduino `ESP8266WiFi` library (`BearSSL::WiFiClientSecure`,
|
||||||
|
`BearSSL::WiFiServerSecure`, etc.) you do _NOT_ need to work in this
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Normal users can simply use the libbearssl.a file already included in
|
||||||
|
the `Arduino` repo. Experienced users looking to work on the underlying
|
||||||
|
BearSSL-ESP8266 ported library can use this directory to automate the
|
||||||
|
build flow.
|
||||||
|
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
The tools directory needs to be populated (i.e. Arduino IDE should be able
|
||||||
|
to compile an executable probect. `get.py` should ensure this).
|
||||||
|
|
||||||
|
### UNIX-like system (Linux, Mac):
|
||||||
|
If you need to change the *.t0 (Forth-like language) you will need a
|
||||||
|
.NET-compatible runtime (such as `mono` under Linux) to rebuild the
|
||||||
|
resulant `.c` files.
|
||||||
|
|
||||||
|
### For Windows (untested)
|
||||||
|
Microsoft's .NET runtime must be installed to run the `.t0`->`.c` workflow.
|
||||||
|
|
||||||
|
|
||||||
|
## Building
|
||||||
|
* `make all`: Init the submodule, if needed, then build _but do not install_ the library
|
||||||
|
* `make install`: Init the submodule, if needed, then build and copy the library to the standard location in `tools/sdk/lib`
|
||||||
|
|
||||||
|
## Editing the library
|
||||||
|
`https://github.com/earlephilhower/bearssl-esp8266` is the current repository
|
||||||
|
for this library. A `git remote` to the original BearSSL sources from
|
||||||
|
`https://bearssl.org/git/BearSSL` is added on submodule init. You can either
|
||||||
|
manually do pulls, or `make merge-upstream` to bring in any BearSSL upstream
|
||||||
|
changes.
|
||||||
|
|
||||||
|
Documentation in the library README-esp8266 and git log describes the changes done.
|
||||||
|
|
||||||
|
|
||||||
|
Feel free to drop me a line at <earlephilhower@yahoo.com> if you have questions.
|
||||||
|
|
||||||
|
-Earle F. Philhower, III
|
||||||
1
tools/libbearssl/bearssl
Submodule
1
tools/libbearssl/bearssl
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit f294aa022f82833941ffdf3b0f306c2072e3a26c
|
||||||
|
|
@ -9,8 +9,6 @@ extern "C" {
|
||||||
// Critical section protection
|
// Critical section protection
|
||||||
extern void noInterrupts();
|
extern void noInterrupts();
|
||||||
extern void interrupts();
|
extern void interrupts();
|
||||||
//static int lwipNoInterrupts() { noInterrupts(); return 0; }
|
|
||||||
//static void lwipInterrupts(int ign) { interrupts(); }
|
|
||||||
#define SYS_ARCH_DECL_PROTECT int
|
#define SYS_ARCH_DECL_PROTECT int
|
||||||
#define SYS_ARCH_PROTECT(lev) noInterrupts
|
#define SYS_ARCH_PROTECT(lev) noInterrupts
|
||||||
#define SYS_ARCH_UNPROTECT(lev) interrupts
|
#define SYS_ARCH_UNPROTECT(lev) interrupts
|
||||||
|
|
@ -22,7 +20,6 @@ extern void interrupts();
|
||||||
#define LWIP_SOCKET 0
|
#define LWIP_SOCKET 0
|
||||||
#define MEM_LIBC_MALLOC 0
|
#define MEM_LIBC_MALLOC 0
|
||||||
|
|
||||||
|
|
||||||
#define MEM_ALIGNMENT 4
|
#define MEM_ALIGNMENT 4
|
||||||
#define MEM_SIZE 4000
|
#define MEM_SIZE 4000
|
||||||
#define MEMP_NUM_TCP_SEG 32
|
#define MEMP_NUM_TCP_SEG 32
|
||||||
|
|
@ -56,6 +53,13 @@ extern void interrupts();
|
||||||
#define DHCP_DOES_ARP_CHECK 0
|
#define DHCP_DOES_ARP_CHECK 0
|
||||||
#define LWIP_DHCP_DOES_ACD_CHECK 0
|
#define LWIP_DHCP_DOES_ACD_CHECK 0
|
||||||
|
|
||||||
|
// NTP
|
||||||
|
extern void __setSystemTime(unsigned long long sec, unsigned long us);
|
||||||
|
#define SNTP_SET_SYSTEM_TIME_US(sec, us) __setSystemTime(sec, us)
|
||||||
|
#define SNTP_MAX_SERVERS 2
|
||||||
|
//#define SNTP_SERVER_ADDRESS "pool.ntp.org"
|
||||||
|
#define SNTP_SERVER_DNS 1
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define LWIP_DEBUG 1
|
#define LWIP_DEBUG 1
|
||||||
#define LWIP_STATS 1
|
#define LWIP_STATS 1
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,12 @@ mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
make -j
|
make -j
|
||||||
|
|
||||||
|
# Put everything in its place
|
||||||
mv libpico.a ../../../lib/.
|
mv libpico.a ../../../lib/.
|
||||||
mv generated/pico_base/pico/version.h ../../../lib/pico_base/pico/.
|
mv generated/pico_base/pico/version.h ../../../include/pico_base/pico/.
|
||||||
|
cp ../lwipopts.h ../../../include/.
|
||||||
|
cp ../tusb_config.h ../../../include/.
|
||||||
|
|
||||||
rm -rf boot
|
rm -rf boot
|
||||||
mkdir boot
|
mkdir boot
|
||||||
|
|
|
||||||
|
|
@ -47,4 +47,15 @@ def main():
|
||||||
fout.write("#define ARDUINO_PICO_REVISION " + str(sub) + "\n")
|
fout.write("#define ARDUINO_PICO_REVISION " + str(sub) + "\n")
|
||||||
fout.write('#define ARDUINO_PICO_VERSION_STR "' + str(args.version) + '"' + "\n")
|
fout.write('#define ARDUINO_PICO_VERSION_STR "' + str(args.version) + '"' + "\n")
|
||||||
|
|
||||||
|
# docs/conf.py
|
||||||
|
with open("docs/conf.py", "r") as fin:
|
||||||
|
with open("docs/conf.py.new", "w") as fout:
|
||||||
|
for l in fin:
|
||||||
|
if l.startswith("version = "):
|
||||||
|
l = "version = u'" + str(args.version) + "'\n"
|
||||||
|
if l.startswith("release = "):
|
||||||
|
l = "release = u'" + str(args.version) + "'\n"
|
||||||
|
fout.write(l);
|
||||||
|
shutil.move("docs/conf.py.new", "docs/conf.py")
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,8 @@ env.Append(
|
||||||
|
|
||||||
# link lib/libpico.a by full path, ignore libstdc++
|
# link lib/libpico.a by full path, ignore libstdc++
|
||||||
LIBS=[
|
LIBS=[
|
||||||
File(os.path.join(FRAMEWORK_DIR, "lib", "libpico.a")),
|
File(os.path.join(FRAMEWORK_DIR, "lib", "libpico.a")),
|
||||||
|
File(os.path.join(FRAMEWORK_DIR, "lib", "libbearssl.a")),
|
||||||
"m", "c", stdcpp_lib, "c"]
|
"m", "c", stdcpp_lib, "c"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -247,7 +248,7 @@ if not "USE_TINYUSB" in cpp_defines:
|
||||||
configure_usb_flags(cpp_defines)
|
configure_usb_flags(cpp_defines)
|
||||||
|
|
||||||
# ensure LWIP headers are in path after any TINYUSB distributed versions, also PicoSDK USB path headers
|
# ensure LWIP headers are in path after any TINYUSB distributed versions, also PicoSDK USB path headers
|
||||||
env.Append(CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")])
|
env.Append(CPPPATH=[os.path.join(FRAMEWORK_DIR, "include")])
|
||||||
|
|
||||||
# info about the filesystem is already parsed by the platform's main.py
|
# info about the filesystem is already parsed by the platform's main.py
|
||||||
# script. We can just use the info here
|
# script. We can just use the info here
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue