[+] ICertificateStore::RemoveCertificate

[+] ICertificateStore::RemoveCertificatesFromChain
[+] ICertificateStore::Size
This commit is contained in:
Reece Wilson 2024-11-18 22:30:31 +00:00
parent e63903d0f4
commit 5abfb0eee0
3 changed files with 161 additions and 8 deletions

View File

@ -16,10 +16,15 @@ namespace Aurora::Crypto::CA
{
struct ICertificateStore : IPinCertificate
{
virtual void Serialize(Memory::ByteBuffer &buffer) = 0;
virtual bool Deserialize(Memory::ByteBuffer &buffer) = 0;
virtual bool AddCertificate(const AuMemoryViewRead &x509Certificate) = 0;
virtual bool AddCertificateChain(X509::ICertificateChain *pChain) = 0;
virtual void Serialize(Memory::ByteBuffer &buffer) = 0;
virtual bool Deserialize(Memory::ByteBuffer &buffer) = 0;
virtual bool RemoveCertificate(const AuMemoryViewRead &x509Certificate) = 0;
virtual AuUInt32 RemoveCertificatesFromChain(X509::ICertificateChain *pChain) = 0;
virtual AuUInt32 Size() = 0;
};
}

View File

@ -18,9 +18,37 @@ namespace Aurora::Crypto::X509
namespace Aurora::Crypto::CA
{
// ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
// Digicerts "high assurance" and other special roots trusted by payment insitutions use 2048... FUCKING WHY?
// These certs should be expiring in early 2030. Hopefully PayPal, Stripe, and others will get their act
// together soon. Oh, and guess what, Amazon and tons of AWS customers use Amazon Root CA 1 with a 2048-bit PK as well.
// ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
//
// ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
// Please also note that this profile is only used to verify certificate *chains*
//
// When chain[0].publicKey is trusted by your client, and you've performed a key exchanged based upon that keypair, we don't care.
// Certificate parameter validation is your issue - the clients' implementation side with your expected profile parameters and state container
// of the peers connection and hostname,common-name pair. Such validation is not an issue for this relatively stateless * certificate store *.
//
// However, when *we* recurse a *chain*, we need to verify that the previous certificate the signator to the next, at this point it is our
// responsibility to ensure some unsound certificates weren't injected into the middle of the chain to violate the "is trusted by a known root
// via a series of unknown middle-man certificates" test. Noting we dont care for testing CN and SANs; we only care about testing the PK infra
// which just to happens to include a signature test of the serialized ASN.1 properties from the anonymous root down to the chain[0] common name.
// These certificate chains, we have to assume they're arbitrary remote user data, and therefore could be severely malformed or manipulated.
// Any provided TLS stack will verify the chain[0] common name and profile parameters of the peer, however as the root-store validator, we need
// to vertify cert[1...n] eventually references a good known anon root authority without a breakage the chains of signatures.
//
// PS: Emphasis on anonymous. I've seen some certificate roots, *ahem google*, change their x509 container without changing their key.
// If we're hard-coding a series of CAs to trust, or even storing long term keychains, we're saying "we trust the owner of this key" to not
// be a dipshit, therefore we shouldn't need to worry about every minute detail of the CA - we only care about: 1) the binary public key,
// and 2) expiration time. It is therefore the case we only serialized these two properties. Do we really care that somebody we trust changed
// their their expiration time by an hour after reserializing their root cert? No, not really. Do we care that they added some SANs? Again,
// no. What about extended key uses? What are those? The extension RFC specifies use cases we couldn't care less about.
// Any certificate revocation or further tests must come from another validator, perhaps connected to us via a "PinCheckTwoAnd" object.
//
// kAssumeRootIsSmart is used to satisfy this relationship test.
// ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
static const mbedtls_x509_crt_profile kAssumeRootIsSmart =
{
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | // TODO(by 2030): delete me
@ -42,17 +70,37 @@ namespace Aurora::Crypto::CA
2048, // TODO(by 2030): Raise to 4k
};
bool CertificateStore::CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
bool CertificateStore::CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain2,
const AuMemoryViewRead &derCertificate)
{
AU_LOCK_GUARD(this->rwLock->AsReadable());
AuUPtr<X509::ICertificateChain> pTempChain;
X509::ICertificateChain *pChain;
bool bFoundTrustedCA {};
if (!pChain)
AU_LOCK_GUARD(this->rwLock->AsReadable());
if (!pChain2)
{
if (derCertificate)
{
pTempChain = X509::NewChainFromOneDerGenericUnique(derCertificate);
if (!pTempChain)
{
return false;
}
pChain = pTempChain.get();
}
else
{
return false;
}
}
else
{
pChain = pChain2.get();
}
auto uCount = pChain->GetCertificateCount();
for (AU_ITERATE_N(i, uCount))
{
@ -199,8 +247,104 @@ namespace Aurora::Crypto::CA
return true;
}
bool CertificateStore::RemoveCertificate(const AuMemoryViewRead &x509Certificate)
{
bool bRet {};
mbedtls_x509_crt crt;
if (!x509Certificate)
{
SysPushErrorArg();
return false;
}
mbedtls_x509_crt_init(&crt);
if (mbedtls_x509_crt_parse(&crt,
x509Certificate.Begin<unsigned char>(),
x509Certificate.Size()) < 0)
{
SysPushErrorGeneric();
return false;
}
AuUInt32 uCode { AuFnv1a32Runtime(crt.pk_raw.p, crt.pk_raw.len) };
{
AU_LOCK_GUARD(this->rwLock->AsWritable());
auto itr = this->storage.find(uCode);
if (itr != this->storage.end())
{
if (AuTryRemoveByTupleN<0>(itr->second, AuMemoryViewRead { crt.pk_raw.p, crt.pk_raw.len }))
{
bRet = true;
}
}
}
mbedtls_x509_crt_free(&crt);
return bRet;
}
AuUInt32 CertificateStore::RemoveCertificatesFromChain(X509::ICertificateChain *pChain)
{
AuUInt32 uRet {};
if (!pChain)
{
SysPushErrorArg();
return uRet;
}
AU_LOCK_GUARD(this->rwLock->AsWritable());
auto uCount = pChain->GetCertificateCount();
for (AU_ITERATE_N(i, uCount))
{
auto pCert = AuStaticCast<AuCrypto::X509::CertificateChain>(pChain)->GetCertificateInternal(i);
if (!pCert)
{
continue;
}
AuUInt32 uCode { AuFnv1a32Runtime(pCert->pk_raw.p, pCert->pk_raw.len) };
auto itr = this->storage.find(uCode);
if (itr == this->storage.end())
{
continue;
}
if (!AuTryRemoveByTupleN<0>(itr->second, AuMemoryViewRead { pCert->pk_raw.p, pCert->pk_raw.len }))
{
continue;
}
uRet++;
}
return uRet;
}
AuUInt32 CertificateStore::Size()
{
AuUInt32 uRet {};
AU_LOCK_GUARD(this->rwLock->AsReadable());
for (auto &[uID, storageList] : this->storage)
{
uRet += storageList.size();
}
return uRet;
}
void CertificateStore::Serialize(Memory::ByteBuffer &buffer)
{
AU_LOCK_GUARD(this->rwLock->AsReadable());
for (auto &[uID, storageList] : this->storage)
{
for (auto &[cert, uValidTo] : storageList)

View File

@ -17,6 +17,10 @@ namespace Aurora::Crypto::CA
bool AddCertificate(const AuMemoryViewRead &x509Certificate) override;
bool AddCertificateChain(X509::ICertificateChain *pChain) override;
bool RemoveCertificate(const AuMemoryViewRead &x509Certificate) override;
AuUInt32 RemoveCertificatesFromChain(X509::ICertificateChain *pChain) override;
AuUInt32 Size() override;
void Serialize(Memory::ByteBuffer &buffer) override;
bool Deserialize(Memory::ByteBuffer &buffer) override;