halfway through rewrite of mTLS api, need to finish testing RSA support

This commit is contained in:
Noah Laptop 2020-02-26 11:54:18 -08:00
parent 801f81ec9b
commit f5672e6884
5 changed files with 59 additions and 95 deletions

View file

@ -272,17 +272,25 @@ void SSLClient::removeSession(const char* host) {
} }
/* see SSLClient.h */ /* see SSLClient.h */
void SSLClient::setMutualAuthParams(const SSLClientParameters* params) { void SSLClient::setMutualAuthParams(const SSLClientParameters& params) {
// if mutual authentication if needed, configure bearssl to support it. // if mutual authentication if needed, configure bearssl to support it.
if (params != nullptr) if (params.getECKey() != NULL) {
br_ssl_client_set_single_ec( &m_sslctx, br_ssl_client_set_single_ec( &m_sslctx,
params->client_cert_chain, params.getCertChain(),
params->chain_len, 1,
&params->ec_key, params.getECKey(),
BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
BR_KEYTYPE_EC, BR_KEYTYPE_EC,
br_ssl_engine_get_ec(&m_sslctx.eng), br_ssl_engine_get_ec(&m_sslctx.eng),
&br_ecdsa_i15_sign_asn1); &br_ecdsa_i15_sign_asn1);
}
else if (params.getRSAKey() != NULL) {
br_ssl_client_set_single_rsa( &m_sslctx,
params.getCertChain(),
1,
params.getRSAKey(),
&br_rsa_i15_pkcs1_sign);
}
} }
bool SSLClient::m_soft_connected(const char* func_name) { bool SSLClient::m_soft_connected(const char* func_name) {

View file

@ -21,7 +21,6 @@
#include "Client.h" #include "Client.h"
#include "SSLSession.h" #include "SSLSession.h"
#include "SSLClientParameters.h" #include "SSLClientParameters.h"
#include "SSLObj.h"
#include <vector> #include <vector>
#ifndef SSLClient_H_ #ifndef SSLClient_H_
@ -313,7 +312,7 @@ public:
* *
* @pre SSLClient has not already started an SSL connection. * @pre SSLClient has not already started an SSL connection.
*/ */
void setMutualAuthParams(const SSLClientParameters* params); void setMutualAuthParams(const SSLClientParameters& 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

View file

@ -1,4 +1,4 @@
#include "SSLObj.h" #include "SSLClientParameters.h"
// fix for non-exception arduino platforms // fix for non-exception arduino platforms
#ifdef ADAFRUIT_FEATHER_M0 #ifdef ADAFRUIT_FEATHER_M0
@ -8,24 +8,24 @@ namespace std {
#endif #endif
struct ssl_pem_decode_state { struct ssl_pem_decode_state {
std::vector<unsigned char>* vect; std::vector<char>* vect;
size_t index = 0; size_t index = 0;
}; };
static void ssl_pem_decode_callback(void *dest_ctx, const void *src, size_t len) { static void ssl_pem_decode_callback(void *dest_ctx, const void *src, size_t len) {
ssl_pem_decode_state* ctx = static_cast<ssl_pem_decode_state*>(dest_ctx); ssl_pem_decode_state* ctx = static_cast<ssl_pem_decode_state*>(dest_ctx);
for (size_t i = 0; i < len; i++) ctx->vect->emplace_back(static_cast<const unsigned char*>(src)[i]); for (size_t i = 0; i < len; i++) ctx->vect->emplace_back(static_cast<const char*>(src)[i]);
// update index // update index
ctx->index += len; ctx->index += len;
} }
const std::vector<unsigned char> SSLObj::make_vector_pem(const char* data, const size_t len) { static const std::vector<char> make_vector_pem(const char* data, const size_t len) {
if (data == nullptr || len < 80) return {}; if (data == nullptr || len < 80) return {};
// initialize the bearssl PEM context // initialize the bearssl PEM context
br_pem_decoder_context pctx; br_pem_decoder_context pctx;
br_pem_decoder_init(&pctx); br_pem_decoder_init(&pctx);
// create a temporary vector // create a temporary vector
std::vector<unsigned char> temp; std::vector<char> temp;
// initialize the DER storage context // initialize the DER storage context
ssl_pem_decode_state state; ssl_pem_decode_state state;
state.vect = &temp; state.vect = &temp;
@ -53,3 +53,15 @@ const std::vector<unsigned char> SSLObj::make_vector_pem(const char* data, const
// else we're good! // else we're good!
return temp; return temp;
} }
static br_skey_decoder_context make_key_from_der(const std::vector<char>& der) {
br_skey_decoder_context out;
br_skey_decoder_init(&out);
br_skey_decoder_push(&out, der.data(), der.size());
return out;
}
SSLClientParameters::SSLClientParameters(const char* cert, const size_t cert_len, const char* key, const size_t key_len, bool is_der)
: m_cert(is_der ? std::vector<char>(cert, cert + cert_len) : make_vector_pem(cert, cert_len))
, m_cert_struct{ const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(m_cert.data())), m_cert.size() }
, m_key{ make_key_from_der(is_der ? std::vector<char>(key, key + key_len) : make_vector_pem(key, key_len)) } {}

View file

@ -26,17 +26,15 @@
*/ */
#include "bearssl.h" #include "bearssl.h"
#undef min
#undef max
#include <vector>
#ifndef SSLClientParameters_H_ #ifndef SSLClientParameters_H_
#define SSLClientParameters_H_ #define SSLClientParameters_H_
/** /**
* This file contains a simple struct to package together all the data required to * \brief This class stores data required for SSLClient to use mutual authentication.
* 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 * TLS mutual authentication is a process in which both the server and client
* perform cryptographic operations to verify the authenticity of eachother, for more * perform cryptographic operations to verify the authenticity of eachother, for more
@ -49,18 +47,28 @@
* At the moment SSLClient only supports mutual authentication using ECC client certificates. * At the moment SSLClient only supports mutual authentication using ECC client certificates.
*/ */
struct SSLClientParameters { class SSLClientParameters {
/** public:
* \brief Pointer to the client certificate chain.
* /*
* Must be availible in memory AT ALL TIMES, should not be a local object. static SSLClientParameters fromECCPEM(const char* cert_pem, const char* key_pem);
* Certificates must be ordered from Client->Intermediate->...->Root. static SSLClientParameters fromECCDER(const char* cert_der, const char* key_der);
static SSLClientParameters fromRSAPEM(const char* cert_pem, const char* key_pem);
static SSLClientParameters fromRSADER(const char* cert_der, const char* key_der);
*/ */
const br_x509_certificate* client_cert_chain;
/** The number of certificates in SSLClientParameters::client_cert_chain */ const br_x509_certificate* getCertChain() const { return &m_cert_struct; }
const size_t chain_len; int getCertType() const { return br_skey_decoder_key_type(&m_key); }
/** The private key corresponding to the first certificate in SSLClientParameters::client_cert_chain */ const br_ec_private_key* getECKey() const { return br_skey_decoder_get_ec(&m_key); }
const br_ec_private_key ec_key; const br_rsa_private_key* getRSAKey() const { return br_skey_decoder_get_rsa(&m_key); }
// protected:
SSLClientParameters(const char* cert, const size_t cert_len, const char* key, const size_t key_len, bool is_der = false);
private:
const std::vector<char> m_cert;
const br_x509_certificate m_cert_struct;
const br_skey_decoder_context m_key;
}; };
#endif #endif

View file

@ -1,63 +0,0 @@
/* 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 <cstring>
#include "bearssl_pem.h"
#ifndef SSLObj_H_
#define SSLObj_H_
#undef min
#undef max
#include <vector>
/**
* \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.
*/
namespace SSLObj {
/**
* @brief Convert a PEM buffer into a vector of raw DER bytes
*
* This function takes a PEM buffer (e.g. `----BEGIN CERTIFICATE...`) and converts
* it into a vector of raw bytes. The bytes given to this function must:
* * Contain both the `-----BEGIN XXX-----` and `-----END XXX-----` strings. These are
* removed during processing.
* * Have a base64 encoded body
* * Only contain a single object (certificate, private key, etc.).
*
* @returns The raw bytes decoded from the PEM file.
*/
const std::vector<unsigned char> make_vector_pem(const char* data, const size_t len);
}
#endif