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 "SSLClientImpl.h"
|
||||||
#include "SSLSession.h"
|
#include "SSLSession.h"
|
||||||
#include "SSLClientParameters.h"
|
#include "SSLClientParameters.h"
|
||||||
|
#include "SSLObj.h"
|
||||||
|
|
||||||
#ifndef SSLClient_H_
|
#ifndef SSLClient_H_
|
||||||
#define SSLClient_H_
|
#define SSLClient_H_
|
||||||
|
@ -82,25 +83,6 @@ public:
|
||||||
setTimeout(30 * 1000);
|
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
|
//= Functions implemented in SSLClientImpl
|
||||||
//========================================
|
//========================================
|
||||||
|
@ -307,6 +289,13 @@ public:
|
||||||
//= Functions Not in the Client Interface
|
//= 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
|
* @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);
|
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__;
|
||||||
|
@ -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) {
|
bool SSLClientImpl::m_soft_connected(const char* func_name) {
|
||||||
// check if the socket is still open and such
|
// check if the socket is still open and such
|
||||||
if (getWriteError()) {
|
if (getWriteError()) {
|
||||||
|
|
|
@ -107,7 +107,8 @@ public:
|
||||||
SSLSession& get_session_impl(const char* host, const IPAddress& addr);
|
SSLSession& get_session_impl(const char* host, const IPAddress& addr);
|
||||||
/** @see SSLClient::removeSession */
|
/** @see SSLClient::removeSession */
|
||||||
void remove_session_impl(const char* host, const IPAddress& addr);
|
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
|
//= 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