476 lines
12 KiB
C++
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);
|
||
|
}
|
||
|
}
|