SPIFFS and self-sign fixes

This commit is contained in:
iranl
2025-02-18 15:27:03 +01:00
parent 21d5491e50
commit 3fa605b2b0
8 changed files with 211 additions and 196 deletions

View File

@@ -1,10 +1,34 @@
/*
MIT License
Copyright (c) 2017 Frank Hessel
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.
*/
#include "SSLCert.hpp"
SSLCert::SSLCert(unsigned char * certData, uint16_t certLength, unsigned char * pkData, uint16_t pkLength):
SSLCert::SSLCert(uint16_t certLength, uint16_t pkLength, String keyPEM, String certPEM):
_certLength(certLength),
_certData(certData),
_pkLength(pkLength),
_pkData(pkData) {
_keyPEM(keyPEM),
_certPEM(certPEM) {
}
@@ -12,7 +36,6 @@ SSLCert::~SSLCert() {
// TODO Auto-generated destructor stub
}
uint16_t SSLCert::getCertLength() {
return _certLength;
}
@@ -21,39 +44,88 @@ uint16_t SSLCert::getPKLength() {
return _pkLength;
}
unsigned char * SSLCert::getCertData() {
return _certData;
String SSLCert::getKeyPEM() {
return _keyPEM;
}
unsigned char * SSLCert::getPKData() {
return _pkData;
String SSLCert::getCertPEM() {
return _certPEM;
}
void SSLCert::setPK(unsigned char * pkData, uint16_t length) {
_pkData = pkData;
_pkLength = length;
void SSLCert::setPK(String keyPEM) {
_keyPEM = keyPEM;
_pkLength = keyPEM.length();
}
void SSLCert::setCert(unsigned char * certData, uint16_t length) {
_certData = certData;
_certLength = length;
void SSLCert::setCert(String certPEM) {
_certPEM = certPEM;
_certLength = certPEM.length();
}
void SSLCert::clear() {
for(uint16_t i = 0; i < _certLength; i++) _certData[i]=0;
delete _certData;
_certLength = 0;
for(uint16_t i = 0; i < _pkLength; i++) _pkData[i] = 0;
delete _pkData;
_pkLength = 0;
_keyPEM = "";
_certPEM = "";
}
/**
* Returns the CN value from a DN, or "" if it cannot be found
*/
static std::string get_cn(std::string dn) {
size_t cnStart = dn.find("CN=");
if (cnStart == std::string::npos) {
return "";
}
cnStart += 3;
size_t cnStop = dn.find(",", cnStart);
if (cnStop == std::string::npos) {
cnStop = dn.length();
}
return dn.substr(cnStart, cnStop - cnStart);
}
/**
* Sets the DN as subjectAltName extension in the certificate
*/
static int add_subject_alt_name(mbedtls_x509write_cert *crt, std::string &cn) {
size_t bufsize = cn.length() + 8; // some additional space for tags and length fields
uint8_t buf[bufsize];
uint8_t *p = &buf[bufsize - 1];
uint8_t *start = buf;
int length = 0;
int ret; // used by MBEDTLS macro
// The ASN structure that we will construct as parameter for write_crt_set_extension is as follows:
// | 0x30 = Sequence | length | 0x82 = dNSName, context-specific | length | cn0 | cn1 | cn2 | cn3 | .. | cnn |
// ↑ : ↑ `-------------v------------------´:
// | : `-------------------´ :
// | `----------v------------------------------------------------------------------´
// `---------------´
// Let's encrypt has useful infos: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/#choice-and-any-encoding
MBEDTLS_ASN1_CHK_ADD(length,
mbedtls_asn1_write_raw_buffer(&p, start, (uint8_t*)cn.c_str(), cn.length()));
MBEDTLS_ASN1_CHK_ADD(length,
mbedtls_asn1_write_len(&p, start, length));
MBEDTLS_ASN1_CHK_ADD(length,
mbedtls_asn1_write_tag(&p, start, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0x02)); // 0x02 = dNSName
MBEDTLS_ASN1_CHK_ADD(length,
mbedtls_asn1_write_len(&p, start, length));
MBEDTLS_ASN1_CHK_ADD(length,
mbedtls_asn1_write_tag(&p, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ));
return mbedtls_x509write_crt_set_extension( crt,
MBEDTLS_OID_SUBJECT_ALT_NAME, MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
0, // not critical
p, length);
}
/**
* Function to create the key for a self-signed certificate.
*
*
* Writes private key as DER in certCtx
*
*
* Based on programs/pkey/gen_key.c
*/
static int gen_key(SSLCert &certCtx, SSLKeySize keySize) {
@@ -84,7 +156,7 @@ static int gen_key(SSLCert &certCtx, SSLKeySize keySize) {
return HTTPS_SERVER_ERROR_KEYGEN_SETUP_PK;
}
// Actual key generation
// Actual key generation
int resPkGen = mbedtls_rsa_gen_key(
mbedtls_pk_rsa( key ),
mbedtls_ctr_drbg_random,
@@ -112,30 +184,20 @@ static int gen_key(SSLCert &certCtx, SSLKeySize keySize) {
memset(output_buf, 0, 4096);
// Write the key to the temporary buffer and determine its length
int resPkWrite = mbedtls_pk_write_key_der( &key, output_buf, 4096 );
int resPkWrite = mbedtls_pk_write_key_pem( &key, output_buf, 4096 );
if (resPkWrite < 0) {
delete[] output_buf;
mbedtls_pk_free( &key );
return HTTPS_SERVER_ERROR_KEY_WRITE_PK;
}
size_t pkLength = resPkWrite;
unsigned char *pkOffset = output_buf + sizeof(unsigned char) * 4096 - pkLength;
// Copy the key into a new, fitting space on the heap
unsigned char * output_pk = new unsigned char[pkLength];
if (output_pk == NULL) {
delete[] output_buf;
mbedtls_pk_free( &key );
return HTTPS_SERVER_ERROR_KEY_WRITE_PK;
}
memcpy(output_pk, pkOffset, pkLength);
// Clean up the temporary buffer and clear the key context
delete[] output_buf;
mbedtls_pk_free( &key );
// Set the private key in the context
certCtx.setPK(output_pk, pkLength);
certCtx.setPK((char*)output_buf);
delete[] output_buf;
return 0;
}
@@ -180,12 +242,12 @@ static int parse_serial_decimal_format(unsigned char *obuf, size_t obufmax,
/**
* Function to generate the X509 certificate data for a private key
*
*
* Writes certificate in certCtx
*
* Based on programs/x509/cert_write.c
*/
static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom, std::string validityTo) {
int funcRes = 0;
int stepRes = 0;
@@ -198,14 +260,18 @@ static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom
unsigned char *certOffset;
unsigned char * output_buffer;
size_t certLength;
const char *defaultSerial = "1";
unsigned char serial[MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN];
const char *serial = "peer";
size_t serial_len;
// Make a C-friendly version of the distinguished name
char dn_cstr[dn.length()+1];
strcpy(dn_cstr, dn.c_str());
std::string cn = get_cn(dn);
if (cn == "") {
return HTTPS_SERVER_ERROR_CERTGEN_CN;
}
// Initialize the entropy source
mbedtls_entropy_init( &entropy );
@@ -218,7 +284,8 @@ static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom
}
mbedtls_pk_init( &key );
stepRes = mbedtls_pk_parse_key( &key, certCtx.getPKData(), certCtx.getPKLength(), NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg);
stepRes = mbedtls_pk_parse_key( &key, (const unsigned char *)certCtx.getKeyPEM().c_str(), certCtx.getPKLength() + 1, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg);
if (stepRes != 0) {
funcRes = HTTPS_SERVER_ERROR_CERTGEN_READKEY;
goto error_after_key;
@@ -260,15 +327,14 @@ static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom
goto error_after_cert;
}
// Initialize the serial number
stepRes = parse_serial_decimal_format(serial, sizeof(serial), defaultSerial, &serial_len);
stepRes = add_subject_alt_name( &crt, cn );
if (stepRes != 0) {
funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL;
goto error_after_cert_serial;
funcRes = HTTPS_SERVER_ERROR_CERTGEN_NAME;
goto error_after_cert;
}
stepRes = mbedtls_x509write_crt_set_serial_raw( &crt, serial, sizeof(serial) );
// Initialize the serial number
stepRes = mbedtls_x509write_crt_set_serial_raw( &crt, (unsigned char *)serial, strlen(serial) );
if (stepRes != 0) {
funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL;
goto error_after_cert_serial;
@@ -282,26 +348,14 @@ static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom
}
// Write the actual certificate
stepRes = mbedtls_x509write_crt_der(&crt, primary_buffer, 4096, mbedtls_ctr_drbg_random, &ctr_drbg );
stepRes = mbedtls_x509write_crt_pem(&crt, primary_buffer, 4096, mbedtls_ctr_drbg_random, &ctr_drbg );
if (stepRes < 0) {
funcRes = HTTPS_SERVER_ERROR_CERTGEN_WRITE;
goto error_after_primary_buffer;
}
// Create a matching buffer
certLength = stepRes;
certOffset = primary_buffer + sizeof(unsigned char) * 4096 - certLength;
// Copy the cert into a new, fitting space on the heap
output_buffer = new unsigned char[certLength];
if (output_buffer == NULL) {
funcRes = HTTPS_SERVER_ERROR_CERTGEN_OUT_OF_MEM;
goto error_after_primary_buffer;
}
memcpy(output_buffer, certOffset, certLength);
// Configure the cert in the context
certCtx.setCert(output_buffer, certLength);
certCtx.setCert((char*)primary_buffer);
// Run through the cleanup process
error_after_primary_buffer:
@@ -334,7 +388,7 @@ int createSelfSignedCert(SSLCert &certCtx, SSLKeySize keySize, std::string dn, s
int certRes = cert_write(certCtx, dn, validFrom, validUntil);
if (certRes != 0) {
// Cert writing failed, reset the pk and return failure code
certCtx.setPK(NULL, 0);
certCtx.setPK("");
return certRes;
}