diff --git a/host/Crypto/Makefile b/host/Crypto/Makefile index 6da44297..5ecb2e56 100644 --- a/host/Crypto/Makefile +++ b/host/Crypto/Makefile @@ -85,6 +85,7 @@ SOURCES += \ NoiseCipherState_AESGCM.cpp \ NoiseCipherState_ChaChaPoly.cpp \ NoiseCipherState.cpp \ + NoiseClient.cpp \ NoiseDHState_Curve25519.cpp \ NoiseDHState.cpp \ NoiseHandshakeState.cpp \ @@ -92,12 +93,13 @@ SOURCES += \ Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp \ Noise_IK_25519_ChaChaPoly_SHA256.cpp \ Noise_IK.cpp \ - NoiseNamespace.cpp \ + NoiseLinkOptions.cpp \ Noise_NNpsk0_25519_AESGCM_SHA256.cpp \ Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp \ Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp \ Noise_NNpsk0.cpp \ NoiseProtobufs.cpp \ + NoiseServer.cpp \ NoiseSymmetricState_AESGCM_SHA256.cpp \ NoiseSymmetricState_ChaChaPoly_BLAKE2s.cpp \ NoiseSymmetricState_ChaChaPoly_SHA256.cpp \ diff --git a/host/emulation/Client.h b/host/emulation/Client.h new file mode 100644 index 00000000..6ee2c060 --- /dev/null +++ b/host/emulation/Client.h @@ -0,0 +1,55 @@ +/* + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right 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 +*/ + +#ifndef client_h +#define client_h + +// XXX: This file has been hacked up to make it compile in the +// emulation environment. Not intended for real work. + +//#include "Print.h" +//#include "Stream.h" +//#include "IPAddress.h" + +#include +#include + +typedef uint32_t IPAddress; + +class Client /*: public Stream*/ { + +public: + virtual ~Client() {} + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +//protected: +// uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/host/emulation/Server.h b/host/emulation/Server.h new file mode 100644 index 00000000..11fd9832 --- /dev/null +++ b/host/emulation/Server.h @@ -0,0 +1,33 @@ +/* + Server.h - Base class that provides Server + Copyright (c) 2011 Adrian McEwen. All right 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 +*/ + +#ifndef server_h +#define server_h + +// XXX: This file has been hacked up to make it compile in the +// emulation environment. Not intended for real work. + +//#include "Print.h" + +class Server /*: public Print*/ { +public: + virtual void begin() =0; +}; + +#endif diff --git a/libraries/Crypto/KeyRing.cpp b/libraries/Crypto/KeyRing.cpp index 3cc2ef2a..ce0918a1 100644 --- a/libraries/Crypto/KeyRing.cpp +++ b/libraries/Crypto/KeyRing.cpp @@ -196,6 +196,11 @@ KeyRingClass KeyRing; * primary remote device that this device will be communicating with. */ +/** + * \var KeyRingClass::PreSharedKeyDefault + * \brief Identifier for the default pre-shared symmetric key for the device. + */ + /** * \var KeyRingClass::EthernetMACAddress * \brief Identifier for storing a generated MAC address into the other diff --git a/libraries/Crypto/KeyRing.h b/libraries/Crypto/KeyRing.h index c360408b..2e3b230c 100644 --- a/libraries/Crypto/KeyRing.h +++ b/libraries/Crypto/KeyRing.h @@ -65,6 +65,8 @@ public: static const uint16_t LocalEd25519Default = 0x4501; // 'E', 0x01 static const uint16_t RemoteEd25519Default = 0x6501; // 'e', 0x01 + static const uint16_t PreSharedKeyDefault = 0x5001; // 'P', 0x01 + static const uint16_t EthernetMACAddress = 0x4D01; // 'M', 0x01 private: diff --git a/libraries/NoiseProtocol/keywords.txt b/libraries/NoiseProtocol/keywords.txt index 5d2173ed..1b971ec3 100644 --- a/libraries/NoiseProtocol/keywords.txt +++ b/libraries/NoiseProtocol/keywords.txt @@ -1,2 +1,6 @@ NoiseClient KEYWORD1 +NoiseEthernetClient KEYWORD1 +NoiseWiFiClient KEYWORD1 NoiseServer KEYWORD1 +NoiseEthernetServer KEYWORD1 +NoiseWiFiServer KEYWORD1 diff --git a/libraries/NoiseProtocol/library.json b/libraries/NoiseProtocol/library.json index beeb5550..d5bb2fbb 100644 --- a/libraries/NoiseProtocol/library.json +++ b/libraries/NoiseProtocol/library.json @@ -1,7 +1,7 @@ { "name": "NoiseProtocol", "version": "0.2.0", - "keywords": "NoiseClient,NoiseServer", + "keywords": "NoiseClient,NoiseServer,NoiseEthernetClient,NoiseEthernetServer,NoiseWiFiClient,NoiseWiFiServer", "description": "Noise protocol for creating secure sessions", "authors": { diff --git a/libraries/NoiseProtocol/src/NoiseClient.cpp b/libraries/NoiseProtocol/src/NoiseClient.cpp new file mode 100644 index 00000000..91ce3a77 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseClient.cpp @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * 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. + */ + +#include "NoiseClient.h" + +/** + * \class NoiseClient NoiseClient.h + * \brief Network class for connecting to a peer using the Noise protocol. + */ + +/** + * \var NoiseEthernetClient + * \brief Convenience type for communicating via Noise over an Ethernet link. + */ + +/** + * \var NoiseWiFiClient + * \brief Convenience type for communicating via Noise over a Wi-Fi link. + */ + +/** @cond noise_client_private */ + +// Standard Arduino network error codes for connect(). +#define NOISE_CLIENT_SUCCESS 1 +#define NOISE_CLIENT_FAILED 0 +#define NOISE_CLIENT_TIMED_OUT -1 +#define NOISE_CLIENT_INVALID_SERVER -2 +#define NOISE_CLIENT_TRUNCATED -3 +#define NOISE_CLIENT_INVALID_RESPONSE -4 + +/** @endcond */ + +/** + * \brief Constructs a new Noise network client. + * + * \param networkClient The underlying transport client; usually an instance + * of EthernetClient or WiFiClient. + * + * The new object will take owership of \a networkClient and will delete it + * when this object is destroyed. + */ +NoiseClient::NoiseClient(Client *networkClient) + : refCount(1) + , net(networkClient) + , opts(0) +{ +} + +/** + * \brief Destroys this Noise network client. + */ +NoiseClient::~NoiseClient() +{ + delete net; + delete opts; +} + +/** + * \brief Gets the options block for this client so that the application + * can modify the options for this client only. + * + * \return A pointer to the options block. + * + * Normally the options for clients are set on the global NoiseClientOptions + * object, which then apply to all clients on the device. If this function + * is called, then the options in NoiseClientOptions are copied and the + * application can then make local modifications specific to this session. + * + * The options can be modified up until the point that connect() is + * called. After that, whatever options were set on the client become + * permanent for the session. Any modifications that are made to the + * options will be ignored until the next call to connect() on this object. + * + * For incoming connections, use NoiseServerOptions and NoiseServer::options() + * instead. + * + * \sa NoiseServer::options() + */ +NoiseLinkOptions *NoiseClient::options() +{ + // The caller may be modifying the options, so we need to clone + // the global options block to avoid making modifications to it. + if (opts) + return opts; + opts = new NoiseLinkOptions(); + opts->copyFrom(NoiseClientOptions); + return opts; +} + +/** + * \brief Gets a constant reference to the options block for this client. + * + * \return A constant pointer to the options block. + */ +const NoiseLinkOptions *NoiseClient::constOptions() const +{ + // Avoid cloning the global options block if we don't need to. + if (opts) + return opts; + return &NoiseClientOptions; +} + +/** + * \fn Client *NoiseClient::network() const + * \brief Gets the underlying network client. + * + * \return The underlying network client for this Noise client; + * usually an instance of EthernetClient or WiFiClient. + * + * Applications normally won't need to use this unless they need to + * adjust the raw socket options on the transport. + */ + +/** + * \brief Gets the status of the connection. + * + * \return Noise::Closed if the connection has closed or it hasn't started yet. + * \return Noise::Connecting if the connection is in the process of connecting + * to the remote host, but the secure handshake has not completed yet. + * \return Noise::Connected if the connection is active and ready to + * send and receive data. + * \return Noise::Closing if the remote end of the connection has been + * closed but there are still bytes left in the receive buffer. Any data + * that is transmitted in this state will be discarded. + * \return HandshakeFailed if the client failed to establish a secure + * connection with the remote party. + * + * \sa connected() + */ +Noise::ConnectionStatus NoiseClient::connectionStatus() const +{ + // TODO + if (!net) + return Noise::Closed; + return net->connected() ? Noise::Closed : Noise::Connected; +} + +/** + * \brief Clears security-sensitive data from this object. + * + * If the connection is active, then calling this function will stop() it. + */ +void NoiseClient::clear() +{ + stop(); + if (opts) + opts->clear(); + // TODO +} + +/** + * \brief Gets the public key of the remote party that this client + * is communicating with. + * + * \param value Buffer to receive the remote public key. + * \param maxSize Maximum size of the \a value buffer. + * + * \return The number of bytes that were written to the \a value buffer if + * the remote public key is available. + * \return 0 if the remote public key is not available yet. + * \return 0 if \a maxSize is too small to contain the key. + * \return 0 if the protocol does not make use of remote public keys, + * such as the "NNpsk0" pattern. + * + * The remote public key is available once the handshake completes + * and when connected() becomes true. Typically an application will use + * this to verify the identity of the party they are communicating with. + * + * \sa getHandshakeHash() + */ +size_t NoiseClient::getRemotePublicKey(void *value, size_t maxSize) const +{ + // TODO + return 0; +} + +/** + * \brief Gets the handshake hash at the end of the handshake. + * + * \param value Buffer to receive the handshake hash. + * \param maxSize Maximum size of the \a value buffer. + * + * \return The number of bytes that were written to the \a value buffer if + * the handshake hash is available. + * \return 0 if the handshake hash is not available yet. + * \return 0 if \a maxSize is too small to contain the handshake hash. + * + * The handshake hash is a value defined by the Noise specification that + * is unique for every connection, and which can be used to secure higher + * level authentication protocols. See the Noise specification for details. + * + * \sa getRemotePublicKey() + */ +size_t NoiseClient::getHandshakeHash(void *value, size_t maxSize) const +{ + // TODO: modify NoiseHandshakeState API to use the maxSize idiom. + return 0; +} + +/** + * \brief Connects to a remote host using an IP address and port number. + * + * \param ip The IP address of the remote host. + * \param port The port number on the remote host. + * + * \return 1 if the connection was initiated. + * \return 0 if the connection attempt failed. + * \return A negative code on error. + * + * This function establishes the basic connection but the security handshake + * will not be complete when this function returns. The connection will not + * be ready send or receive until conected() returns true. Data that is + * sent before then will be discarded. + * + * \sa connected() + */ +int NoiseClient::connect(IPAddress ip, uint16_t port) +{ + // Stop the previous connection first. + stop(); + + // Fail if the underlying network client is not ready. + if (!net || !(net->operator bool())) + return NOISE_CLIENT_FAILED; + + // Attempt to connect to the remote host using the underlying network. + int ret = net->connect(ip, port); + if (ret <= 0) + return ret; + + // Start the handshake running. + return connect(); +} + +/** + * \brief Connects to a remote host using a host name and port number. + * + * \param host The name of the remote host. + * \param port The port number on the remote host. + * + * \return 1 if the connection was initiated. + * \return 0 if the connection attempt failed. + * \return A negative code on error. + * + * This function establishes the basic connection but the security handshake + * will not be complete when this function returns. The connection will not + * be ready send or receive until conected() returns true. Data that is + * sent before then will be discarded. + * + * \sa connected() + */ +int NoiseClient::connect(const char *host, uint16_t port) +{ + // Stop the previous connection first. + stop(); + + // Fail if the underlying network client is not ready. + if (!net || !(net->operator bool())) + return NOISE_CLIENT_FAILED; + + // Attempt to connect to the remote host using the underlying network. + int ret = net->connect(host, port); + if (ret <= 0) + return ret; + + // Start the handshake running. + return connect(); +} + +/** + * \brief Internal implementation of the public connect() methods that + * is called after the basic network link is established. + * + * \return 1 if the connection was initiated. + * \return 0 if the connection attempt failed. + * \return A negative code on error. + */ +int NoiseClient::connect() +{ + // TODO + return NOISE_CLIENT_SUCCESS; +} + +/** + * \brief Writes a single byte to the connection. + * + * \param data The byte to write. + * + * \return 1 if the byte was written successfully, 0 if the byte was + * not written. + * + * If the security handshake has not completed or the connection has been + * lost, then the write will be rejected with a 0 return value. + * + * This function may not send the byte to the other party immediately. + * It may be queued up until the next call to flush(), read(), or + * available(). + * + * \sa flush(), read(), available() + */ +size_t NoiseClient::write(uint8_t data) +{ + // TODO + return 0; +} + +/** + * \brief Writes a buffer of bytes to the connection. + * + * \param buf Points to the start of the buffer. + * \param size The number of bytes in the buffer. + * + * \return The number of bytes that were written, which may be 0 if + * the connection is not ready to accept data. + * + * If the security handshake has not completed or the connection has been + * lost, then the write will be rejected with a 0 return value. + * + * This function may not send the data to the other party immediately. + * It may be queued up until the next call to flush(), read(), or + * available(). + * + * \sa flush(), read() + */ +size_t NoiseClient::write(const uint8_t *buf, size_t size) +{ + // TODO + return size; +} + +/** + * \brief Gets the number of bytes that are available to read(). + * + * \return The number of bytes that are available. + * + * This function will implicitly perform a flush() to send any outstanding + * data in the internal write buffer to the other party. + * + * \sa read(), flush() + */ +int NoiseClient::available() +{ + flush(); + // TODO + return 0; +} + +/** + * \brief Reads a single byte from the connection if one is ready. + * + * \return The next byte or -1 if no bytes are ready to read. + * + * This function will implicitly perform a flush() to send any outstanding + * data in the internal write buffer to the other party. + * + * \sa write(), available(), flush(), peek() + */ +int NoiseClient::read() +{ + flush(); + // TODO + return -1; +} + +/** + * \brief Reads a buffer of bytes from the connection if data is ready. + * + * \param buf Points to the buffer to read into. + * \param size Maximum number of bytes that can be read into the buffer. + * + * This function will implicitly perform a flush() to send any outstanding + * data in the internal write buffer to the other party. + * + * \sa write(), available(), flush() + */ +int NoiseClient::read(uint8_t *buf, size_t size) +{ + flush(); + // TODO + return 0; +} + +/** + * \brief Peeks at the next byte without removing it from the receive buffer. + * + * \return The next byte or -1 if no bytes are ready to read. + * + * This function will implicitly perform a flush() to send any outstanding + * data in the internal write buffer to the other party. + * + * \sa read() + */ +int NoiseClient::peek() +{ + flush(); + // TODO + return -1; +} + +/** + * \brief Flushes pending data in internal buffers to the other party. + */ +void NoiseClient::flush() +{ + // TODO +} + +/** + * \brief Closes the connection and stops it. + */ +void NoiseClient::stop() +{ + // TODO +} + +/** + * \brief Determine if this client is connected to the remote peer and + * ready to send or receive application data. + * + * \return Returns non-zero if the client is connected and the security + * handshake has completed successfully; zero if not. + * + * This function can be used to determine if the connection is ready + * to send and receive application data. Requests to read() or write() + * before this point will fail. + * + * The connectionStatus() function can be used to get more detailed + * information on the state of the connection. + * + * \sa connectionStatus() + */ +uint8_t NoiseClient::connected() +{ + Noise::ConnectionStatus status = connectionStatus(); + return status == Noise::Connected || status == Noise::Closing; +} + +/** + * \brief Determine if this network client is ready to make connections. + * + * \return Returns true if the client is ready, false otherwise. + */ +NoiseClient::operator bool() +{ + if (!net) + return false; + return net->operator bool(); +} + +void NoiseClient::ref(NoiseClient *client) +{ + if (client) + ++(client->refCount); +} + +void NoiseClient::deref(NoiseClient *client) +{ + if (client && --(client->refCount) <= 0) + delete client; +} + +bool NoiseClient::accept(const NoiseLinkOptions &options) +{ + // Make a copy of the incoming server options. + if (!opts) + opts = new NoiseLinkOptions(); + opts->copyFrom(options); + // TODO + return false; +} diff --git a/libraries/NoiseProtocol/src/NoiseClient.h b/libraries/NoiseProtocol/src/NoiseClient.h new file mode 100644 index 00000000..ae1d8066 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseClient.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * 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 NOISE_CLIENT_h +#define NOISE_CLIENT_h + +#include "NoiseLinkOptions.h" +#include + +class NoiseClient : public Client +{ +private: + // Disable the copy operators. NoiseEthernetClient and NoiseWiFiClient + // should be used instead for safe copiable network client objects. + NoiseClient(const NoiseClient &other) {} + NoiseClient &operator=(const NoiseClient &other) { return *this; } + +public: + explicit NoiseClient(Client *networkClient); + virtual ~NoiseClient(); + + NoiseLinkOptions *options(); + + Client *network() const { return net; } + + Noise::ConnectionStatus connectionStatus() const; + + void clear(); + + // TODO: How to check for known remote public keys in a simple way? + + size_t getRemotePublicKey(void *value, size_t maxSize) const; + size_t getHandshakeHash(void *value, size_t maxSize) const; + + // Standard API for Arduino network clients. + int connect(IPAddress ip, uint16_t port); + int connect(const char *host, uint16_t port); + size_t write(uint8_t data); + size_t write(const uint8_t *buf, size_t size); + int available(); + int read(); + int read(uint8_t *buf, size_t size); + int peek(); + void flush(); + void stop(); + uint8_t connected(); + operator bool(); + + /** @cond noise_client_internal */ + // Internal helper functions for NoiseClientWrapper and NoiseServer. + // Not part of the public API that applications should be using. + static void ref(NoiseClient *client); + static void deref(NoiseClient *client); + bool accept(const NoiseLinkOptions &options); + /** @endcond */ + +private: + int refCount; + Client *net; + NoiseLinkOptions *opts; + + const NoiseLinkOptions *constOptions() const; + + int connect(); +}; + +/** @cond noise_client_wrapper */ + +// Nelper template for safely creating and copying instances of NoiseClient for +// specific underlying network stacks such as EthernetClient or WiFiClient. +template +class NoiseClientWrapper : public Client +{ +public: + inline NoiseClientWrapper() : d(0) {} + inline NoiseClientWrapper(const NoiseClientWrapper &other) + : d(other.d) { NoiseClient::ref(d); } + inline NoiseClientWrapper(NoiseClient *client) : d(client) {} + inline ~NoiseClientWrapper() { NoiseClient::deref(d); } + + inline NoiseClientWrapper &operator=(const NoiseClientWrapper &other) + { + NoiseClient::ref(other.d); + NoiseClient::deref(d); + d = other.d; + return *this; + } + + inline NoiseLinkOptions *options() + { + return d ? d->options() : &NoiseClientOptions; + } + + inline T *network() const + { + return d ? (T *)(d->network()) : 0; + } + + int connect(IPAddress ip, uint16_t port) + { + if (!d) + d = new NoiseClient(new T()); + return d->connect(ip, port); + } + + int connect(const char *host, uint16_t port) + { + if (!d) + d = new NoiseClient(new T()); + return d->connect(host, port); + } + + size_t write(uint8_t data) + { + return d ? d->write(data) : 0; + } + + size_t write(const uint8_t *buf, size_t size) + { + return d ? d->write(buf, size) : 0; + } + + int available() + { + return d ? d->available() : 0; + } + + int read() + { + return d ? d->read() : -1; + } + + int read(uint8_t *buf, size_t size) + { + return d ? d->read(buf, size) : -1; + } + + int peek() + { + return d ? d->peek() : -1; + } + + void flush() + { + if (d) + d->flush(); + } + + void stop() + { + if (d) + d->stop(); + } + + uint8_t connected() + { + return d ? d->connected() : false; + } + + operator bool() + { + return d ? (d->operator bool()) : false; + } + +private: + NoiseClient *d; +}; + +/** @endcond */ + +#define NoiseEthernetClient NoiseClientWrapper +#define NoiseWiFiClient NoiseClientWrapper + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseLinkOptions.cpp b/libraries/NoiseProtocol/src/NoiseLinkOptions.cpp new file mode 100644 index 00000000..74ff3a22 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseLinkOptions.cpp @@ -0,0 +1,867 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * 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. + */ + +#include "NoiseLinkOptions.h" +#include "NoiseHandshakeState.h" +#include "Crypto.h" +#include "RNG.h" +#include "Curve25519.h" +#include + +/** + * \class NoiseLinkOptions NoiseLinkOptions.h + * \brief Collection of options for NoiseLink clients and servers. + * + * The global objects NoiseClientOptions and NoiseServerOptions are + * used to set the initial options for Noise sessions created by + * NoiseClient and NoiseServer respectively. They are usually populated + * at system startup. + * + * \code + * void setup() + * { + * ... + * + * // Load the device's local key pair from the key ring. Otherwise, + * // generate a new key pair and store it in the key ring. + * if (!NoiseClientOptions.load(Noise::LocalStaticKeyPair)) { + * Serial.println("Generating a new key pair, please wait ..."); + * NoiseClientOptions.generate(Noise::LocalStaticKeyPair); + * } + * + * ... + * } + * \endcode + * + * If you are using the "IK" pattern to connect to a remote device, + * then you also need to load the public key of the remote device: + * + * \code + * void setup() + * { + * ... + * + * // Load the public key of the remote device we are communicating with. + * if (!NoiseClientOptions.load(Noise::RemoteStaticPublicKey)) { + * Serial.println("Do not know the identity of the remote device"); + * ... + * } + * + * ... + * } + * \endcode + * + * If you want to be more clever, you can try connecting with the "XX" + * pattern if the identity of the remote device is unknown and then + * record the public key for use with "IK" in subsequent sessions. + * + * Keys do not have to be stored in the key ring. If you have obtained a + * remote public key through other means, you can pass it to the options + * block with setParameter(): + * + * \code + * uint8_t remoteKey[32] = {...}; + * + * NoiseClientOptions.setParameter(Noise::RemoteStaticPublicKey, remoteKey, 32); + * \endcode + * + * At present, NoiseLinkOptions only supports Curve25519 keys and PSK's. + * Support for other Noise DH algorithms is not implemented yet. + */ + +/** + * \brief Default options to use when establishing an outgoing session + * from a client device using NoiseClient. + */ +NoiseLinkOptions NoiseClientOptions; + +/** + * \brief Default options to use when establishing an incoming session + * on a server device using NoiseServer. + */ +NoiseLinkOptions NoiseServerOptions; + +/** @cond noise_link_options_private */ + +#define HAVE_KEY_PAIR_25519 0x01 +#define HAVE_REMOTE_KEY_25519 0x02 +#define HAVE_PSK 0x04 + +#define MAX_PROTOCOLS 4 + +class NoiseLinkOptionsPrivate +{ +public: + NoiseLinkOptionsPrivate() + : allowAliases(true) + , padding(Noise::NoPadding) + , sendSize(NOISE_DEFAULT_BUFSIZ) + , recvSize(NOISE_DEFAULT_BUFSIZ) + , numProtocols(0) + { + st.flags = 0; + } + ~NoiseLinkOptionsPrivate() { clean(&st, sizeof(st)); } + + void clear() { clean(&st, sizeof(st)); } + + void copyFrom(const NoiseLinkOptionsPrivate *other) + { + memcpy(&st, &(other->st), sizeof(st)); + allowAliases = other->allowAliases; + padding = other->padding; + sendSize = other->sendSize; + recvSize = other->recvSize; + numProtocols = other->numProtocols; + memcpy(protocols, other->protocols, + numProtocols * sizeof(protocols[0])); + } + + struct { + uint8_t flags; + uint8_t keyPair25519[64]; + uint8_t remoteKey25519[32]; + uint8_t psk[32]; + } st; + bool allowAliases; + Noise::Padding padding; + uint16_t sendSize; + uint16_t recvSize; + size_t numProtocols; + const NoiseProtocolDescriptor *protocols[MAX_PROTOCOLS]; +}; + +/** @endcond */ + +/** + * \brief Constructs a new options block. + */ +NoiseLinkOptions::NoiseLinkOptions() + : d(new NoiseLinkOptionsPrivate()) +{ +} + +/** + * \brief Destroys this options block. + */ +NoiseLinkOptions::~NoiseLinkOptions() +{ + delete d; +} + +/** + * \brief Sets a parameter within this options block. + * + * \param id Identifies the parameter. + * \param value Points to the value to set for the parameter. + * \param size Size of the parameter value in bytes. + * + * \return Returns true if the parameter is set; false if the parameter + * \a id is not supported; or false if the \a size is not valid for the + * parameter. + * + * If the \a id is for the private key component of a key pair, then the + * public key component will be generated from \a value. Returns false if + * it is not possible to generate the public key component from the + * private key component. + * + * \sa getParameter(), getParameterSize() + */ +bool NoiseLinkOptions::setParameter(Noise::Parameter id, const void *value, size_t size) +{ + if (!value) + return false; + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + if (size != 64) + break; + memcpy(d->st.keyPair25519, value, 64); + d->st.flags |= HAVE_KEY_PAIR_25519; + return true; + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + if (size != 32) + break; + memcpy(d->st.keyPair25519, value, 32); + d->st.keyPair25519[0] &= 0xF8; + d->st.keyPair25519[31] = (d->st.keyPair25519[31] & 0x7F) | 0x40; + Curve25519::eval(d->st.keyPair25519 + 32, d->st.keyPair25519, 0); + d->st.flags |= HAVE_KEY_PAIR_25519; + return true; + case Noise::RemoteStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + if (size != 32) + break; + memcpy(d->st.remoteKey25519, value, 32); + d->st.flags |= HAVE_REMOTE_KEY_25519; + return true; + case Noise::PreSharedKey: + if (size != 32) + break; + memcpy(d->st.psk, value, 32); + d->st.flags |= HAVE_PSK; + return true; + default: break; + } + return false; +} + +/** + * \brief Gets the value associated from within this options block. + * + * \param id Identifies the parameter. + * \param value Points to the buffer to write the parameter value to. + * \param maxSize Maximum size of the \a value buffer in bytes. + * + * \return The number of bytes that were written to \a value. + * \return 0 if \a id is not valid. + * \return 0 if \a maxSize is not large enough to hold the parameter value. + * \return 0 if the parameter \a id has not been set yet. + * + * The getParameterSize() function can be used to determine the actual + * size of the parameter so that the caller can allocate a buffer large + * enough to contain it ahead of time. + * + * \sa setParameter(), getParameterSize() + */ +size_t NoiseLinkOptions::getParameter(Noise::Parameter id, void *value, size_t maxSize) const +{ + if (!value) + return 0; + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + if (maxSize < 64 || !(d->st.flags & HAVE_KEY_PAIR_25519)) + break; + memcpy(value, d->st.keyPair25519, 64); + return 64; + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + if (maxSize < 32 || !(d->st.flags & HAVE_KEY_PAIR_25519)) + break; + memcpy(value, d->st.keyPair25519, 32); + return 32; + case Noise::LocalStatic25519PublicKey: + case Noise::LocalStaticPublicKey: + if (maxSize < 32 || !(d->st.flags & HAVE_KEY_PAIR_25519)) + break; + memcpy(value, d->st.keyPair25519 + 32, 32); + return 32; + case Noise::RemoteStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + if (maxSize < 32 || !(d->st.flags & HAVE_KEY_PAIR_25519)) + break; + memcpy(value, d->st.remoteKey25519, 32); + return 32; + case Noise::PreSharedKey: + if (maxSize < 32 || !(d->st.flags & HAVE_PSK)) + break; + memcpy(value, d->st.psk, 32); + return 32; + default: break; + } + return 0; +} + +/** + * \brief Gets the size of a parameter within this options block. + * + * \param id Identifies the parameter. + * + * \return The parameter's size, or zero if \a id is not recognised. + * + * If the parameter is variable-length, then this function will return + * the actual length of the value, which may be zero if the value has + * not been set yet. + * + * \sa getParameter(), setParameter(), hasParameter() + */ +size_t NoiseLinkOptions::getParameterSize(Noise::Parameter id) const +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + return 64; + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + case Noise::RemoteStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + case Noise::PreSharedKey: + return 32; + default: + return 0; + } +} + +/** + * \brief Determine if a parameter has a value set within this options block. + * + * \param id Identifies the parameter. + * + * \return Returns true if \a id has a value; false if \a id does not + * have a value; false if \a id is not valid. + * + * \sa getParameterSize(), getParameter(), removeParameter() + */ +bool NoiseLinkOptions::hasParameter(Noise::Parameter id) const +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + return (d->st.flags & HAVE_KEY_PAIR_25519) != 0; + case Noise::RemoteStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + return (d->st.flags & HAVE_REMOTE_KEY_25519) != 0; + case Noise::PreSharedKey: + return (d->st.flags & HAVE_PSK) != 0; + default: + return false; + } +} + +/** + * \brief Removes a parameter from this options block. + * + * \param id Identifies the parameter. If the parameter is unknown, + * the request will be ignored. + * + * The clear() function will remove all parameters in a single call. + * + * \sa clear(), hasParameter() + */ +void NoiseLinkOptions::removeParameter(Noise::Parameter id) +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + clean(d->st.keyPair25519, 64); + d->st.flags &= ~HAVE_KEY_PAIR_25519; + break; + case Noise::RemoteStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + clean(d->st.remoteKey25519, 32); + d->st.flags &= ~HAVE_REMOTE_KEY_25519; + break; + case Noise::PreSharedKey: + clean(d->st.psk, 32); + d->st.flags &= ~HAVE_PSK; + break; + default: break; + } +} + +/** + * \brief Loads a parameter from the device's key ring. + * + * \param id Identifies the parameter to load. + * \param keyRingId Identifier of the stored key within the key ring, + * or zero to use the default key ring identifier for \a id. + * + * \return Returns true if the parameter was loaded. + * \return Returns false if \a id is not a valid parameter. + * \return Returns false if \a keyRingId does not have a key stored for it. + * + * The following example loads the Curve25519 key pair for the local + * device and the public key for the remote device that we are expecting + * to communicate with. If the local device does not have a key pair, + * then this example will generate a new one: + * + * \code + * if (!NoiseClientOptions.load(Noise::LocalStaticKeyPair)) { + * Serial.println("Generating a new key pair, please wait ..."); + * NoiseClientOptions.generate(Noise::LocalStaticKeyPair); + * } + * NoiseClientOptions.load(Noise::RemoteStaticPublicKey); + * \endcode + * + * If the key ring is protected by an encryption key or passphrase, + * then it is assumed that the key ring was already unlocked by a + * previous call to KeyRing.begin(). + * + * \sa generate(), save() + */ +bool NoiseLinkOptions::load(Noise::Parameter id, uint16_t keyRingId) +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + if (!keyRingId) + keyRingId = KeyRingClass::LocalCurve25519Default; + if (KeyRing.getLocalKeyPair(keyRingId, d->st.keyPair25519, 64) == 64) { + d->st.flags |= HAVE_KEY_PAIR_25519; + return true; + } + clean(d->st.keyPair25519, 64); + d->st.flags &= ~HAVE_KEY_PAIR_25519; + break; + case Noise::RemoteStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + if (!keyRingId) + keyRingId = KeyRingClass::RemoteCurve25519Default; + if (KeyRing.getRemotePublicKey + (keyRingId, d->st.remoteKey25519, 32) == 32) { + d->st.flags |= HAVE_REMOTE_KEY_25519; + return true; + } + clean(d->st.remoteKey25519, 32); + d->st.flags &= ~HAVE_REMOTE_KEY_25519; + break; + case Noise::PreSharedKey: + if (!keyRingId) + keyRingId = KeyRingClass::PreSharedKeyDefault; + if (KeyRing.getSharedSymmetricKey(keyRingId, d->st.psk, 32) == 32) { + d->st.flags |= HAVE_PSK; + return true; + } + clean(d->st.psk, 32); + d->st.flags &= ~HAVE_PSK; + break; + default: break; + } + return false; +} + +/** + * \brief Saves a parameter into the device's key ring. + * + * \param id Identifies the parameter to save. + * \param keyRingId Identifier of the stored key within the key ring, + * or zero to use the default key ring identifier for \a id. + * + * \return Returns true if the parameter was saved. + * \return Returns false if \a id is not a valid parameter or it does + * not currently have a value in this options block. + * \return Returns false if the key ring does not have enough space + * to store the parameter. + * + * If the key ring is protected by an encryption key or passphrase, + * then it is assumed that the key ring was already unlocked by a + * previous call to KeyRing.begin(). + * + * \sa load(), generate() + */ +bool NoiseLinkOptions::save(Noise::Parameter id, uint16_t keyRingId) +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + if (!keyRingId) + keyRingId = KeyRingClass::LocalCurve25519Default; + if ((d->st.flags & HAVE_KEY_PAIR_25519) == 0) + break; + return KeyRing.setLocalKeyPair(keyRingId, d->st.keyPair25519, 64); + case Noise::RemoteStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + if (!keyRingId) + keyRingId = KeyRingClass::RemoteCurve25519Default; + if ((d->st.flags & HAVE_REMOTE_KEY_25519) == 0) + break; + return KeyRing.setRemotePublicKey(keyRingId, d->st.remoteKey25519, 32); + case Noise::PreSharedKey: + if (!keyRingId) + keyRingId = KeyRingClass::PreSharedKeyDefault; + if ((d->st.flags & HAVE_PSK) == 0) + break; + return KeyRing.setSharedSymmetricKey(keyRingId, d->st.psk, 32); + default: break; + } + return false; +} + +/** + * \brief Generates a new local key pair for the device and saves it + * into the device's key ring. + * + * \param id Identifies the key pair to be generated. + * \param keyRingId Identifier for the saved key within the key ring, + * or zero to use the default key ring identifier for \a id. + * \param wait Set to true to wait for the system random number generator + * to have enough entropy to safely generate the key; false to immediately + * generate the key with whatever entropy is available at the moment. + * The default value for this parameter is true. + * + * \return Returns true if the new key pair was generated and saved. + * \return Returns false if \a id does not specify a valid key pair name. + * \return Returns false if there is not enough space left in the + * key ring to save the new key. + * + * The new key pair will also be loaded into this options block, ready for use. + * + * If the key ring is protected by an encryption key or passphrase, + * then it is assumed that the key ring was already unlocked by a + * previous call to KeyRing.begin(). + * + * \note If \a wait is true then this function may block for a long + * time on some devices to accumulate enough entropy to safely generate + * the key pair. Alternatively, the application can poll + * \link RNGClass::available() RNG.available()\endlink itself and call + * this function with \a wait set to false when ready; allowing the + * application to perform other setup tasks while waiting. + * + * \sa load(), save() + */ +bool NoiseLinkOptions::generate + (Noise::Parameter id, uint16_t keyRingId, bool wait) +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + if (!keyRingId) + keyRingId = KeyRingClass::LocalCurve25519Default; + while (wait && !RNG.available(32)) { + RNG.loop(); + crypto_feed_watchdog(); + } + Curve25519::generateKeyPair(d->st.keyPair25519); + if (KeyRing.setLocalKeyPair(keyRingId, d->st.keyPair25519, 64)) { + d->st.flags |= HAVE_KEY_PAIR_25519; + return true; + } + clean(d->st.keyPair25519, 64); + d->st.flags &= ~HAVE_KEY_PAIR_25519; + break; + default: break; + } + return false; +} + +/** + * \brief Gets the number of protocols that have been added to this + * options block. + * + * \return The number of protocols. + * + * \sa protocolAt(), addProtocol(), removeProtocol() + */ +size_t NoiseLinkOptions::protocolCount() const +{ + return d->numProtocols; +} + +/** + * \brief Gets a specific protocol from this options block. + * + * \param index The index of the protocol between 0 and protocolCount() - 1. + * + * \return A pointer to the protocol descriptor or NULL if \a index + * is out of range. + * + * \sa protocolCount(), addProtocol(), removeProtocol() + */ +const NoiseProtocolDescriptor *NoiseLinkOptions::protocolAt(size_t index) const +{ + if (index < d->numProtocols) + return d->protocols[index]; + else + return 0; +} + +/** + * \brief Adds a protocol to this options block. + * + * \param protocol The new protocol to add. + * + * The caller can add a maximum of 4 protocols to an options block. + * The first protocol added is the one used for outgoing connections + * using NoiseClient. All protocols can be accepted for incoming + * connections using NoiseServer. + * + * \sa removeProtocol(), protocolCount(), protocolAt() + */ +void NoiseLinkOptions::addProtocol(const NoiseProtocolDescriptor &protocol) +{ + if (d->numProtocols < MAX_PROTOCOLS) + d->protocols[(d->numProtocols)++] = &protocol; +} + +/** + * \brief Removes a protocol from this options block. + * + * \param protocol The protocol to remove. + * + * \sa addProtocol(), protocolCount(), protocolAt() + */ +void NoiseLinkOptions::removeProtocol(const NoiseProtocolDescriptor &protocol) +{ + for (size_t index = 0; index < d->numProtocols; ++index) { + if (d->protocols[index] == &protocol) { + memmove(d->protocols + index, d->protocols + index + 1, + (d->numProtocols - index - 1) * sizeof(d->protocols[0])); + --(d->numProtocols); + return; + } + } +} + +/** + * \brief Gets the size of the send buffer when a session is in progress. + * + * \return The size of the send buffer between 128 and 2048; default is 512. + * + * \sa setSendBufferSize(), receiveBufferSize() + */ +size_t NoiseLinkOptions::sendBufferSize() const +{ + return d->sendSize; +} + +/** + * \brief Sets the size of the send buffer when a session is in progress. + * + * \param size The size of the send buffer between 128 and 2048. + * + * \sa sendBufferSize(), setReceiveBufferSize(), setBufferSize() + */ +void NoiseLinkOptions::setSendBufferSize(size_t size) +{ + if (size < NOISE_MIN_BUFSIZ) + size = NOISE_MIN_BUFSIZ; + else if (size > NOISE_MAX_BUFSIZ) + size = NOISE_MAX_BUFSIZ; + d->sendSize = size; +} + +/** + * \brief Gets the size of the receive buffer when a session is in progress. + * + * \return The size of the receive buffer between 128 and 2048; default is 512. + * + * \sa setReceiveBufferSize(), sendBufferSize() + */ +size_t NoiseLinkOptions::receiveBufferSize() const +{ + return d->recvSize; +} + +/** + * \brief Sets the size of the receive buffer when a session is in progress. + * + * \param size The size of the receive buffer between 128 and 2048. + * + * \sa receiveBufferSize(), setSendBufferSize(), setBufferSize() + */ +void NoiseLinkOptions::setReceiveBufferSize(size_t size) +{ + if (size < NOISE_MIN_BUFSIZ) + size = NOISE_MIN_BUFSIZ; + else if (size > NOISE_MAX_BUFSIZ) + size = NOISE_MAX_BUFSIZ; + d->recvSize = size; +} + +/** + * \fn void NoiseLinkOptions::setBufferSize(size_t size) + * \brief Sets the size of the send and receive buffers to the same value. + * + * \param size The size of the send and receive buffers between 128 and 2048. + * + * \sa setSendBufferSize(), setReceiveBufferSize() + */ + +/** + * \brief Determine if NoiseTinyLink protocol name aliases are allowed. + * + * \return Returns true if protocol name aliases are allowed or false if not. + * The default is true. + * + * Protocol name aliases are strings like "2" instead of a full protocol + * name like "Noise_XX_25519_ChaChaPoly_SHA256". This can save bytes on + * the network when making an outgoing connection using NoiseClient. + * + * Incoming connections via NoiseServer can use either full names or aliases. + * This option has no effect on NoiseServer. + * + * If a protocol does not have a name alias, the full name will be used + * regardless of this option's setting. + * + * If your device is communicating with a server that is running the full + * version of NoiseLink, then it may not have support for protocol name + * aliases. In that case, use setAllowAliases(false) to force the use + * of the full protocol name when communicating with that server. + * + * \sa setAllowAliases() + */ +bool NoiseLinkOptions::allowAliases() const +{ + return d->allowAliases; +} + +/** + * \brief Enables or disables the use of NoiseTinyLink protocol name aliases. + * + * \param allow Set to true if protocol name aliases are allowed; false if not. + * + * \sa allowAliases() + */ +void NoiseLinkOptions::setAllowAliases(bool allow) +{ + d->allowAliases = allow; +} + +/** + * \brief Gets the type of padding to use on plaintext before encryption. + * + * \return The type of padding; default is Noise::NoPadding. + * + * \sa setPadding() + */ +Noise::Padding NoiseLinkOptions::padding() const +{ + return d->padding; +} + +/** + * \brief Sets the type of padding to use on plaintext before encryption. + * + * \param padding The type of padding; Noise::NoPadding, Noise::ZeroPadding, + * or Noise::RandomPadding. + * + * If \a padding is Noise::ZeroPadding, then the plaintext on outgoing + * packets will be padded with zeroes to sendBufferSize() before encryption. + * + * If \a padding is Noise::RandomPadding, then the plaintext on outgoing + * packets will be padded with random data to sendBufferSize() before + * encryption. + * + * \sa setPadding() + */ +void NoiseLinkOptions::setPadding(Noise::Padding padding) +{ + d->padding = padding; +} + +/** + * \brief Copies all values from another options block into this one. + * + * \param options The other options block to copy from. + */ +void NoiseLinkOptions::copyFrom(const NoiseLinkOptions &options) +{ + if (d != options.d) + d->copyFrom(options.d); +} + +/** + * \brief Destroys all security-sensitive data within this options block. + * + * If you only need to destroy a specific parameter (e.g. the local key pair), + * then you can use removeParameter() instead. + * + * \sa removeParameter() + */ +void NoiseLinkOptions::clear() +{ + d->clear(); +} + +/** + * \brief Creates a Noise handshake object for a specific protocol. + * + * \param party The party to create the handshake for; one of + * Noise::Initiator or Noise::Responder. + * \param protocolIndex The index of the protocol in this options block. + * + * \return A pointer to a new handshake object, populated with the keys + * that are needed to initialize the handshake. + * \return Returns NULL if \a protocolIndex is invalid or there are + * insufficient keys in this options block to initialize the handshake. + * + * \sa protocolAt() + */ +NoiseHandshakeState *NoiseLinkOptions::createHandshake + (Noise::Party party, size_t protocolIndex) const +{ + // Find the protocol to be created. + const NoiseProtocolDescriptor *desc = protocolAt(protocolIndex); + if (!desc) + return 0; + + // Verify that we have sufficient parameters to start the protocol. + unsigned short flags; + if (party == Noise::Initiator) + flags = desc->initiatorFlags; + else + flags = desc->responderFlags; + if ((flags & NOISE_PROTOCOL_NEEDS_LOCAL_STATIC) != 0 && + (d->st.flags & HAVE_KEY_PAIR_25519) == 0) + return 0; + if ((flags & NOISE_PROTOCOL_NEEDS_REMOTE_STATIC) != 0 && + (d->st.flags & HAVE_REMOTE_KEY_25519) == 0) + return 0; + if ((flags & NOISE_PROTOCOL_NEEDS_PSK) != 0 && + (d->st.flags & HAVE_PSK) == 0) + return 0; + + // Create the handshake object. + NoiseHandshakeState *handshake = desc->createHandshake(); + if (!handshake) + return 0; + + // Add all required keys. It is possible that this may fail if the + // protocol uses a different DH algorithm than Curve25519 or the + // flags in the protocol descriptor were incorrect for the handshake. + bool ok = true; + if ((flags & NOISE_PROTOCOL_NEEDS_LOCAL_STATIC) != 0) { + if (!handshake->setParameter + (Noise::LocalStatic25519KeyPair, d->st.keyPair25519, 64)) + ok = false; + } + if (ok && (flags & NOISE_PROTOCOL_NEEDS_REMOTE_STATIC) != 0) { + if (!handshake->setParameter + (Noise::RemoteStatic25519PublicKey, d->st.remoteKey25519, 32)) + ok = false; + } + if (ok && (flags & NOISE_PROTOCOL_NEEDS_PSK) != 0) { + if (!handshake->setParameter(Noise::PreSharedKey, d->st.psk, 32)) + ok = false; + } + if (!ok) { + delete handshake; + return 0; + } + + // Ready to go. + return handshake; +} diff --git a/libraries/NoiseProtocol/src/NoiseLinkOptions.h b/libraries/NoiseProtocol/src/NoiseLinkOptions.h new file mode 100644 index 00000000..c6684f86 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseLinkOptions.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * 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 NOISE_LINK_OPTIONS_h +#define NOISE_LINK_OPTIONS_h + +#include "NoiseNamespace.h" +#include "NoiseProtocolDescriptor.h" +#include "KeyRing.h" + +/** Default send/receive buffer size for NoiseLink sessions */ +#define NOISE_DEFAULT_BUFSIZ 512 + +/** Minimum send/receive buffer size that we allow for NoiseLink sessions */ +#define NOISE_MIN_BUFSIZ 128 + +/** Maximum send/receive buffer size that we allow for NoiseLink sessions */ +#define NOISE_MAX_BUFSIZ 2048 + +class NoiseLinkOptionsPrivate; + +class NoiseLinkOptions +{ +private: + // Disable the copy operators. + NoiseLinkOptions(const NoiseLinkOptions &other) {} + NoiseLinkOptions &operator=(const NoiseLinkOptions &other) { return *this; } + +public: + NoiseLinkOptions(); + ~NoiseLinkOptions(); + + bool setParameter(Noise::Parameter id, const void *value, size_t size); + size_t getParameter(Noise::Parameter id, void *value, size_t maxSize) const; + size_t getParameterSize(Noise::Parameter id) const; + bool hasParameter(Noise::Parameter id) const; + void removeParameter(Noise::Parameter id); + + bool load(Noise::Parameter id, uint16_t keyRingId = 0); + bool save(Noise::Parameter id, uint16_t keyRingId = 0); + bool generate(Noise::Parameter id, uint16_t keyRingId = 0, bool wait = true); + + size_t protocolCount() const; + const NoiseProtocolDescriptor *protocolAt(size_t index) const; + void addProtocol(const NoiseProtocolDescriptor &protocol); + void removeProtocol(const NoiseProtocolDescriptor &protocol); + + size_t sendBufferSize() const; + void setSendBufferSize(size_t size); + size_t receiveBufferSize() const; + void setReceiveBufferSize(size_t size); + void setBufferSize(size_t size) + { setSendBufferSize(size); setReceiveBufferSize(size); } + + bool allowAliases() const; + void setAllowAliases(bool allow); + + Noise::Padding padding() const; + void setPadding(Noise::Padding padding); + + void copyFrom(const NoiseLinkOptions &options); + + void clear(); + + NoiseHandshakeState *createHandshake + (Noise::Party party, size_t protocolIndex) const; + +private: + NoiseLinkOptionsPrivate *d; +}; + +extern NoiseLinkOptions NoiseClientOptions; +extern NoiseLinkOptions NoiseServerOptions; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseNamespace.cpp b/libraries/NoiseProtocol/src/NoiseNamespace.cpp deleted file mode 100644 index 505a4474..00000000 --- a/libraries/NoiseProtocol/src/NoiseNamespace.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2018 Southern Storm Software, Pty Ltd. - * - * 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. - */ - -#include "NoiseNamespace.h" - -/** - * \namespace Noise - * \brief Common definitions for the Noise protocol. - */ diff --git a/libraries/NoiseProtocol/src/NoiseNamespace.h b/libraries/NoiseProtocol/src/NoiseNamespace.h index 7985efe1..41ecc183 100644 --- a/libraries/NoiseProtocol/src/NoiseNamespace.h +++ b/libraries/NoiseProtocol/src/NoiseNamespace.h @@ -23,8 +23,10 @@ #ifndef NOISE_NAMESPACE_h #define NOISE_NAMESPACE_h -#include - +/** + * \namespace Noise + * \brief Common definitions for the Noise protocol. + */ namespace Noise { /** @@ -77,6 +79,28 @@ namespace Noise RemoteEphem25519PublicKey = 207 /**< Remote ephemeral Curve25519 public key */ }; + /** + * \brief Type of padding to apply to plaintext before encryption. + */ + enum Padding + { + NoPadding, /**< No padding */ + ZeroPadding, /**< Pad with zeroes to the maximum length */ + RandomPadding /**< Pad with random data to the maximum length */ + }; + + /** + * \brief Status of a NoiseClient connection. + */ + enum ConnectionStatus + { + Closed, /**< Connection is closed or session hasn't started */ + Connecting, /**< Connecting, handshake is not complete yet */ + Connected, /**< Connected, ready to transmit/receive data */ + Closing, /**< Connection is closing, but still unread data */ + HandshakeFailed /**< Failed to establish a secure connection */ + }; + }; // namespace Noise #endif diff --git a/libraries/NoiseProtocol/src/NoiseProtocol.h b/libraries/NoiseProtocol/src/NoiseProtocol.h index 8edb78d2..f04dae21 100644 --- a/libraries/NoiseProtocol/src/NoiseProtocol.h +++ b/libraries/NoiseProtocol/src/NoiseProtocol.h @@ -37,4 +37,7 @@ #include "Noise_XX_25519_ChaChaPoly_BLAKE2s.h" #include "Noise_XX_25519_ChaChaPoly_SHA256.h" +#include "NoiseClient.h" +#include "NoiseServer.h" + #endif diff --git a/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.h b/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.h index 60f4b198..a1864ae5 100644 --- a/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.h +++ b/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.h @@ -37,8 +37,13 @@ class NoiseHandshakeState; */ struct NoiseProtocolDescriptor { - /** Flags that define the properties and required keys for the protocol */ - unsigned flags; + /** Flags that define the properties and required keys for the protocol + * when the handshake is created from the initiator side. */ + unsigned short initiatorFlags; + + /** Flags that define the properties and required keys for the protocol + * when the handshake is created from the responder side. */ + unsigned short responderFlags; /** Full Noise protocol name; e.g. "Noise_XX_25519_ChaChaPoly_BLAKE2s" */ const char *protocolName; diff --git a/libraries/NoiseProtocol/src/NoiseServer.cpp b/libraries/NoiseProtocol/src/NoiseServer.cpp new file mode 100644 index 00000000..7f845081 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseServer.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * 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. + */ + +#include "NoiseServer.h" + +/** + * \class NoiseServer NoiseServer.h + * \brief Network server that uses Noise to secure incoming connections. + * + * This class is a template that wraps an underlying network server + * interface to layer the Noise protocol on top to provide security. + * Normally an application will use the NoiseEthernetServer or + * NoiseWiFiServer template instances to create a network server. + * + * Incoming Noise connections are secured using the options within + * the global NoiseServerOptions instance. + * + * \code + * #include + * #include + * #include + * + * uint8_t mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; + * NoiseEthernetServer server(4433); + * + * void setup() { + * // Initialise the system random number generator. + * RNG.begin("MyApp 1.0"); + * + * // Start the Ethernet interface. + * Ethernet.begin(mac); + * + * // Load or generate the Curve25519 key pair for this device. + * if (!NoiseServerOptions.load(Noise::LocalStaticKeyPair)) + * NoiseServerOptions.generate(Noise::LocalStaticKeyPair); + * + * // Specify the protocols that we permit incoming connections to use. + * NoiseServerOptions.addProtocol(Noise_XX_25519_ChaChaPoly_BLAKE2s); + * NoiseServerOptions.addProtocol(Noise_XX_25519_AESGCM_SHA256); + * + * // Limit packet payloads to 128 bytes and pad to full length. + * NoiseServerOptions.setBufferSize(128); + * NoiseServerOptions.setPadding(Noise::RandomPadding); + * + * // Start Ethernet server operations on the port. + * server.begin(); + * } + * + * void loop() { + * NoiseEthernetClient client = server.available(); + * if (client) { + * // Handle the incoming connection. + * ... + * } + * } + * \endcode + */ + +/** + * \fn NoiseServer::NoiseServer(uint16_t port) + * \brief Constructs a new network server that uses Noise. + * + * \param port The network port number to bind to on the underlying + * network interface when begin() is called. + * + * This will also construct the underlying network interface, which is + * usually an instance of EthernetServer or WiFiServer. + */ + +/** + * \fn NoiseServer::~NoiseServer() + * \brief Destroys this Noise-based network server. + * + * This will also destroy the underlying network interface. + */ + +/** + * \fn ServerT *NoiseServer::network() + * \brief Returns a reference to the underlying network interface. + * + * \return The underlying network server object; usually something like + * EthernetServer or WiFiServer. + * + * This function is intended to let the application adjust custom settings + * on the underlying network interface prior to calling begin(): + * + * \code + * NoiseWiFiServer server; + * server.network()->setNoDelay(true); + * server.begin(); + * \endcode + * + * \sa begin() + */ + +/** + * \fn void NoiseServer::begin() + * \brief Begins network server operations. + * + * \sa available() + */ + +/** + * \fn NoiseClientWrapper NoiseServer::available() + * \brief Checks for the next available incoming client. + * + * \return The next available incoming client, which may be false if there + * is no client available yet. Typically an instance of NoiseEthernetClient + * or NoiseWiFiClient depending upon the underlying network interface type. + * + * \code + * NoiseEthernetServer server; + * server.begin(); + * ... + * void loop() { + * NoiseEthernetClient client = server.available(); + * if (client) { + * // Handle the new client. + * ... + * } + * } + * \endcode + * + * \sa begin() + */ diff --git a/libraries/NoiseProtocol/src/NoiseServer.h b/libraries/NoiseProtocol/src/NoiseServer.h new file mode 100644 index 00000000..7f0fdd42 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseServer.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * 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 NOISE_SERVER_h +#define NOISE_SERVER_h + +#include "NoiseClient.h" +#include + +template +class NoiseServer : public Server +{ +private: + // Disable the copy operators. + NoiseServer(const NoiseServer &other) {} + NoiseServer &operator=(const NoiseServer &other) { return *this; } + +public: + explicit NoiseServer(uint16_t port) : net(port) {} + virtual ~NoiseServer() {} + + inline ServerT *network() { return &net; } + + // Standard Arduino Server interface. + inline void begin() { net.begin(); } + NoiseClientWrapper available(); + + /** @cond noise_server_write */ + // Disable the write() functions from the base Print class. + // "Write to all clients" behaviour is not supported. + size_t write(uint8_t) { return 0; } + size_t write(const uint8_t *buffer, size_t size) { return 0; } + /** @endcond */ + +private: + ServerT net; +}; + +template +NoiseClientWrapper NoiseServer::available() +{ + ClientT client = net.available(); + if (client) { + ClientT *networkClient = new ClientT(); + *networkClient = client; + NoiseClient *noiseClient = new NoiseClient(networkClient); + if (noiseClient->accept(NoiseServerOptions)) + return NoiseClientWrapper(noiseClient); + delete networkClient; + } + return NoiseClientWrapper(); +} + +#define NoiseEthernetServer NoiseServer +#define NoiseWiFiServer NoiseServer + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.cpp index ff2aeeb8..d56d8e6b 100644 --- a/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.cpp +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.cpp @@ -56,6 +56,7 @@ static NoiseHandshakeState *Noise_IK_25519_AESGCM_SHA256_createHandshake() */ const NoiseProtocolDescriptor Noise_IK_25519_AESGCM_SHA256 = { NOISE_PROTOCOL_NEEDS_LOCAL_STATIC | NOISE_PROTOCOL_NEEDS_REMOTE_STATIC, + NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, Noise_IK_25519_AESGCM_SHA256_Name, 0, Noise_IK_25519_AESGCM_SHA256_createHandshake diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp index 802172d9..a7c31b7d 100644 --- a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp @@ -56,6 +56,7 @@ static NoiseHandshakeState *Noise_IK_25519_ChaChaPoly_BLAKE2s_createHandshake() */ const NoiseProtocolDescriptor Noise_IK_25519_ChaChaPoly_BLAKE2s = { NOISE_PROTOCOL_NEEDS_LOCAL_STATIC | NOISE_PROTOCOL_NEEDS_REMOTE_STATIC, + NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, Noise_IK_25519_ChaChaPoly_BLAKE2s_Name, 0, Noise_IK_25519_ChaChaPoly_BLAKE2s_createHandshake diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.cpp index 2c064a0e..92dc0dd4 100644 --- a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.cpp +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.cpp @@ -56,6 +56,7 @@ static NoiseHandshakeState *Noise_IK_25519_ChaChaPoly_SHA256_createHandshake() */ const NoiseProtocolDescriptor Noise_IK_25519_ChaChaPoly_SHA256 = { NOISE_PROTOCOL_NEEDS_LOCAL_STATIC | NOISE_PROTOCOL_NEEDS_REMOTE_STATIC, + NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, Noise_IK_25519_ChaChaPoly_SHA256_Name, 0, Noise_IK_25519_ChaChaPoly_SHA256_createHandshake diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.cpp index 6e45459d..b2f1f24b 100644 --- a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.cpp +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.cpp @@ -55,6 +55,7 @@ static NoiseHandshakeState *Noise_NNpsk0_25519_AESGCM_SHA256_createHandshake() * \brief Protocol descriptor for "Noise_NNps0_25519_AESGCM_SHA256". */ const NoiseProtocolDescriptor Noise_NNpsk0_25519_AESGCM_SHA256 = { + NOISE_PROTOCOL_NEEDS_PSK, NOISE_PROTOCOL_NEEDS_PSK, Noise_NNpsk0_25519_AESGCM_SHA256_Name, 0, diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp index f03b3d3d..b1283a97 100644 --- a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp @@ -55,6 +55,7 @@ static NoiseHandshakeState *Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s_createHandshak * \brief Protocol descriptor for "Noise_NNps0_25519_ChaChaPoly_BLAKE2s". */ const NoiseProtocolDescriptor Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s = { + NOISE_PROTOCOL_NEEDS_PSK, NOISE_PROTOCOL_NEEDS_PSK, Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s_Name, 0, diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp index 3d56f5b8..889dc071 100644 --- a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp @@ -55,6 +55,7 @@ static NoiseHandshakeState *Noise_NNpsk0_25519_ChaChaPoly_SHA256_createHandshake * \brief Protocol descriptor for "Noise_NNps0_25519_ChaChaPoly_SHA256". */ const NoiseProtocolDescriptor Noise_NNpsk0_25519_ChaChaPoly_SHA256 = { + NOISE_PROTOCOL_NEEDS_PSK, NOISE_PROTOCOL_NEEDS_PSK, Noise_NNpsk0_25519_ChaChaPoly_SHA256_Name, 0, diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.cpp index a0004714..ba78a393 100644 --- a/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.cpp +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.cpp @@ -55,6 +55,7 @@ static NoiseHandshakeState *Noise_XX_25519_AESGCM_SHA256_createHandshake() * \brief Protocol descriptor for "Noise_XX_25519_AESGCM_SHA256". */ const NoiseProtocolDescriptor Noise_XX_25519_AESGCM_SHA256 = { + NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, Noise_XX_25519_AESGCM_SHA256_Name, "1", diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp index f40cc909..452d5ca0 100644 --- a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp @@ -55,6 +55,7 @@ static NoiseHandshakeState *Noise_XX_25519_ChaChaPoly_BLAKE2s_createHandshake() * \brief Protocol descriptor for "Noise_XX_25519ChaChaPoly_BLAKE2s". */ const NoiseProtocolDescriptor Noise_XX_25519_ChaChaPoly_BLAKE2s = { + NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, Noise_XX_25519_ChaChaPoly_BLAKE2s_Name, "3", diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.cpp index 86acf2e6..890b2cc7 100644 --- a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.cpp +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.cpp @@ -55,6 +55,7 @@ static NoiseHandshakeState *Noise_XX_25519_ChaChaPoly_SHA256_createHandshake() * \brief Protocol descriptor for "Noise_XX_25519ChaChaPoly_SHA256". */ const NoiseProtocolDescriptor Noise_XX_25519_ChaChaPoly_SHA256 = { + NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, NOISE_PROTOCOL_NEEDS_LOCAL_STATIC, Noise_XX_25519_ChaChaPoly_SHA256_Name, "2",