added mutual authentication, tweaked command line tool

This commit is contained in:
Noah Laptop 2019-07-23 18:29:13 -07:00
parent 0538c30081
commit 4b95e7d7a1
5 changed files with 132 additions and 18 deletions

View file

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

View file

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

View file

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

View file

@ -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,12 +134,15 @@ 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 = []
for i, c in enumerate(cert_objs): if no_verify:
cn_hash = c.get_issuer().hash() root_certs = cert_objs
if cn_hash not in cert_dict: else:
click.echo('Could not find a root certificate for {0}'.format(cert[i].name)) for i, c in enumerate(cert_objs):
else: cn_hash = c.get_issuer().hash()
root_certs.append(cert_dict[cn_hash]) if cn_hash not in cert_dict:
click.echo('Could not find a root certificate for {0}'.format(cert[i].name))
else:
root_certs.append(cert_dict[cn_hash])
# Combine PEMs and write output header. # Combine PEMs and write output header.
cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes) cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes)