added mutual authentication, tweaked command line tool
This commit is contained in:
parent
0538c30081
commit
4b95e7d7a1
5 changed files with 132 additions and 18 deletions
|
@ -22,6 +22,7 @@
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "SSLClientImpl.h"
|
#include "SSLClientImpl.h"
|
||||||
#include "SSLSession.h"
|
#include "SSLSession.h"
|
||||||
|
#include "SSLClientParameters.h"
|
||||||
|
|
||||||
#ifndef SSLClient_H_
|
#ifndef SSLClient_H_
|
||||||
#define SSLClient_H_
|
#define SSLClient_H_
|
||||||
|
@ -67,11 +68,35 @@ public:
|
||||||
* @param trust_anchors_num The number of objects in the trust_anchors array.
|
* @param trust_anchors_num The number of objects in the trust_anchors array.
|
||||||
* @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG.
|
* @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG.
|
||||||
* @param debug The level of debug logging (use the ::DebugLevel enum).
|
* @param debug The level of debug logging (use the ::DebugLevel enum).
|
||||||
|
* @param mutual_auth_params Configuration to use for mutual authentication, nullptr to disable mutual auth. (see ::SSLClientParameters).
|
||||||
*/
|
*/
|
||||||
explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
|
explicit SSLClient( const C& client,
|
||||||
|
const br_x509_trust_anchor *trust_anchors,
|
||||||
|
const size_t trust_anchors_num,
|
||||||
|
const int analog_pin,
|
||||||
|
const DebugLevel debug = SSL_WARN)
|
||||||
: SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
|
: SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
|
||||||
, m_client(client)
|
, m_client(client)
|
||||||
, m_sessions{SSLSession()}
|
, m_sessions{}
|
||||||
|
{
|
||||||
|
// set the timeout to a reasonable number (it can always be changes later)
|
||||||
|
// SSL Connections take a really long time so we don't want to time out a legitimate thing
|
||||||
|
setTimeout(30 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as SSLClient::SSLClient(const C &, const br_x509_trust_anchor*, const size_t, const int, const DebugLevel),
|
||||||
|
* but can compile support for mutual authentication.
|
||||||
|
*/
|
||||||
|
explicit SSLClient( const C& client,
|
||||||
|
const br_x509_trust_anchor *trust_anchors,
|
||||||
|
const size_t trust_anchors_num,
|
||||||
|
const int analog_pin,
|
||||||
|
const DebugLevel debug,
|
||||||
|
const SSLClientParameters* mutual_auth_params)
|
||||||
|
: SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug, mutual_auth_params)
|
||||||
|
, m_client(client)
|
||||||
|
, m_sessions{}
|
||||||
{
|
{
|
||||||
// set the timeout to a reasonable number (it can always be changes later)
|
// set the timeout to a reasonable number (it can always be changes later)
|
||||||
// SSL Connections take a really long time so we don't want to time out a legitimate thing
|
// SSL Connections take a really long time so we don't want to time out a legitimate thing
|
||||||
|
|
|
@ -52,9 +52,7 @@ static int freeMemory() {
|
||||||
/* see SSLClientImpl.h */
|
/* see SSLClientImpl.h */
|
||||||
SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
||||||
const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
|
const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
|
||||||
: m_trust_anchors(trust_anchors)
|
: m_analog_pin(analog_pin)
|
||||||
, m_trust_anchors_num(trust_anchors_num)
|
|
||||||
, m_analog_pin(analog_pin)
|
|
||||||
, m_session_index(0)
|
, m_session_index(0)
|
||||||
, m_debug(debug)
|
, m_debug(debug)
|
||||||
, m_is_connected(false)
|
, m_is_connected(false)
|
||||||
|
@ -63,7 +61,7 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
||||||
// zero the iobuf just in case it's still garbage
|
// zero the iobuf just in case it's still garbage
|
||||||
memset(m_iobuf, 0, sizeof m_iobuf);
|
memset(m_iobuf, 0, sizeof m_iobuf);
|
||||||
// initlalize the various bearssl libraries so they're ready to go when we connect
|
// initlalize the various bearssl libraries so they're ready to go when we connect
|
||||||
br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
|
br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, trust_anchors, trust_anchors_num);
|
||||||
// comment the above line and uncomment the line below if you're having trouble connecting over SSL
|
// comment the above line and uncomment the line below if you're having trouble connecting over SSL
|
||||||
// br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
|
// br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
|
||||||
// check if the buffer size is half or full duplex
|
// check if the buffer size is half or full duplex
|
||||||
|
@ -71,6 +69,23 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
||||||
br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex);
|
br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* see SSLClientImpl.h */
|
||||||
|
SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
||||||
|
const size_t trust_anchors_num, const int analog_pin,
|
||||||
|
const DebugLevel debug, const SSLClientParameters* mutual_auth_params)
|
||||||
|
: SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) {
|
||||||
|
// if mutual authentication if needed, configure bearssl to support it.
|
||||||
|
if (mutual_auth_params != nullptr)
|
||||||
|
br_ssl_client_set_single_ec( &m_sslctx,
|
||||||
|
mutual_auth_params->client_cert_chain,
|
||||||
|
mutual_auth_params->chain_len,
|
||||||
|
&mutual_auth_params->ec_key,
|
||||||
|
BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
|
||||||
|
BR_KEYTYPE_EC,
|
||||||
|
br_ssl_engine_get_ec(&m_sslctx.eng),
|
||||||
|
&br_ecdsa_i15_sign_asn1);
|
||||||
|
}
|
||||||
|
|
||||||
/* see SSLClientImpl.h*/
|
/* see SSLClientImpl.h*/
|
||||||
int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) {
|
int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) {
|
||||||
const char* func_name = __func__;
|
const char* func_name = __func__;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "SSLSession.h"
|
#include "SSLSession.h"
|
||||||
|
#include "SSLClientParameters.h"
|
||||||
|
|
||||||
#ifndef SSLClientImpl_H_
|
#ifndef SSLClientImpl_H_
|
||||||
#define SSLClientImpl_H_
|
#define SSLClientImpl_H_
|
||||||
|
@ -72,7 +73,13 @@ class SSLClientImpl : public Client {
|
||||||
public:
|
public:
|
||||||
/** @see SSLClient::SSLClient */
|
/** @see SSLClient::SSLClient */
|
||||||
explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
||||||
const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug);
|
const size_t trust_anchors_num, const int analog_pin,
|
||||||
|
const DebugLevel debug);
|
||||||
|
|
||||||
|
/** @see SSLClient::SSLClient */
|
||||||
|
explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
||||||
|
const size_t trust_anchors_num, const int analog_pin,
|
||||||
|
const DebugLevel debug, const SSLClientParameters* mutual_auth_params);
|
||||||
|
|
||||||
//============================================
|
//============================================
|
||||||
//= Functions implemented in SSLClientImpl.cpp
|
//= Functions implemented in SSLClientImpl.cpp
|
||||||
|
@ -171,10 +178,6 @@ private:
|
||||||
//= Data Members
|
//= Data Members
|
||||||
//============================================
|
//============================================
|
||||||
|
|
||||||
// store pointers to the trust anchors
|
|
||||||
// should not be computed at runtime
|
|
||||||
const br_x509_trust_anchor *m_trust_anchors;
|
|
||||||
const size_t m_trust_anchors_num;
|
|
||||||
// store the pin to fetch an RNG see from
|
// store the pin to fetch an RNG see from
|
||||||
const int m_analog_pin;
|
const int m_analog_pin;
|
||||||
// store an index of where a new session can be placed if we don't have any corresponding sessions
|
// store an index of where a new session can be placed if we don't have any corresponding sessions
|
||||||
|
|
66
src/SSLClientParameters.h
Normal file
66
src/SSLClientParameters.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* Copyright 2019 OSU OPEnS Lab
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSLClientParameters.h
|
||||||
|
*
|
||||||
|
* This file contains a simple utility class to store parameters about an SSL Session
|
||||||
|
* for reuse later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bearssl.h"
|
||||||
|
|
||||||
|
#ifndef SSLClientParameters_H_
|
||||||
|
#define SSLClientParameters_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file contains a simple struct to package together all the data required to
|
||||||
|
* use client certificate authentication with SSLClient.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This struct stores data required for SSLClient to use mutual authentication.
|
||||||
|
*
|
||||||
|
* TLS mutual authentication is a process in which both the server and client
|
||||||
|
* perform cryptographic operations to verify the authenticity of eachother, for more
|
||||||
|
* information check out this article: https://medium.com/sitewards/the-magic-of-tls-x509-and-mutual-authentication-explained-b2162dec4401 .
|
||||||
|
* If this struct is provided to SSLClient::SSLClient, SSLClient will automatically
|
||||||
|
* send a client certificate if one is requested by the server. This will happen for all
|
||||||
|
* SSLClient connections, and may cause issues for websites that do not need mutual authentication---
|
||||||
|
* as a result, please only turn on mutual authentication if you are sure it is neccesary.
|
||||||
|
*
|
||||||
|
* At the moment SSLClient only supports mutual authentication using ECC client certificates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct SSLClientParameters {
|
||||||
|
/**
|
||||||
|
* \brief Pointer to the client certificate chain.
|
||||||
|
*
|
||||||
|
* Must be availible in memory AT ALL TIMES, should not be a local object.
|
||||||
|
* Certificates must be ordered from Client->Intermediate->...->Root.
|
||||||
|
*/
|
||||||
|
const br_x509_certificate* client_cert_chain;
|
||||||
|
/** The number of certificates in SSLClientParameters::client_cert_chain */
|
||||||
|
const size_t chain_len;
|
||||||
|
/** The private key corresponding to the first certificate in SSLClientParameters::client_cert_chain */
|
||||||
|
const br_ec_private_key ec_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -100,8 +100,10 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom
|
||||||
help='the location of the .pem file containing a list of trusted root certificates (default: use certifi.where())')
|
help='the location of the .pem file containing a list of trusted root certificates (default: use certifi.where())')
|
||||||
@click.option('--keep-dupes', '-d', is_flag=True, default=False,
|
@click.option('--keep-dupes', '-d', is_flag=True, default=False,
|
||||||
help='write all certs including any duplicates (default: remove duplicates)')
|
help='write all certs including any duplicates (default: remove duplicates)')
|
||||||
|
@click.option('--no-verify', '-n', is_flag=True, default=False,
|
||||||
|
help='Do not attempt to match a root certificate to the provided PEM files')
|
||||||
@click.argument('cert', type=click.File('r'), nargs=-1)
|
@click.argument('cert', type=click.File('r'), nargs=-1)
|
||||||
def convert(cert_var, cert_length_var, output, use_store, keep_dupes, cert):
|
def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_verify, cert):
|
||||||
"""Convert PEM certificates into a C header that can be imported into a
|
"""Convert PEM certificates into a C header that can be imported into a
|
||||||
sketch. Specify each certificate to encode as a separate argument (each
|
sketch. Specify each certificate to encode as a separate argument (each
|
||||||
must be in PEM format) and they will be merged into a single file.
|
must be in PEM format) and they will be merged into a single file.
|
||||||
|
@ -132,6 +134,9 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, cert):
|
||||||
cert_objs.append(cert_parsed)
|
cert_objs.append(cert_parsed)
|
||||||
# find a root certificate for each
|
# find a root certificate for each
|
||||||
root_certs = []
|
root_certs = []
|
||||||
|
if no_verify:
|
||||||
|
root_certs = cert_objs
|
||||||
|
else:
|
||||||
for i, c in enumerate(cert_objs):
|
for i, c in enumerate(cert_objs):
|
||||||
cn_hash = c.get_issuer().hash()
|
cn_hash = c.get_issuer().hash()
|
||||||
if cn_hash not in cert_dict:
|
if cn_hash not in cert_dict:
|
||||||
|
|
Loading…
Reference in a new issue