mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Define the NoiseClient and NoiseServer API's
This commit is contained in:
parent
ff04a61efa
commit
3b5da67919
@ -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 \
|
||||
|
55
host/emulation/Client.h
Normal file
55
host/emulation/Client.h
Normal file
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
33
host/emulation/Server.h
Normal file
33
host/emulation/Server.h
Normal file
@ -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
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -1,2 +1,6 @@
|
||||
NoiseClient KEYWORD1
|
||||
NoiseEthernetClient KEYWORD1
|
||||
NoiseWiFiClient KEYWORD1
|
||||
NoiseServer KEYWORD1
|
||||
NoiseEthernetServer KEYWORD1
|
||||
NoiseWiFiServer KEYWORD1
|
||||
|
@ -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":
|
||||
{
|
||||
|
489
libraries/NoiseProtocol/src/NoiseClient.cpp
Normal file
489
libraries/NoiseProtocol/src/NoiseClient.cpp
Normal file
@ -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 <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;
|
||||
}
|
193
libraries/NoiseProtocol/src/NoiseClient.h
Normal file
193
libraries/NoiseProtocol/src/NoiseClient.h
Normal file
@ -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 <Client.h>
|
||||
|
||||
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 <typename T>
|
||||
class NoiseClientWrapper : public Client
|
||||
{
|
||||
public:
|
||||
inline NoiseClientWrapper() : d(0) {}
|
||||
inline NoiseClientWrapper(const NoiseClientWrapper<T> &other)
|
||||
: d(other.d) { NoiseClient::ref(d); }
|
||||
inline NoiseClientWrapper(NoiseClient *client) : d(client) {}
|
||||
inline ~NoiseClientWrapper() { NoiseClient::deref(d); }
|
||||
|
||||
inline NoiseClientWrapper<T> &operator=(const NoiseClientWrapper<T> &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<EthernetClient>
|
||||
#define NoiseWiFiClient NoiseClientWrapper<WiFiClient>
|
||||
|
||||
#endif
|
867
libraries/NoiseProtocol/src/NoiseLinkOptions.cpp
Normal file
867
libraries/NoiseProtocol/src/NoiseLinkOptions.cpp
Normal file
@ -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 <string.h>
|
||||
|
||||
/**
|
||||
* \class NoiseLinkOptions NoiseLinkOptions.h <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;
|
||||
}
|
94
libraries/NoiseProtocol/src/NoiseLinkOptions.h
Normal file
94
libraries/NoiseProtocol/src/NoiseLinkOptions.h
Normal file
@ -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
|
@ -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.
|
||||
*/
|
@ -23,8 +23,10 @@
|
||||
#ifndef NOISE_NAMESPACE_h
|
||||
#define NOISE_NAMESPACE_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* \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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
144
libraries/NoiseProtocol/src/NoiseServer.cpp
Normal file
144
libraries/NoiseProtocol/src/NoiseServer.cpp
Normal file
@ -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 <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 <NoiseProtocol.h>
|
||||
* #include <Ethernet.h>
|
||||
* #include <RNG.h>
|
||||
*
|
||||
* 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<ClientT> 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()
|
||||
*/
|
76
libraries/NoiseProtocol/src/NoiseServer.h
Normal file
76
libraries/NoiseProtocol/src/NoiseServer.h
Normal file
@ -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 <Server.h>
|
||||
|
||||
template <typename ServerT, typename ClientT>
|
||||
class NoiseServer : public Server
|
||||
{
|
||||
private:
|
||||
// Disable the copy operators.
|
||||
NoiseServer(const NoiseServer<ServerT, ClientT> &other) {}
|
||||
NoiseServer &operator=(const NoiseServer<ServerT, ClientT> &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<ClientT> 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 <typename ServerT, typename ClientT>
|
||||
NoiseClientWrapper<ClientT> NoiseServer<ServerT, ClientT>::available()
|
||||
{
|
||||
ClientT client = net.available();
|
||||
if (client) {
|
||||
ClientT *networkClient = new ClientT();
|
||||
*networkClient = client;
|
||||
NoiseClient *noiseClient = new NoiseClient(networkClient);
|
||||
if (noiseClient->accept(NoiseServerOptions))
|
||||
return NoiseClientWrapper<ClientT>(noiseClient);
|
||||
delete networkClient;
|
||||
}
|
||||
return NoiseClientWrapper<ClientT>();
|
||||
}
|
||||
|
||||
#define NoiseEthernetServer NoiseServer<EthernetServer, EthernetClient>
|
||||
#define NoiseWiFiServer NoiseServer<WiFiServer, WiFiClient>
|
||||
|
||||
#endif
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user