feat: add CA install fn, load and gen fns, and decode helper
This commit is contained in:
+117
-12
@@ -12,6 +12,12 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#pragma comment(lib, "crypt32.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
CertificateManager implementation
|
CertificateManager implementation
|
||||||
*/
|
*/
|
||||||
@@ -38,8 +44,7 @@ bool CertificateManager::init()
|
|||||||
if (derLen < 0) return false;
|
if (derLen < 0) return false;
|
||||||
_sessionKeyDer.resize(derLen);
|
_sessionKeyDer.resize(derLen);
|
||||||
|
|
||||||
if (loadCA()) return true;
|
return true;
|
||||||
return generateCA();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WOLFSSL_CTX* CertificateManager::createHostContext(const std::string& host)
|
WOLFSSL_CTX* CertificateManager::createHostContext(const std::string& host)
|
||||||
@@ -87,41 +92,141 @@ WOLFSSL_CTX* CertificateManager::createHostContext(const std::string& host)
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CertificateManager::generateCA()
|
#ifdef _WIN32
|
||||||
|
bool CertificateManager::installCertificate()
|
||||||
|
{
|
||||||
|
if (_caCertDer.empty()) return false;
|
||||||
|
|
||||||
|
PCCERT_CONTEXT certCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, _caCertDer.data(),
|
||||||
|
(DWORD)_caCertDer.size());
|
||||||
|
|
||||||
|
if (!certCtx) return false;
|
||||||
|
HCERTSTORE rootStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"Root");
|
||||||
|
bool success = false;
|
||||||
|
if (rootStore)
|
||||||
|
{
|
||||||
|
success = CertAddCertificateContextToStore(rootStore, certCtx, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
|
||||||
|
CertCloseStore(rootStore, 0);
|
||||||
|
}
|
||||||
|
CertFreeCertificateContext(certCtx);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool CertificateManager::generateAndSaveCA(const char* caName, int days, const std::string& certPath,
|
||||||
|
const std::string& keyPath)
|
||||||
{
|
{
|
||||||
_caKey.reset(new RsaKey());
|
_caKey.reset(new RsaKey());
|
||||||
wc_InitRsaKey(_caKey.get(), nullptr);
|
wc_InitRsaKey(_caKey.get(), nullptr);
|
||||||
|
|
||||||
if (wc_MakeRsaKey(_caKey.get(), 2048, 65537, _rng.get()) != 0)
|
if (wc_MakeRsaKey(_caKey.get(), 2048, 65537, _rng.get()) != 0) return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cert = std::make_unique<Cert>();
|
auto cert = std::make_unique<Cert>();
|
||||||
memset(cert.get(), 0, sizeof(Cert));
|
memset(cert.get(), 0, sizeof(Cert));
|
||||||
wc_InitCert(cert.get());
|
wc_InitCert(cert.get());
|
||||||
|
|
||||||
strncpy_s(cert->subject.commonName, sizeof(cert->subject.commonName), "TinyMITM-CA", _TRUNCATE);
|
strncpy_s(cert->subject.commonName, sizeof(cert->subject.commonName), caName, _TRUNCATE);
|
||||||
cert->isCA = 1;
|
cert->isCA = 1;
|
||||||
cert->sigType = CTC_SHA256wRSA;
|
cert->sigType = CTC_SHA256wRSA;
|
||||||
cert->daysValid = 3650;
|
cert->daysValid = days;
|
||||||
|
|
||||||
_caCertDer.resize(4096);
|
_caCertDer.resize(4096);
|
||||||
|
|
||||||
int certLen =
|
int certLen =
|
||||||
wc_MakeCert(cert.get(), _caCertDer.data(), (word32)_caCertDer.size(), _caKey.get(), nullptr, _rng.get());
|
wc_MakeCert(cert.get(), _caCertDer.data(), (word32)_caCertDer.size(), _caKey.get(), nullptr, _rng.get());
|
||||||
if (certLen < 0) return false;
|
if (certLen < 0) return false;
|
||||||
|
|
||||||
certLen = wc_SignCert(cert->bodySz, cert->sigType, _caCertDer.data(), (word32)_caCertDer.size(), _caKey.get(),
|
certLen = wc_SignCert(cert->bodySz, cert->sigType, _caCertDer.data(), (word32)_caCertDer.size(), _caKey.get(),
|
||||||
nullptr, _rng.get());
|
nullptr, _rng.get());
|
||||||
|
|
||||||
if (certLen < 0) return false;
|
if (certLen < 0) return false;
|
||||||
_caCertDer.resize(certLen);
|
_caCertDer.resize(certLen);
|
||||||
|
|
||||||
|
std::vector<unsigned char> keyDer(4096);
|
||||||
|
int keyDerLen = wc_RsaKeyToDer(_caKey.get(), keyDer.data(), (word32)keyDer.size());
|
||||||
|
if (keyDerLen < 0) return false;
|
||||||
|
|
||||||
|
std::vector<unsigned char> keyPem(4096);
|
||||||
|
int keyPemLen =
|
||||||
|
wc_DerToPem(keyDer.data(), (word32)keyDerLen, keyPem.data(), (word32)keyPem.size(), PRIVATEKEY_TYPE);
|
||||||
|
|
||||||
|
std::ofstream kOut(keyPath, std::ios::binary);
|
||||||
|
if (!kOut.is_open()) return false;
|
||||||
|
kOut.write((char*)keyPem.data(), keyPemLen);
|
||||||
|
|
||||||
|
std::vector<unsigned char> certPem(4096);
|
||||||
|
int certPemLen =
|
||||||
|
wc_DerToPem(_caCertDer.data(), (word32)_caCertDer.size(), certPem.data(), (word32)certPem.size(), CERT_TYPE);
|
||||||
|
|
||||||
|
std::ofstream cOut(certPath, std::ios::binary);
|
||||||
|
if (!cOut.is_open()) return false;
|
||||||
|
cOut.write((char*)certPem.data(), certPemLen);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CertificateManager::loadCA()
|
bool CertificateManager::loadCA(const char* certPath, const char* keyPath)
|
||||||
{
|
{
|
||||||
|
auto readFile = [](const char* path) -> std::vector<unsigned char> {
|
||||||
|
std::ifstream file(path, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file.is_open()) return {};
|
||||||
|
std::streamsize size = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
std::vector<unsigned char> buffer((size_t)size);
|
||||||
|
if (file.read((char*)buffer.data(), size)) return buffer;
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<unsigned char> certPem = readFile(certPath);
|
||||||
|
std::vector<unsigned char> keyPem = readFile(keyPath);
|
||||||
|
|
||||||
|
if (certPem.empty() || keyPem.empty()) return false;
|
||||||
|
|
||||||
|
std::vector<unsigned char> certDer;
|
||||||
|
std::vector<unsigned char> keyDer;
|
||||||
|
DerBuffer* derBuff = nullptr;
|
||||||
|
|
||||||
|
int ret = wc_PemToDer(certPem.data(), (long)certPem.size(), CERT_TYPE, &derBuff, nullptr, nullptr, nullptr);
|
||||||
|
if (ret == 0 && derBuff)
|
||||||
|
{
|
||||||
|
certDer.assign(derBuff->buffer, derBuff->buffer + derBuff->length);
|
||||||
|
free(derBuff->buffer);
|
||||||
|
free(derBuff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
derBuff = nullptr;
|
||||||
|
ret = wc_PemToDer(keyPem.data(), (long)keyPem.size(), PRIVATEKEY_TYPE, &derBuff, nullptr, nullptr, nullptr);
|
||||||
|
if (ret == 0 && derBuff)
|
||||||
|
{
|
||||||
|
keyDer.assign(derBuff->buffer, derBuff->buffer + derBuff->length);
|
||||||
|
free(derBuff->buffer);
|
||||||
|
free(derBuff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return decodeCA(certDer, keyDer);
|
||||||
|
}
|
||||||
|
bool CertificateManager::decodeCA(const std::vector<unsigned char>& certDer, const std::vector<unsigned char>& keyDer)
|
||||||
|
{
|
||||||
|
if (certDer.empty() || keyDer.empty()) return false;
|
||||||
|
|
||||||
|
RsaKey* rawKey = new RsaKey();
|
||||||
|
if (wc_InitRsaKey(rawKey, nullptr) != 0)
|
||||||
|
{
|
||||||
|
delete rawKey;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<RsaKey, RAAIHelper> tempKey(rawKey, RAAIHelper());
|
||||||
|
|
||||||
|
word32 idx = 0;
|
||||||
|
int ret = wc_RsaPrivateKeyDecode(keyDer.data(), &idx, tempKey.get(), (word32)keyDer.size());
|
||||||
|
|
||||||
|
if (ret != 0) return false;
|
||||||
|
|
||||||
|
_caKey = std::move(tempKey);
|
||||||
|
_caCertDer = certDer;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,9 +18,15 @@ class CertificateManager
|
|||||||
|
|
||||||
WOLFSSL_CTX* createHostContext(const std::string& host);
|
WOLFSSL_CTX* createHostContext(const std::string& host);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
bool installCertificate();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool generateAndSaveCA(const char* caName, int days, const std::string& certPath, const std::string& keyPath);
|
||||||
|
bool loadCA(const char* certPath, const char* keyPath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool generateCA();
|
bool decodeCA(const std::vector<unsigned char>& certDer, const std::vector<unsigned char>& keyDer);
|
||||||
bool loadCA();
|
|
||||||
|
|
||||||
std::unique_ptr<RsaKey, RAAIHelper> _caKey;
|
std::unique_ptr<RsaKey, RAAIHelper> _caKey;
|
||||||
std::unique_ptr<RsaKey, RAAIHelper> _sessionKey;
|
std::unique_ptr<RsaKey, RAAIHelper> _sessionKey;
|
||||||
|
|||||||
Reference in New Issue
Block a user