feat: add CA install fn, load and gen fns, and decode helper
This commit is contained in:
+118
-13
@@ -12,6 +12,12 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
#endif
|
||||
|
||||
/*
|
||||
CertificateManager implementation
|
||||
*/
|
||||
@@ -38,8 +44,7 @@ bool CertificateManager::init()
|
||||
if (derLen < 0) return false;
|
||||
_sessionKeyDer.resize(derLen);
|
||||
|
||||
if (loadCA()) return true;
|
||||
return generateCA();
|
||||
return true;
|
||||
}
|
||||
|
||||
WOLFSSL_CTX* CertificateManager::createHostContext(const std::string& host)
|
||||
@@ -87,41 +92,141 @@ WOLFSSL_CTX* CertificateManager::createHostContext(const std::string& host)
|
||||
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());
|
||||
wc_InitRsaKey(_caKey.get(), nullptr);
|
||||
|
||||
if (wc_MakeRsaKey(_caKey.get(), 2048, 65537, _rng.get()) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (wc_MakeRsaKey(_caKey.get(), 2048, 65537, _rng.get()) != 0) return false;
|
||||
|
||||
auto cert = std::make_unique<Cert>();
|
||||
memset(cert.get(), 0, sizeof(Cert));
|
||||
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->sigType = CTC_SHA256wRSA;
|
||||
cert->daysValid = 3650;
|
||||
cert->daysValid = days;
|
||||
|
||||
_caCertDer.resize(4096);
|
||||
|
||||
int certLen =
|
||||
wc_MakeCert(cert.get(), _caCertDer.data(), (word32)_caCertDer.size(), _caKey.get(), nullptr, _rng.get());
|
||||
if (certLen < 0) return false;
|
||||
|
||||
certLen = wc_SignCert(cert->bodySz, cert->sigType, _caCertDer.data(), (word32)_caCertDer.size(), _caKey.get(),
|
||||
nullptr, _rng.get());
|
||||
|
||||
if (certLen < 0) return false;
|
||||
_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;
|
||||
}
|
||||
|
||||
bool CertificateManager::loadCA()
|
||||
bool CertificateManager::loadCA(const char* certPath, const char* keyPath)
|
||||
{
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#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:
|
||||
bool generateCA();
|
||||
bool loadCA();
|
||||
bool decodeCA(const std::vector<unsigned char>& certDer, const std::vector<unsigned char>& keyDer);
|
||||
|
||||
std::unique_ptr<RsaKey, RAAIHelper> _caKey;
|
||||
std::unique_ptr<RsaKey, RAAIHelper> _sessionKey;
|
||||
@@ -31,6 +37,6 @@ class CertificateManager
|
||||
std::unique_ptr<WC_RNG, RAAIHelper> _rng;
|
||||
|
||||
std::mutex _mutex;
|
||||
|
||||
|
||||
std::unordered_map<std::string, WOLFSSL_CTX*> _hostContexts;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user