/*** 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 #include "AuCertificateChain.hpp" #include 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 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 &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 &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(pHandle); } AUKN_SYM ICertificateChain *NewChainFromManyDerNew(const AuList &read) { auto pCertificateChain = _new CertificateChain(); if (!pCertificateChain) { SysPushErrorMemory(); return {}; } if (!pCertificateChain->Init(read)) { return {}; } return pCertificateChain; } AUKN_SYM void NewChainFromManyDerRelease(ICertificateChain *pHandle) { AuSafeDelete(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(pHandle); } AUKN_SYM ICertificateChain *NewChainFromManyPemNew(const AuList &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(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(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(pHandle); } }