Rework client certificates, add support for decoding a PEM object
This commit is contained in:
parent
43d517c9df
commit
2b287f5179
5 changed files with 132 additions and 37 deletions
|
@ -22,6 +22,7 @@
|
|||
#include "SSLClientImpl.h"
|
||||
#include "SSLSession.h"
|
||||
#include "SSLClientParameters.h"
|
||||
#include "SSLObj.h"
|
||||
|
||||
#ifndef SSLClient_H_
|
||||
#define SSLClient_H_
|
||||
|
@ -81,25 +82,6 @@ public:
|
|||
// 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)
|
||||
// SSL Connections take a really long time so we don't want to time out a legitimate thing
|
||||
setTimeout(30 * 1000);
|
||||
}
|
||||
|
||||
//========================================
|
||||
//= Functions implemented in SSLClientImpl
|
||||
|
@ -307,6 +289,13 @@ public:
|
|||
//= Functions Not in the Client Interface
|
||||
//========================================
|
||||
|
||||
/**
|
||||
* @brief Add a client certificate and enable support for mutual auth
|
||||
*
|
||||
* This function must be called BEFORE making an SSL connection.
|
||||
*/
|
||||
void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); }
|
||||
|
||||
/**
|
||||
* @brief Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist
|
||||
*
|
||||
|
|
|
@ -69,23 +69,6 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
|
|||
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*/
|
||||
int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) {
|
||||
const char* func_name = __func__;
|
||||
|
@ -331,6 +314,20 @@ void SSLClientImpl::remove_session_impl(const char* host, const IPAddress& addr)
|
|||
}
|
||||
}
|
||||
|
||||
/* see SSLClientImpl.h */
|
||||
void SSLClientImpl::set_mutual_impl(const SSLClientParameters* params) {
|
||||
// if mutual authentication if needed, configure bearssl to support it.
|
||||
if (params != nullptr)
|
||||
br_ssl_client_set_single_ec( &m_sslctx,
|
||||
params->client_cert_chain,
|
||||
params->chain_len,
|
||||
¶ms->ec_key,
|
||||
BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
|
||||
BR_KEYTYPE_EC,
|
||||
br_ssl_engine_get_ec(&m_sslctx.eng),
|
||||
&br_ecdsa_i15_sign_asn1);
|
||||
}
|
||||
|
||||
bool SSLClientImpl::m_soft_connected(const char* func_name) {
|
||||
// check if the socket is still open and such
|
||||
if (getWriteError()) {
|
||||
|
|
|
@ -107,7 +107,8 @@ public:
|
|||
SSLSession& get_session_impl(const char* host, const IPAddress& addr);
|
||||
/** @see SSLClient::removeSession */
|
||||
void remove_session_impl(const char* host, const IPAddress& addr);
|
||||
|
||||
/** @see SSLClient::setMutualAuthParams */
|
||||
void set_mutual_impl(const SSLClientParameters* params);
|
||||
//============================================
|
||||
//= Functions implemented in SSLClient.h
|
||||
//============================================
|
||||
|
|
57
src/SSLObj.cpp
Normal file
57
src/SSLObj.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "SSLObj.h"
|
||||
|
||||
struct ssl_pem_decode_state {
|
||||
std::vector<unsigned char>* vect;
|
||||
size_t index = 0;
|
||||
};
|
||||
|
||||
static void ssl_pem_decode(void *dest_ctx, const void *src, size_t len) {
|
||||
ssl_pem_decode_state* ctx = static_cast<ssl_pem_decode_state*>(dest_ctx);
|
||||
// copy the recieved bytes into the vector, resizing if needed
|
||||
if (ctx->vect->size() < len + ctx->index) {
|
||||
Serial.println("Overflow!");
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) (*(ctx->vect))[i + ctx->index] = static_cast<const unsigned char*>(src)[i];
|
||||
// update index
|
||||
ctx->index += len;
|
||||
}
|
||||
|
||||
const std::vector<unsigned char> SSLObj::make_vector_pem(const char* data, const size_t len) {
|
||||
if (data == nullptr || len == 0) return { 0 };
|
||||
// initialize the bearssl PEM context
|
||||
br_pem_decoder_context pctx;
|
||||
br_pem_decoder_init(&pctx);
|
||||
// create a temporary vector
|
||||
std::vector<unsigned char> temp(len * 3 / 4 + 5);
|
||||
// initialize the DER storage context
|
||||
ssl_pem_decode_state state;
|
||||
state.vect = &temp;
|
||||
state.index = 0;
|
||||
// set the byte reciever
|
||||
br_pem_decoder_setdest(&pctx, &ssl_pem_decode, &state);
|
||||
// start decoding!
|
||||
int br_state = 0;
|
||||
size_t index = 0;
|
||||
do {
|
||||
index += br_pem_decoder_push(&pctx, static_cast<const void*>(&data[index]), len - index);
|
||||
br_state = br_pem_decoder_event(&pctx);
|
||||
} while (br_state != BR_PEM_ERROR && br_state != BR_PEM_END_OBJ);
|
||||
// error check
|
||||
if (br_state == BR_PEM_ERROR) {
|
||||
// set data to error
|
||||
temp.clear();
|
||||
}
|
||||
// else we're good!
|
||||
return { temp };
|
||||
}
|
||||
|
||||
const std::vector<unsigned char> SSLObj::make_vector_der(const char* data, const size_t len) {
|
||||
if (data == nullptr || len == 0) return { 0 };
|
||||
// create a temporary vector
|
||||
std::vector<unsigned char> temp(len);
|
||||
// copy the elements over
|
||||
for (size_t i = 0; i < len; i++) temp[i] = data[i];
|
||||
// return the new SSLObj
|
||||
return { temp };
|
||||
}
|
51
src/SSLObj.h
Normal file
51
src/SSLObj.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SSLObj.h
|
||||
*
|
||||
* This file contains a utility class to take PEM input and store it as a DER object
|
||||
* for later use by BearSSL.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include "bearssl_pem.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifndef SSLObj_H_
|
||||
#define SSLObj_H_
|
||||
|
||||
/**
|
||||
* \brief This namespace works with raw DER byte arrays for use later with TLS mutual auth.
|
||||
*
|
||||
* This namespace was created to store some of the values stored in ::SSLClientParameters,
|
||||
* which allow BearSSL use client certificates when creating a TLS connection. Since
|
||||
* most certificates are transmitted over the internet in PEM format, a certificate can
|
||||
* be provided in PEM or DER format, and will be converted internally to DER format for
|
||||
* later use. A PEM file provided to this class MUST CONTAIN the `----BEGIN ... -----`
|
||||
* header in order to be parsed correctly.
|
||||
*/
|
||||
|
||||
namespace SSLObj {
|
||||
const std::vector<unsigned char> make_vector_pem(const char* data, const size_t len);
|
||||
const std::vector<unsigned char> make_vector_der(const char* data, const size_t len);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue