AuroraRuntime/Source/Crypto/X509/AuCertificateChain.cpp
J Reece Wilson 7a0593adeb [+] AuCrypto::CA::ICertificateStore
[+] AuCrypto::CA::INewCertificateStore
[+] AuCrypto::CA::IPinCertificate
[+] AuCrypto::CA::PinAlwaysFail
[+] AuCrypto::CA::PinAlwaysPass
[+] AuCrypto::CA::PinCheckOS
[+] AuCrypto::CA::PinCheckDefault
[+] AuCrypto::CA::PinCheckBuiltin
[+] AuCrypto::CA::PinCheckGlobal
[+] AuCrypto::CA::PinCheckTwoAnd
[+] AuCrypto::CA::PinCheckTwoOr
[+] AuCrypto::CA::SetGlobalTLSPinner
[*] Minor AuCrypto::X509 decoder work
[*] AuCrypto::X509: transition to memory views (x509 is bytebuffer era and earlier code, beri early)
[+] AuCrypto::IPrivateKeyProvider
[+] AuCrypto::IPrivateKeyPair
[+] AuCrypto::PrivateKeyPair
[+] AuCrypto::ImportPrivateKeyPair
[*] Refactor: AuCrypto::X509::GenerateCertificate(...)
[+] AuCrypto::X509::NewChainFromOneDer
[+] AuCrypto::X509::NewChainFromManyDer
[+] AuCrypto::X509::NewChainFromManyDerInStream
[+] AuCrypto::X509::NewChainFromOnePem
[+] AuCrypto::X509::NewChainFromManyPem
[+] AuCrypto::X509::NewChainFromManyPemInStream
[*] Fix TLS code that was abandoned since its introduction with the net code. mbedtls is a hairbrained mess. so many *blocking* github issues starting after 2017. so little progress.
[+] AuIO::TLS::TLSMeta::pKeyPairProvider
[+] AuIO::TLS::TLSServer::bAllowSNIToFallBackDefault
[+] AuIO::TLS::TLSServer::bAllowSNILessUseDefaultCert
2024-10-16 02:07:24 +01:00

476 lines
12 KiB
C++

/***
Copyright (C) 2022-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuCertificateChain.cpp
File: TLSCertificateChain.cpp
Date: 2022-8-27
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuCertificateChain.hpp"
#include <Source/Crypto/X509/x509.hpp>
namespace Aurora::Crypto::X509
{
CertificateChain::CertificateChain()
{
}
CertificateChain::~CertificateChain()
{
::mbedtls_x509_crt_free(&this->ownCertificate);
}
AuUInt32 CertificateChain::GetCertificateCount()
{
AuUInt32 ret {};
auto pCert = this->pCertificate;
if (!pCert)
{
return {};
}
do
{
auto index = ret++;
}
while ((pCert = pCert->next));
return ret;
}
AuMemoryViewRead CertificateChain::GetCertificate(AuUInt32 idx)
{
AuUInt32 ret {};
auto pCert = this->pCertificate;
if (!pCert)
{
return {};
}
do
{
auto index = ret++;
if (index == idx)
{
return AuMemoryViewRead { AuMemoryViewRead { pCert->raw.p, pCert->raw.len}, AuSharedFromThis() };
}
}
while ((pCert = pCert->next));
return {};
}
AuOptional<const X509::CertificateDecoded &> CertificateChain::GetCertificateDetails(AuUInt32 uSelectedIndex)
{
AU_LOCK_GUARD(this->mutex);
if (auto uSize = this->decoded.size())
{
if (uSize <= uSelectedIndex)
{
return {};
}
else
{
return this->decoded[uSelectedIndex];
}
}
else
{
auto pCert = this->pCertificate;
if (!pCert)
{
return {};
}
AuUInt32 uIterator {};
do
{
uIterator++;
Crypto::X509::CertificateDecoded cert;
AuCrypto::X509::DecodeInternal(*pCert, cert);
this->decoded.push_back(cert);
}
while ((pCert = pCert->next));
if (uIterator <= uSelectedIndex)
{
return {};
}
else
{
return this->decoded[uSelectedIndex];
}
}
}
mbedtls_x509_crt *CertificateChain::GetCertificateInternal(AuUInt32 idx)
{
AuUInt32 ret {};
auto pCert = this->pCertificate;
if (!pCert)
{
return {};
}
do
{
if (ret++ == idx)
{
return pCert;
}
}
while ((pCert = pCert->next));
return nullptr;
}
bool CertificateChain::Init(const AuList<AuMemoryViewRead> &certs)
{
int iRet {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
this->ownership = certs;
for (auto &cert : this->ownership)
{
if (!cert.HasControlBlock())
{
if (!cert.TryCloneSelf())
{
return false;
}
}
iRet = ::mbedtls_x509_crt_parse_der_nocopy(&this->ownCertificate,
(const unsigned char *)cert.ToPointer(),
cert.length);
if (iRet != 0)
{
this->pCertificate = nullptr;
SysPushErrorCrypto("Failed to parse certificate chain: {}", iRet);
return false;
}
}
return this->Precache();
}
bool CertificateChain::Init(const AuMemoryViewRead &cert)
{
int iRet {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
this->ownership2 = cert;
if (!this->ownership2.HasControlBlock())
{
if (!this->ownership2.TryCloneSelf())
{
return false;
}
}
iRet = ::mbedtls_x509_crt_parse_der_nocopy(&this->ownCertificate,
(const unsigned char *)this->ownership2.ToPointer(),
this->ownership2.length);
if (iRet != 0)
{
SysPushErrorCrypto("Failed to parse certificate chain: {}", iRet);
return false;
}
return this->Precache();
}
bool CertificateChain::Init2(const AuMemoryViewRead &cert)
{
int iRet {};
AuUInt uReadOffset {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
this->ownership2 = cert;
if (!this->ownership2.HasControlBlock())
{
if (!this->ownership2.TryCloneSelf())
{
return false;
}
}
while (uReadOffset != cert.uLength)
{
iRet = ::mbedtls_x509_crt_parse_der_nocopy(&this->ownCertificate,
(const unsigned char *)this->ownership2.ToPointer() + uReadOffset,
this->ownership2.length - uReadOffset);
if (iRet != 0)
{
SysPushErrorCrypto("Failed to parse certificate chain: {} at {}", iRet, uReadOffset);
return false;
}
{
auto pCert = this->pCertificate;
while (pCert->next)
{
pCert = pCert->next;
}
uReadOffset += pCert->raw.len;
}
}
return this->Precache();
}
bool CertificateChain::Init(const mbedtls_x509_crt *pCert)
{
this->pCertificate = (mbedtls_x509_crt *)pCert;
return this->Precache();
}
bool CertificateChain::Init(const AuList<AuROString> &certs)
{
int iRet {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
for (auto &cert : certs)
{
AuByteBuffer buffer;
if (!PEM::FromString(cert, buffer))
{
SysPushErrorSyntax("Couldnt parse PEM");
return false;
}
iRet = ::mbedtls_x509_crt_parse_der(&this->ownCertificate,
(const unsigned char *)buffer.base,
buffer.length);
if (iRet != 0)
{
SysPushErrorCrypto("Failed to parse certificate chain: {}", iRet);
return false;
}
}
return this->Precache();
}
bool CertificateChain::Init(const AuROString &cert)
{
int iRet {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
AuByteBuffer buffer;
if (!PEM::FromString(cert, buffer))
{
SysPushErrorSyntax("Couldnt parse PEM");
return false;
}
iRet = ::mbedtls_x509_crt_parse_der(&this->ownCertificate,
(const unsigned char *)buffer.base,
buffer.length);
if (iRet != 0)
{
SysPushErrorCrypto("Failed to parse certificate chain [TEXT]: {}", iRet);
return false;
}
return this->Precache();
}
bool CertificateChain::Init2(const AuROString &cert)
{
int iRet {};
AuUInt uIndex {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
uIndex = cert.find("-----BEGIN CERTIFICATE-----");
while (uIndex != AuROString::npos)
{
AuByteBuffer buffer;
auto uEndIndex = cert.find("-----END CERTIFICATE-----", uIndex);
if (uEndIndex == AuROString::npos)
{
return false;
}
if (!PEM::FromString(cert.SubStr(uIndex, uEndIndex + 25 - uIndex), buffer))
{
SysPushErrorSyntax("Couldnt parse PEM");
return false;
}
iRet = ::mbedtls_x509_crt_parse_der(&this->ownCertificate,
(const unsigned char *)buffer.base,
buffer.length);
if (iRet != 0)
{
SysPushErrorCrypto("Failed to parse certificate chain: {}, PEM: {}", iRet, cert.SubStr(uIndex, uEndIndex + 25 - uIndex));
return false;
}
uIndex = cert.find("-----BEGIN CERTIFICATE-----", uIndex + 10);
}
return this->Precache();
}
bool CertificateChain::Precache()
{
return true;
}
AUKN_SYM ICertificateChain *NewChainFromOneDerNew(const AuMemoryViewRead &read)
{
auto pCertificateChain = _new CertificateChain();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init(read))
{
return {};
}
return pCertificateChain;
}
AUKN_SYM void NewChainFromOneDerRelease(ICertificateChain *pHandle)
{
AuSafeDelete<CertificateChain *>(pHandle);
}
AUKN_SYM ICertificateChain *NewChainFromManyDerNew(const AuList<AuMemoryViewRead> &read)
{
auto pCertificateChain = _new CertificateChain();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init(read))
{
return {};
}
return pCertificateChain;
}
AUKN_SYM void NewChainFromManyDerRelease(ICertificateChain *pHandle)
{
AuSafeDelete<CertificateChain *>(pHandle);
}
AUKN_SYM ICertificateChain *NewChainFromOnePemNew(const AuROString &read)
{
auto pCertificateChain = _new CertificateChain();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init(read))
{
NewChainFromOnePemRelease(pCertificateChain);
return {};
}
return pCertificateChain;
}
AUKN_SYM void NewChainFromOnePemRelease(ICertificateChain *pHandle)
{
AuSafeDelete<CertificateChain *>(pHandle);
}
AUKN_SYM ICertificateChain *NewChainFromManyPemNew(const AuList<AuROString> &read)
{
auto pCertificateChain = _new CertificateChain();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init(read))
{
NewChainFromManyPemRelease(pCertificateChain);
return {};
}
return pCertificateChain;
}
AUKN_SYM void NewChainFromManyPemRelease(ICertificateChain *pHandle)
{
AuSafeDelete<CertificateChain *>(pHandle);
}
AUKN_SYM ICertificateChain *NewChainFromManyPemInStreamNew(const AuROString &read)
{
auto pCertificateChain = _new CertificateChain();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init2(read))
{
NewChainFromManyPemInStreamRelease(pCertificateChain);
return {};
}
return pCertificateChain;
}
AUKN_SYM void NewChainFromManyPemInStreamRelease(ICertificateChain *pHandle)
{
AuSafeDelete<CertificateChain *>(pHandle);
}
AUKN_SYM ICertificateChain *NewChainFromManyDerInStreamNew(const AuMemoryViewRead &read)
{
auto pCertificateChain = _new CertificateChain();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init2(read))
{
NewChainFromManyDerInStreamRelease(pCertificateChain);
return {};
}
return pCertificateChain;
}
AUKN_SYM void NewChainFromManyDerInStreamRelease(ICertificateChain *pHandle)
{
AuSafeDelete<CertificateChain *>(pHandle);
}
}