[+] 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
This commit is contained in:
Reece Wilson 2024-10-16 02:05:11 +01:00
parent b5c4271807
commit 7a0593adeb
61 changed files with 4338 additions and 724 deletions

View File

@ -1,5 +1,5 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
Copyright (C) 2021-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CA.hpp
Date: 2021-6-11
@ -7,30 +7,12 @@
***/
#pragma once
namespace Aurora::Crypto::RSA
{
struct IRSAPublic;
}
#include "IPinCertificate.hpp"
#include "ICertificateStore.hpp"
#include "PinCertificate.hpp"
#include "CertificateStore.hpp"
namespace Aurora::Crypto::CA
{
class ICertificateStore
{
public:
virtual void AddSignature(const AuSPtr<RSA::IRSAPublic> &CA,
const Memory::ByteBuffer &sig,
Aurora::Hashing::EHashType method,
EPaddingType type) = 0;
virtual void AddPublicCert(const X509::Certificate &cert) = 0;
/// For future support of http gets of the CA list
virtual bool& AllowHTTPTree() = 0;
virtual bool CheckKey(const AuSPtr<RSA::IRSAPublic> &pub) = 0;
virtual bool CheckCert(const X509::Certificate &cert) = 0;
};
AUKN_SHARED_API(NewCA, ICertificateStore);
}

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CertificateStore.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
AUKN_SHARED_API(NewCertificateStore, ICertificateStore)
}

View File

@ -0,0 +1,25 @@
/***
Copyright (C) 2021-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ICertificateStore.hpp
Date: 2021-6-11
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
struct ICertificateChain;
}
namespace Aurora::Crypto::CA
{
struct ICertificateStore : IPinCertificate
{
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;
};
}

View File

@ -7,12 +7,15 @@
***/
#pragma once
namespace Aurora::IO::TLS
namespace Aurora::Crypto::X509
{
struct NetError;
struct ICertificateChain;
}
namespace Aurora::Crypto::CA
{
AUKN_INTERFACE(IPinCertificate,
AUI_METHOD(bool, CheckCertificate, (const AuSPtr<ICertificateChain> &, pChain,
const Memory::MemoryViewRead &, derCertificate))
AUI_METHOD(bool, CheckCertificate, (const AuSPtr<X509::ICertificateChain> &, pChain,
const AuMemoryViewRead &, derCertificate))
);
}

View File

@ -0,0 +1,48 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: PinCertificate.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
/*
* Dummy pinner
*/
AUKN_SHARED_API(PinAlwaysFail, IPinCertificate)
/*
* Dummy pinner
*/
AUKN_SHARED_API(PinAlwaysPass, IPinCertificate)
/*
* Provides an instance of the platforms certificate validation framework
*/
AUKN_SHARED_API(PinCheckOS, IPinCertificate)
/*
* Provides an instance of the (limited) builtin certificate authority store
*/
AUKN_SHARED_API(PinCheckBuiltin, IPinCertificate)
/*
* Per application configuration, provides an instance of the default TLS certificate validator
*/
AUKN_SHARED_API(PinCheckDefault, IPinCertificate)
/**
* See: SetGlobalTLSPinner
*/
AUKN_SHARED_API(PinCheckGlobal, IPinCertificate)
AUKN_SHARED_API(PinCheckBasicValidity, IPinCertificate)
AUKN_SHARED_API(PinCheckTwoAnd, IPinCertificate, const AuSPtr<IPinCertificate> &pCheckA, const AuSPtr<IPinCertificate> &pCheckB)
AUKN_SHARED_API(PinCheckTwoOr, IPinCertificate, const AuSPtr<IPinCertificate> &pCheckA, const AuSPtr<IPinCertificate> &pCheckB)
AUKN_SYM void SetGlobalTLSPinner(const AuSPtr<IPinCertificate> &pNewDefault);
}

View File

@ -40,6 +40,7 @@ namespace Aurora::Crypto
#include "ECC/ECC.hpp"
#include "PEM/PEM.hpp"
#include "RSA/RSA.hpp"
#include "KeyPair/KeyPair.hpp"
#include "X509/X509.hpp"
#include "BCrypt/BCrypt.hpp"
#include "HMAC/HMAC.hpp"

View File

@ -1,27 +0,0 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: EHashType.hpp
Date: 2021-6-11
Author: Reece
***/
#pragma once
namespace Aurora::Crypto
{
#if 0
AUE_DEFINE(EHashType,
(
eMD5,
eSHA1_20_160,
eTiger_24_192,
eSHA2_32_256,
eSHA2_48_384,
eSHA2_64_512,
eSHA3_28_224,
eSHA3_32_256,
eSHA3_48_384,
eSHA3_64_512
));
#endif
}

View File

@ -0,0 +1,22 @@
/***
Copyright (C) 2022 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPrivateKeyPair.hpp
File: ITLSPrivateKeyPair.hpp
Date: 2022-8-27
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
struct ICertificateChain;
}
namespace Aurora::Crypto::KeyPair
{
struct IPrivateKeyPair
{
virtual AuSPtr<X509::ICertificateChain> GetChain() = 0;
};
}

View File

@ -0,0 +1,15 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPrivateKeyProvider.hpp
Date: 2024-10-13
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::KeyPair
{
AUKN_INTERFACE(IPrivateKeyProvider,
AUI_METHOD(AuSPtr<IPrivateKeyPair>, FetchBySNI, (const AuROString &, SNI))
);
}

View File

@ -0,0 +1,17 @@
/***
Copyright (C) 2022-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: KeyPair.hpp
Date: 2024-10-13
Author: Reece
***/
#pragma once
#include "PrivateKeyPair.hpp"
#include "IPrivateKeyPair.hpp"
#include "IPrivateKeyProvider.hpp"
namespace Aurora::Crypto::KeyPair
{
AUKN_SHARED_API(ImportPrivateKeyPair, IPrivateKeyPair, const PrivateKeyPair &keyPair);
}

View File

@ -0,0 +1,24 @@
/***
Copyright (C) 2022 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: PrivateKeyPair.hpp
File: TLSPrivateKeyPair.hpp
Date: 2022-8-26
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
struct ICertificateChain;
}
namespace Aurora::Crypto::KeyPair
{
struct PrivateKeyPair
{
AuSPtr<X509::ICertificateChain> pCertificateChain;
AuMemoryViewRead privateKey;
AuString sPassword;
};
}

View File

@ -0,0 +1,19 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CertificateChain.hpp
Date: 2024-10-13
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
AUKN_SHARED_API(NewChainFromOneDer, ICertificateChain, const AuMemoryViewRead &read);
AUKN_SHARED_API(NewChainFromManyDer, ICertificateChain, const AuList<AuMemoryViewRead> &read);
AUKN_SHARED_API(NewChainFromManyDerInStream, ICertificateChain, const AuMemoryViewRead &read);
AUKN_SHARED_API(NewChainFromOnePem, ICertificateChain, const AuROString &read);
AUKN_SHARED_API(NewChainFromManyPem, ICertificateChain, const AuList<AuROString> &read);
AUKN_SHARED_API(NewChainFromManyPemInStream, ICertificateChain, const AuROString &read);
}

View File

@ -0,0 +1,50 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CertificateDecoded.hpp
Date: 2021-6-11
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
struct CertificateDecoded
{
AU_COPY_MOVE_DEF(CertificateDecoded);
int version {};
int iMaxPath {};
bool bIsCA {};
Hashing::EHashType digest;
struct Issuer : CertificateName
{
AU_COPY_MOVE_DEF(Issuer);
Memory::ByteBuffer id;
} issuer;
struct Subject : CertificateName
{
AU_COPY_MOVE_DEF(Subject);
Memory::ByteBuffer id;
} subject;
struct Vaildity
{
AU_COPY_MOVE_DEF(Vaildity);
AuUInt issued;
AuUInt expire;
} validity;
AuList<EExtendedUsage> usage;
Memory::ByteBuffer publicKey;
Memory::ByteBuffer serialNumber;
Memory::ByteBuffer algorithmOid;
AuList<AuString> AIAs;
AuList<AuString> OCSPs;
// TODO: AuString CRL;
// TODO: AuList<String> subjectNames;
// TODO: ...
};
}

View File

@ -0,0 +1,29 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CertificateName.hpp
Date: 2021-6-11
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
struct CertificateName
{
AU_COPY_MOVE_DEF(CertificateName);
AuString commonName;
AuString department;
AuString organization;
AuString address;
AuString locality;
AuString state;
AuString countryCode;
AuString postcode;
AuString name;
AuString email;
AuString title;
};
}

View File

@ -0,0 +1,49 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CertificateRequest.hpp
File: GenerateCertificate.hpp
Date: 2022-11-18
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::KeyPair
{
struct IPrivateKeyPair;
}
namespace Aurora::Crypto::X509
{
struct CertificateRequest
{
// subject --
CertificateName name;
// metadata --
Hashing::EHashType digest;
AuUInt8 uVersion { 3 };
bool bIsCA { };
AuInt8 iMaxPathLength { -1 };
bool bSubjectKeyId { };
AuList<EExtendedUsage> usage;
AuUInt8 uSerialRadix { 10 };
AuString sSerial { "69420" };
// validity --
AuSInt iIssuedDateMs {};
AuSInt iExpirationDateMs {};
// public key ---
AuSPtr<RSA::IRSAPublic> pRSAKey;
AuSPtr<ECC::IECCPublic> pECCKey;
// private key ---
AuSPtr<RSA::IRSAPrivate> pSelfSigningRSAKey;
AuSPtr<ECC::IECCPrivate> pSelfSigningECCKey;
// or
AuSPtr<KeyPair::IPrivateKeyPair> pSigningChain;
};
}

View File

@ -7,44 +7,7 @@
***/
#pragma once
namespace Aurora::IO::TLS
{
struct ITLSPrivateKeyPair;
}
namespace Aurora::Crypto::X509
{
struct CertRequest
{
// subject --
CertName name;
// metadata --
Hashing::EHashType digest;
AuUInt8 uVersion { 3 };
bool bIsCA { };
AuInt8 iMaxPathLength { -1 };
bool bSubjectKeyId { };
AuList<EExtendedUsage> usage;
AuUInt8 uSerialRadix { 10 };
AuString sSerial { "69420" };
// validity --
AuSInt iIssuedDateMs {};
AuSInt iExpirationDateMs {};
// public key ---
AuSPtr<RSA::IRSAPublic> pRSAKey;
AuSPtr<ECC::IECCPublic> pECCKey;
// private key ---
AuSPtr<RSA::IRSAPrivate> pSelfSigningRSAKey;
AuSPtr<ECC::IECCPrivate> pSelfSigningECCKey;
// or
AuSPtr<Aurora::IO::TLS::ITLSPrivateKeyPair> pSigningChain;
};
AUKN_SYM AuResult<Memory::ByteBuffer> GenerateCertificate(const CertRequest &request);
AUKN_SYM AuResult<Memory::ByteBuffer> GenerateCertificate(const CertificateRequest &request);
}

View File

@ -0,0 +1,18 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ICertifiateChain.hpp
Date: 2022-8-30
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
struct ICertificateChain
{
virtual AuUInt32 GetCertificateCount() = 0;
virtual AuMemoryViewRead GetCertificate(AuUInt32 idx) = 0;
virtual AuOptional<const CertificateDecoded &> GetCertificateDetails(AuUInt32 idx) = 0;
};
}

View File

@ -9,70 +9,17 @@
#include "EExtendedUsage.hpp"
#include "CertificateName.hpp"
#include "CertificateDecoded.hpp"
#include "ICertificateChain.hpp"
#include "CertificateChain.hpp"
#include "CertificateRequest.hpp"
#include "GenerateCertificate.hpp"
namespace Aurora::Crypto::X509
{
struct CertName
{
AU_COPY_MOVE_DEF(CertName);
AuString commonName;
AuString department;
AuString organization;
AuString address;
AuString locality;
AuString state;
AuString countryCode;
AuString postcode;
AuString name;
AuString email;
AuString title;
};
struct DecodedCertificate
{
AU_COPY_MOVE_DEF(DecodedCertificate);
int version {};
struct Issuer : CertName
{
AU_COPY_MOVE_DEF(Issuer);
Memory::ByteBuffer id;
} issuer;
struct Subject : CertName
{
AU_COPY_MOVE_DEF(Subject);
Memory::ByteBuffer id;
} subject;
struct Vaildity
{
AU_COPY_MOVE_DEF(Vaildity);
AuUInt issued;
AuUInt expire;
} validity;
AuList<AuUInt8> serialNumber;
AuList<AuUInt8> algorithmOid;
AuList<AuString> AIAs;
// TODO: AuString CRL;
// TODO: AuList<String> subjectNames;
Hashing::EHashType digest;
AuList<EExtendedUsage> usage;
int iMaxPath {};
bool bIsCA {};
// TODO: ...
};
AUKN_SYM bool Decode(const Certificate &der, DecodedCertificate &out);
AUKN_SYM bool Validate(const Certificate &der, const Certificate &parentDer);
AUKN_SYM bool Decode(const AuMemoryViewRead &der, CertificateDecoded &out);
AUKN_SYM bool Validate(const AuMemoryViewRead &der, const AuMemoryViewRead &parentDer);
}
#include "GenerateCertificate.hpp"

View File

@ -1,21 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ICertifiateChain.hpp
Date: 2022-8-30
Author: Reece
***/
#pragma once
namespace Aurora::IO::TLS
{
struct ICertificateChain
{
virtual AuUInt32 GetCertificateCount() = 0;
virtual AuSPtr<Memory::MemoryViewRead> GetCertificate(AuUInt32 idx) = 0;
virtual Crypto::X509::DecodedCertificate GetCertificateDetails(AuUInt32 idx) = 0;
};
AUKN_SYM AuSPtr<ICertificateChain> ChainFromOne(const Memory::MemoryViewRead &read);
AUKN_SYM AuSPtr<ICertificateChain> ChainFromMany(const AuList<Memory::MemoryViewRead> &read);
}

View File

@ -83,6 +83,20 @@ namespace Aurora::IO::TLS
*/
bool bTicketsRotate { false };
/**
* @brief Allows the serving of default keypairs via requests of unknown SNIs.
* Not recommended.
*/
bool bAllowSNIToFallBackDefault { false };
/**
* @brief Allows the serving of default keypairs via SNI-less connections.
* Use me if you care about hiding from service scanners.
* SNI glows for end-users, but, lets say you dont want this server to scream "im publicinfra.servicetype.aws.companyname.com", this could be useful.
* Might be required for legacy clients or privacy configs.
*/
bool bAllowSNILessUseDefaultCert { true };
/**
* @brief
*/
@ -114,6 +128,11 @@ namespace Aurora::IO::TLS
*/
bool bIsClient { true };
/**
* @brief
*/
bool bEnableDebug { false };
/**
* @brief
*/
@ -122,12 +141,17 @@ namespace Aurora::IO::TLS
/**
* @brief
*/
AuSPtr<IPinCertificate> pCertPin;
AuSPtr<Crypto::CA::IPinCertificate> pCertPin;
/**
*
*/
AuSPtr<Crypto::KeyPair::IPrivateKeyProvider> pKeyPairProvider;
/**
* @brief
*/
AuSPtr<ITLSPrivateKeyPair> pKeyPair;
AuSPtr<Crypto::KeyPair::IPrivateKeyPair> pDefaultKeyPair;
/**
* @brief Override the cipersuites defined by ::GetDefaultCipherSuites()

View File

@ -1,18 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ITLSPrivateKeyPair.hpp
Date: 2022-8-27
Author: Reece
***/
#pragma once
namespace Aurora::IO::TLS
{
struct ITLSPrivateKeyPair
{
virtual AuSPtr<ICertificateChain> GetChain() = 0;
};
AUKN_SYM AuSPtr<ITLSPrivateKeyPair> ImportPrivateKeyPair(const TLSPrivateKeyPair &keyPair);
}

View File

@ -8,10 +8,6 @@
#pragma once
#include "../Protocol/Protocol.hpp"
#include "ICertificateChain.hpp"
#include "IPinCertificate.hpp"
#include "TLSPrivateKeyPair.hpp"
#include "ITLSPrivateKeyPair.hpp"
#include "ITLSContext.hpp"
#include "TLSCipherSuites.hpp"

View File

@ -1,18 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: TLSPrivateKeyPair.hpp
Date: 2022-8-26
Author: Reece
***/
#pragma once
namespace Aurora::IO::TLS
{
struct TLSPrivateKeyPair
{
AuList<Memory::ByteBuffer> certificateChain;
Memory::ByteBuffer privateKey;
AuString sPassword;
};
}

View File

@ -99,14 +99,8 @@ namespace Aurora
struct CryptoConfig
{
/// Defer to the rationales in the implementation
/// Update 2023: world war 3 hasnt happened yet
bool allowChineseCerts {false};
/// Defer to the rationales in the implementation
/// Update 2023: spoilers it had nothing to do with the 2022 russian trolling directly, but who didn't see it coming?
/// i dont care about politics; its just useful to divide the glow by factions.
bool allowRussianCerts {true};
bool bPreferSystemCertStoreOverBuiltin { false };
bool bReserved[31];
};
struct AsyncConfig

View File

@ -43,8 +43,10 @@
#include <mimalloc.h>
#include "Process/AuProcessStartTime.hpp"
#include "AuProcAddresses.hpp"
#include "Crypto/CA/CA.hpp"
#if defined(AURORA_IS_LINUX_DERIVED)
#include "Crypto/CA/AuPinOS.Linux.hpp"
void LinuxSuperSecretIOTick();
#endif
@ -75,6 +77,10 @@ static void Init()
Crypto::InitCrypto();
Aurora::IO::TLS::TLSInit();
Aurora::Crypto::CA::InitDefaultBuiltinCA();
#if defined(AURORA_IS_LINUX_DERIVED)
Aurora::Crypto::CA::InitLinuxPinner();
#endif
AuProcess::WarmStartupCaches();
@ -175,6 +181,11 @@ static void RuntimeLateClean()
Aurora::IO::FS::DeinitResources();
Aurora::CmdLine::Deinit();
Aurora::Crypto::CA::DeinitDefaultBuiltinCA();
#if defined(AURORA_IS_LINUX_DERIVED)
Aurora::Crypto::CA::DeinitLinuxPinner();
#endif
Aurora::RNG::Release(); // RNG and crypto should remain alive whilst IO work is ongoing.
// At this point, we should assume libtomcrypt and mbedtls wont be called
// The default gFastDevice shouldn't be hit for any reason

30
Source/Crypto/CA/AuCA.cpp Normal file
View File

@ -0,0 +1,30 @@
/***
Copyright (C) 2021-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuCA.cpp
Date: 2024-10-14
Author: Reece
Date: 2021-6-12
***/
#include <Source/RuntimeInternal.hpp>
namespace Aurora::Crypto::CA
{
AUKN_SYM IPinCertificate *PinCheckDefaultNew()
{
if (gRuntimeConfig.crypto.bPreferSystemCertStoreOverBuiltin)
{
if (auto pOS = PinCheckOSNew())
{
return pOS;
}
}
return PinCheckBuiltinNew();
}
AUKN_SYM void PinCheckDefaultRelease(IPinCertificate *pHandle)
{
}
}

View File

@ -1,7 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CA.cpp
File: AuCA.hpp
Date: 2021-6-12
Author: Reece
***/

View File

@ -0,0 +1,260 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuCertificateStore.cpp
Date: 2024-10-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuCertificateStore.hpp"
#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <Source/Crypto/X509/AuCertificateChain.hpp>
namespace Aurora::Crypto::X509
{
AuInt64 ConvertTime(const mbedtls_x509_time &time);
}
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.
static const mbedtls_x509_crt_profile kAssumeRootIsSmart =
{
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | // TODO(by 2030): delete me
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
0xFFFFFFF, /* Any PK alg */
#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) |
0,
#else
0,
#endif
2048, // TODO(by 2030): Raise to 4k
};
bool CertificateStore::CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate)
{
AU_LOCK_GUARD(this->rwLock->AsReadable());
bool bFoundTrustedCA {};
if (!pChain)
{
return false;
}
auto uCount = pChain->GetCertificateCount();
for (AU_ITERATE_N(i, uCount))
{
auto pCurrentCert = AuStaticCast<AuCrypto::X509::CertificateChain>(pChain)->GetCertificateInternal(i);
if (!pCurrentCert)
{
return false;
}
if (i)
{
auto pPrevCert = AuStaticCast<AuCrypto::X509::CertificateChain>(pChain)->GetCertificateInternal(i - 1);
if (!pPrevCert)
{
return false;
}
uint32_t flags {};
if (mbedtls_x509_crt_verify_restartable(pCurrentCert, pPrevCert, NULL, &kAssumeRootIsSmart, NULL, &flags, NULL, NULL, NULL) < 0)
{
SysPushErrorCrypto("Bad certificate chain");
return false;
}
if (flags != 0)
{
SysPushErrorCrypto("Bad certificate chain");
return false;
}
}
auto uCode = AuFnv1a32Runtime(pCurrentCert->pk_raw.p, pCurrentCert->pk_raw.len);
auto uItrA = this->storage.find(uCode);
if (uItrA == this->storage.end())
{
continue;
}
for (const auto &[that, iDate] : uItrA->second)
{
AuMemoryViewRead toCompare { that };
AuMemoryViewRead currentCert { pCurrentCert->pk_raw.p, pCurrentCert->pk_raw.len };
if (toCompare.uLength != currentCert.uLength)
{
continue;
}
if (AuTime::CurrentClockMS() > iDate)
{
SysPushErrorCrypto("Expired Certificate Authority");
continue;
}
if (AuMemcmp(toCompare.Begin(),
currentCert.Begin(),
currentCert.uLength) == 0)
{
bFoundTrustedCA = true;
break;
}
}
if (bFoundTrustedCA)
{
break;
}
}
return bFoundTrustedCA;
}
bool CertificateStore::AddCertificate(const AuMemoryViewRead &x509Certificate)
{
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) };
AuByteBuffer buffer { AuMemoryViewRead { crt.pk_raw.p, crt.pk_raw.len } };
if (!buffer)
{
SysPushErrorMemory();
mbedtls_x509_crt_free(&crt);
return false;
}
AU_LOCK_GUARD(this->rwLock->AsWritable());
this->storage[uCode].push_back(AuMakePair(AuMove(buffer), X509::ConvertTime(crt.valid_to)));
}
mbedtls_x509_crt_free(&crt);
return true;
}
bool CertificateStore::AddCertificateChain(X509::ICertificateChain *pChain)
{
if (!pChain)
{
SysPushErrorArg();
return false;
}
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)
{
SysPushErrorMemory();
return false;
}
AuUInt32 uCode { AuFnv1a32Runtime(pCert->pk_raw.p, pCert->pk_raw.len) };
AuByteBuffer buffer { AuMemoryViewRead { pCert->pk_raw.p, pCert->pk_raw.len } };
if (!buffer)
{
SysPushErrorMemory();
return false;
}
this->storage[uCode].push_back(AuMakePair(AuMove(buffer), X509::ConvertTime(pCert->valid_to)));
}
return true;
}
void CertificateStore::Serialize(Memory::ByteBuffer &buffer)
{
for (auto &[uID, storageList] : this->storage)
{
for (auto &[cert, uValidTo] : storageList)
{
buffer.Write<AuUInt32>(cert.size());
buffer.Write<AuInt64>(uValidTo);
buffer.Write(AuMemoryViewRead { cert });
}
}
}
bool CertificateStore::Deserialize(Memory::ByteBuffer &buffer)
{
AU_LOCK_GUARD(this->rwLock->AsWritable());
while (buffer.RemainingBytes())
{
auto uLength = buffer.Read<AuUInt32>();
if (!uLength)
{
return false;
}
auto iValidTo = buffer.Read<AuInt64>();
auto view = buffer.GetLinearReadableForExactly(uLength);
if (!view)
{
return false;
}
buffer.readPtr += uLength;
AuUInt32 uCode { AuFnv1a32Runtime(view.Begin(), view.Size()) };
AuByteBuffer buffer { view };
if (!buffer)
{
SysPushErrorMemory();
return false;
}
this->storage[uCode].push_back(AuMakePair(AuMove(buffer), iValidTo));
}
return true;
}
AUKN_SYM ICertificateStore *NewCertificateStoreNew()
{
return _new CertificateStore();
}
AUKN_SYM void NewCertificateStoreRelease(ICertificateStore *pHandle)
{
AuSafeDelete<CertificateStore *>(pHandle);
}
}

View File

@ -0,0 +1,27 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AauCertificateStore.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
struct CertificateStore : ICertificateStore
{
bool CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate) override;
bool AddCertificate(const AuMemoryViewRead &x509Certificate) override;
bool AddCertificateChain(X509::ICertificateChain *pChain) override;
void Serialize(Memory::ByteBuffer &buffer) override;
bool Deserialize(Memory::ByteBuffer &buffer) override;
AuHashMap<AuUInt32, AuList<AuPair<AuMemory::ByteBuffer, AuInt64>>> storage;
AuRWLock rwLock;
};
}

2281
Source/Crypto/CA/AuPinBuiltin.cpp Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinBuiltin.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
}

34
Source/Crypto/CA/AuPinDummy.cpp Executable file
View File

@ -0,0 +1,34 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinDummy.cpp
Date: 2024-10-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuPinDummy.hpp"
namespace Aurora::Crypto::CA
{
AUKN_SYM IPinCertificate *PinAlwaysPassNew()
{
static DummyPinner<true> gInstance;
return &gInstance;
}
AUKN_SYM void PinAlwaysPassRelease(IPinCertificate *pHandle)
{
// Singleton NOP
}
AUKN_SYM IPinCertificate *PinAlwaysFailNew()
{
static DummyPinner<false> gInstance;
return &gInstance;
}
AUKN_SYM void PinAlwaysFailRelease(IPinCertificate *pHandle)
{
// Singleton NOP
}
}

21
Source/Crypto/CA/AuPinDummy.hpp Executable file
View File

@ -0,0 +1,21 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinDummy.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
template<bool bStatus>
struct DummyPinner : IPinCertificate
{
bool CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate) override
{
return bStatus;
}
};
}

View File

@ -0,0 +1,47 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinGlobal.cpp
Date: 2024-10-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuPinGlobal.hpp"
namespace Aurora::Crypto::CA
{
static AuSPtr<IPinCertificate> gDefaultPinner;
static GlobalPinner gGlobalPinner;
static AuRWLock gRWPinnerLock;
bool GlobalPinner::CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate)
{
AU_LOCK_GUARD(gRWPinnerLock->AsReadable());
if (gDefaultPinner)
{
return gDefaultPinner->CheckCertificate(pChain, derCertificate);
}
else
{
return PinCheckDefaultNew()->CheckCertificate(pChain, derCertificate);
}
}
AUKN_SYM IPinCertificate *PinCheckGlobalNew()
{
return &gGlobalPinner;
}
AUKN_SYM void PinCheckGlobalRelease(IPinCertificate *pHandle)
{
// Singleton NOP
}
AUKN_SYM void SetGlobalTLSPinner(const AuSPtr<IPinCertificate> &pNewDefault)
{
AU_LOCK_GUARD(gRWPinnerLock->AsWritable());
gDefaultPinner = pNewDefault;
}
}

View File

@ -0,0 +1,17 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinGlobal.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
struct GlobalPinner : IPinCertificate
{
bool CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate) override;
};
}

View File

@ -0,0 +1,54 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinLinuxLike.cpp
Date: 2024-10-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuPinLinuxLike.hpp"
namespace Aurora::Crypto::CA
{
IPinCertificate *PinLinuxLikeNew()
{
auto pStore = NewCertificateStoreNew();
if (!pStore)
{
return nullptr;
}
AuString certs;
if (!AuFS::ReadString("/etc/ssl/certs/ca-bundle.crt", certs))
{
if (!AuFS::ReadString("/etc/ssl/certs/ca-certificates.crt", certs))
{
SysPushErrorIO("No SSL certificates.crt file");
NewCertificateStoreRelease(pStore);
return nullptr;
}
}
auto pChain = AuCrypto::X509::NewChainFromManyPemInStreamUnique(certs);
if (!pChain)
{
SysPushErrorSyntax("Couldn't parse system cert file!");
NewCertificateStoreRelease(pStore);
return nullptr;
}
if (!pStore->AddCertificateChain(pChain.get()))
{
SysPushErrorGeneric();
NewCertificateStoreRelease(pStore);
return nullptr;
}
return pStore;
}
void PinLinuxLikeRelease(IPinCertificate *pHandle)
{
NewCertificateStoreRelease(AuStaticCast<ICertificateStore>(pHandle));
}
}

View File

@ -0,0 +1,14 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinLinuxLike.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
IPinCertificate *PinLinuxLikeNew();
void PinLinuxLikeRelease(IPinCertificate *pHandle);
}

View File

@ -0,0 +1,35 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinOS.Linux.cpp
Date: 2024-10-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuPinOS.Linux.hpp"
#include "AuPinLinuxLike.hpp"
namespace Aurora::Crypto::CA
{
static IPinCertificate *gLinuxPinner;
AUKN_SYM IPinCertificate *PinCheckOSNew()
{
return gLinuxPinner;
}
AUKN_SYM void PinCheckOSRelease(IPinCertificate *pHandle)
{
}
void InitLinuxPinner()
{
gLinuxPinner = PinLinuxLikeNew();
}
void DeinitLinuxPinner()
{
PinLinuxLikeRelease(AuExchange(gLinuxPinner, nullptr));
}
}

View File

@ -0,0 +1,14 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinOS.Linux.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
void DeinitLinuxPinner();
void InitLinuxPinner();
}

21
Source/Crypto/CA/AuPinOS.NT.cpp Executable file
View File

@ -0,0 +1,21 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinOS.NT.cpp
Date: 2024-10-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
namespace Aurora::Crypto::CA
{
AUKN_SYM IPinCertificate *PinCheckOSNew()
{
return nullptr;
}
AUKN_SYM void PinCheckOSRelease(IPinCertificate *pHandle)
{
// Singleton NOP
}
}

13
Source/Crypto/CA/AuPinOS.NT.hpp Executable file
View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinOS.NT.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
}

68
Source/Crypto/CA/AuPinPair.cpp Executable file
View File

@ -0,0 +1,68 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinPair.cpp
Date: 2024-10-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuPinPair.hpp"
namespace Aurora::Crypto::CA
{
OpAndPinner::OpAndPinner(const AuSPtr<IPinCertificate> &pA,
const AuSPtr<IPinCertificate> &pB) :
pA(pA),
pB(pB)
{
}
bool OpAndPinner::CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate)
{
return this->pA->CheckCertificate(pChain, derCertificate) &&
this->pB->CheckCertificate(pChain, derCertificate);
}
OpOrPinner::OpOrPinner(const AuSPtr<IPinCertificate> &pA,
const AuSPtr<IPinCertificate> &pB) :
pA(pA),
pB(pB)
{
}
bool OpOrPinner::CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate)
{
return this->pA->CheckCertificate(pChain, derCertificate) ||
this->pB->CheckCertificate(pChain, derCertificate);
}
AUKN_SYM IPinCertificate *PinCheckTwoAndNew(const AuSPtr<IPinCertificate> &pCheckA,
const AuSPtr<IPinCertificate> &pCheckB)
{
SysCheckArgNotNull(pCheckA, {});
SysCheckArgNotNull(pCheckB, {});
return _new OpOrPinner(pCheckA, pCheckB);
}
AUKN_SYM void PinCheckTwoAndRelease(IPinCertificate *pHandle)
{
AuSafeDelete<OpAndPinner *>(pHandle);
}
AUKN_SYM IPinCertificate *PinCheckTwoOrNew(const AuSPtr<IPinCertificate> &pCheckA,
const AuSPtr<IPinCertificate> &pCheckB)
{
SysCheckArgNotNull(pCheckA, {});
SysCheckArgNotNull(pCheckB, {});
return _new OpOrPinner(pCheckA, pCheckB);
}
AUKN_SYM void PinCheckTwoOrRelease(IPinCertificate *pHandle)
{
AuSafeDelete<OpOrPinner *>(pHandle);
}
}

33
Source/Crypto/CA/AuPinPair.hpp Executable file
View File

@ -0,0 +1,33 @@
/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPinPair.hpp
Date: 2024-10-14
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::CA
{
struct OpAndPinner : IPinCertificate
{
AuSPtr<IPinCertificate> pA;
AuSPtr<IPinCertificate> pB;
OpAndPinner(const AuSPtr<IPinCertificate> &pA, const AuSPtr<IPinCertificate> &pB);
bool CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate) override;
};
struct OpOrPinner : IPinCertificate
{
AuSPtr<IPinCertificate> pA;
AuSPtr<IPinCertificate> pB;
OpOrPinner(const AuSPtr<IPinCertificate> &pA, const AuSPtr<IPinCertificate> &pB);
bool CheckCertificate(const AuSPtr<X509::ICertificateChain> &pChain,
const AuMemoryViewRead &derCertificate) override;
};
}

12
Source/Crypto/CA/CA.hpp Normal file → Executable file
View File

@ -1,7 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
#pragma once
File: CA.hpp
Date: 2021-6-12
Author: Reece
***/
namespace Aurora::Crypto::CA
{
void InitDefaultBuiltinCA();
void DeinitDefaultBuiltinCA();
}

View File

@ -0,0 +1,104 @@
/***
Copyright (C) 2022-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPrivateKeyPair.cpp
File: TLSPrivateKeyPair.cpp
Date: 2022-8-27
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuPrivateKeyPair.hpp"
namespace Aurora::IO::TLS
{
AuString TLSErrorToString(int iError);
}
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/timing.h> // TODO: deprecate me
namespace Aurora::IO::TLS
{
extern mbedtls_entropy_context gEntropy;
extern mbedtls_ctr_drbg_context gCtrDrbg;
}
namespace Aurora::Crypto::KeyPair
{
PrivateKeyPairImpl::PrivateKeyPairImpl(const AuSPtr<X509::ICertificateChain> &pCertificateChain) :
pCertificateChain(pCertificateChain)
{
::mbedtls_pk_init(&this->privateKey_);
}
PrivateKeyPairImpl::PrivateKeyPairImpl()
{
::mbedtls_pk_init(&this->privateKey_);
}
PrivateKeyPairImpl::~PrivateKeyPairImpl()
{
::mbedtls_pk_free(&this->privateKey_);
AuMemset(&this->privateKey_, 0xFF, sizeof(this->privateKey_));
}
AuSPtr<X509::ICertificateChain> PrivateKeyPairImpl::GetChain()
{
return this->pCertificateChain;
}
X509::CertificateChain *PrivateKeyPairImpl::ToChain()
{
if (this->pCertificateChain)
{
return AuStaticCast<X509::CertificateChain>(this->pCertificateChain.get());
}
else
{
return {};
}
}
mbedtls_pk_context &PrivateKeyPairImpl::GetInternal()
{
return this->privateKey_;
}
AUKN_SYM IPrivateKeyPair *ImportPrivateKeyPairNew(const PrivateKeyPair &keyPair)
{
int iRet {};
if (!keyPair.pCertificateChain)
{
SysPushErrorArg();
return {};
}
auto pPrivateKey = _new PrivateKeyPairImpl(keyPair.pCertificateChain);
if (!pPrivateKey)
{
SysPushErrorMemory();
return {};
}
iRet = ::mbedtls_pk_parse_key(&pPrivateKey->GetInternal(),
(const unsigned char *)keyPair.privateKey.Begin(),
keyPair.privateKey.Size(),
keyPair.sPassword.size() ? (const unsigned char *)keyPair.sPassword.c_str() : nullptr,
keyPair.sPassword.size(),
mbedtls_ctr_drbg_random,
&Aurora::IO::TLS::gCtrDrbg);
if (iRet != 0)
{
SysPushErrorCrypto("Invalid Private Key: {} ({})", Aurora::IO::TLS::TLSErrorToString(iRet), iRet);
return {};
}
return pPrivateKey;
}
AUKN_SYM void ImportPrivateKeyPairRelease(IPrivateKeyPair *pHandle)
{
AuSafeDelete<PrivateKeyPairImpl *>(pHandle);
}
}

View File

@ -0,0 +1,29 @@
/***
Copyright (C) 2022-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuPrivateKeyPair.hpp
Date: 2022-8-27
Author: Reece
***/
#pragma once
#include <Source/Crypto/X509/AuCertificateChain.hpp>
namespace Aurora::Crypto::KeyPair
{
struct PrivateKeyPairImpl : IPrivateKeyPair, AuEnableSharedFromThis<PrivateKeyPairImpl>
{
PrivateKeyPairImpl();
PrivateKeyPairImpl(const AuSPtr<X509::ICertificateChain> &pCertificateChain);
~PrivateKeyPairImpl();
virtual AuSPtr<X509::ICertificateChain> GetChain() override;
X509::CertificateChain *ToChain();
mbedtls_pk_context &GetInternal();
private:
AuSPtr<X509::ICertificateChain> pCertificateChain;
mbedtls_pk_context privateKey_;
};
}

View File

@ -0,0 +1,476 @@
/***
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);
}
}

View File

@ -0,0 +1,45 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuCertificateChain.hpp
Date: 2022-8-27
Author: Reece
***/
#pragma once
#include <mbedtls/entropy.h>
#include <mbedtls/x509.h>
#include <mbedtls/oid.h>
#include <mbedtls/x509_crt.h>
namespace Aurora::Crypto::X509
{
struct CertificateChain : ICertificateChain, AuEnableSharedFromThis<CertificateChain>
{
CertificateChain();
~CertificateChain();
virtual AuUInt32 GetCertificateCount() override;
virtual AuMemoryViewRead GetCertificate(AuUInt32 idx) override;
virtual AuOptional<const CertificateDecoded &> GetCertificateDetails(AuUInt32 idx) override;
mbedtls_x509_crt *GetCertificateInternal(AuUInt32 idx);
bool Init(const AuList<AuMemoryViewRead> &certs);
bool Init(const AuMemoryViewRead &cert);
bool Init2(const AuMemoryViewRead &cert);
bool Init(const AuList<AuROString> &certs);
bool Init(const AuROString &cert);
bool Init2(const AuROString &cert);
bool Init(const mbedtls_x509_crt *pCert);
bool Precache();
mbedtls_x509_crt *pCertificate;
mbedtls_x509_crt ownCertificate {};
AuList<Crypto::X509::CertificateDecoded> decoded;
AuMutex mutex;
AuList<AuMemoryViewRead> ownership;
AuMemoryViewRead ownership2;
};
}

View File

@ -1,7 +1,7 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
Copyright (C) 2022 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: GenerateCertificate.cpp
File: AuGenerateCertificate.cpp
Date: 2022-11-18
Author: Reece
***/
@ -9,13 +9,13 @@
#include "../Crypto.hpp"
#include "x509.hpp"
#include <Source/IO/TLS/TLS.hpp>
#include <Source/IO/TLS/TLSPrivateKeyPair.hpp>
#include <Source/Crypto/KeyPair/AuPrivateKeyPair.hpp>
#include <mbedtls/asn1write.h>
#include <mbedtls/oid.h>
namespace Aurora::Crypto::X509
{
AUKN_SYM AuResult<Memory::ByteBuffer> GenerateCertificate(const CertRequest &request)
AUKN_SYM AuResult<Memory::ByteBuffer> GenerateCertificate(const CertificateRequest &request)
{
int iRet {};
mbedtls_x509write_cert crt;
@ -64,6 +64,9 @@ namespace Aurora::Crypto::X509
{
if (request.pRSAKey)
{
AuCrypto::RSA::RSAMeta rsaKeyMetadata;
rsaKeyMetadata.encoding = AuCrypto::RSA::ERSAKeyType::eRsaKey;
rsaKeyMetadata.type = AuCrypto::EKeyType::eKeyPublic;
if (!request.pRSAKey->ToKey(RSA::ERSAKeyType::eRsaKey, bufPb))
{
SysPushErrorNested();
@ -93,7 +96,7 @@ namespace Aurora::Crypto::X509
if (request.pSigningChain)
{
ctxPv = AuStaticCast<IO::TLS::TLSPrivateKeyPairImpl>(request.pSigningChain)->GetInternal();
ctxPv = AuStaticCast<KeyPair::PrivateKeyPairImpl>(request.pSigningChain)->GetInternal();
}
else
{
@ -163,13 +166,14 @@ namespace Aurora::Crypto::X509
if (request.pSigningChain)
{
crt.private_issuer = &AuStaticCast<IO::TLS::CertificateChain>(request.pSigningChain->GetChain())->pCertificate->issuer;
crt.private_issuer = &AuStaticCast<X509::CertificateChain>(request.pSigningChain->GetChain())->pCertificate->issuer;
}
else
{
crt.private_issuer = crt.private_subject;
}
{
auto issueNorm = AuTime::ToCivilTime(request.iIssuedDateMs, AuTime::ETimezoneShift::eUTC);
auto issue = fmt::format("{:04}{:02}{:02}{:02}{:02}{:02}",

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2022 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuGenerateCertificate.hpp
Date: 2022-11-18
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
}

View File

@ -1,7 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: x509.cpp
File: Aux509.cpp
Date: 2021-6-12
Author: Reece
***/
@ -306,7 +306,7 @@ namespace Aurora::Crypto::X509
}
#pragma endregion
static void FindCommonNames(const mbedtls_x509_name &name, CertName &out)
static void FindCommonNames(const mbedtls_x509_name &name, CertificateName &out)
{
find_oid_value_in_name(&name, MBEDTLS_OID_AT_CN, out.commonName);
find_oid_value_in_name(&name, MBEDTLS_OID_AT_COUNTRY, out.countryCode);
@ -321,28 +321,41 @@ namespace Aurora::Crypto::X509
find_oid_value_in_name(&name, MBEDTLS_OID_AT_LOCALITY, out.locality);
}
static bool ParseCert(const Certificate &der, AuFunction<void(mbedtls_x509_crt &crt)> cb)
bool ParseCert(const AuMemoryViewRead &der, const AuFunction<void(mbedtls_x509_crt &crt)> &cb)
{
bool ret = false;
bool bRet {};
mbedtls_x509_crt crt {};
mbedtls_x509_crt_init(&crt);
auto status = mbedtls_x509_crt_parse(&crt,
reinterpret_cast<const unsigned char *>(der.data()),
der.size());
der.Begin<unsigned char>(),
der.Size());
if (status < 0) goto out;
cb(crt);
ret = true;
out:
mbedtls_x509_crt_free(&crt);
return ret;
if (status < 0)
{
goto out;
}
static AuInt64 ConvertTime(const mbedtls_x509_time &time)
try
{
if (cb)
{
cb(crt);
}
bRet = true;
}
catch (...)
{
SysPushErrorCatch();
}
out:
mbedtls_x509_crt_free(&crt);
return bRet;
}
AuInt64 ConvertTime(const mbedtls_x509_time &time)
{
AuTime::tm tm = {};
tm.year = time.year;
@ -354,7 +367,7 @@ namespace Aurora::Crypto::X509
return AuTime::FromCivilTime(tm, AuTime::ETimezoneShift::eUTC);
}
static void FindUsage(DecodedCertificate &out,
static void FindUsage(CertificateDecoded &out,
const mbedtls_x509_sequence *extended_key_usage)
{
const mbedtls_x509_sequence *pCur = extended_key_usage;
@ -384,7 +397,7 @@ namespace Aurora::Crypto::X509
}
}
void DecodeInternal(const mbedtls_x509_crt &crt, DecodedCertificate &out)
bool DecodeInternal(const mbedtls_x509_crt &crt, CertificateDecoded &out)
{
auto &issuer = crt.issuer;
auto &subject = crt.subject;
@ -403,24 +416,34 @@ namespace Aurora::Crypto::X509
x509_get_ca_id((mbedtls_x509_crt *)&crt, out.issuer.id);
x509_get_subject_id((mbedtls_x509_crt *)&crt, out.subject.id);
x509_get_aia((mbedtls_x509_crt *)&crt, out.OCSPs, out.AIAs);
out.serialNumber.resize(crt.serial.len);
memcpy(out.serialNumber.data(), crt.serial.p, out.serialNumber.size());
out.algorithmOid.resize(crt.sig_oid.len);
memcpy(out.algorithmOid.data(), crt.sig_oid.p, out.algorithmOid.size());
AuList<AuString> oscp;
x509_get_aia((mbedtls_x509_crt *)&crt, oscp, out.AIAs);
if (out.serialNumber.Write(crt.serial.p, crt.serial.len) != crt.serial.len)
{
return false;
}
AUKN_SYM bool Decode(const Certificate &der, DecodedCertificate &out)
if (out.algorithmOid.Write(crt.sig_oid.p, crt.sig_oid.len) != crt.sig_oid.len)
{
return false;
}
if (out.publicKey.Write(crt.pk_raw.p, crt.pk_raw.len) != crt.pk_raw.len)
{
return false;
}
return true;
}
AUKN_SYM bool Decode(const AuMemoryViewRead &der, CertificateDecoded &out)
{
bool bRet { true };
return ParseCert(der,
[&](mbedtls_x509_crt &crt)
{
DecodeInternal(crt, out);
});
bRet = DecodeInternal(crt, out);
}) && bRet;
}
static bool IsHighRiskStateIssuer(const mbedtls_x509_crt &ca)
@ -439,62 +462,15 @@ namespace Aurora::Crypto::X509
return true;
}
// Winnie the Pooh has been caught with his paws in the honey jar one too many times
// At least other nation state attacks have been covert enough for us to not know about any *TLS* MITM attacks originating from them
// Pro-china cuckolds at mozilla suggested we merely block certs issued issued by compromised cn CAs using their issue date. lol no
// https://arstechnica.com/information-technology/2015/03/google-warns-of-unauthorized-tls-certificates-trusted-by-almost-all-oses/
// https://www.zdnet.com/article/china-is-now-blocking-all-encrypted-https-traffic-using-tls-1-3-and-esni/
// https://www.popularmechanics.com/military/news/a28510/china-secret-plan-invade-taiwan/
// https://www.theguardian.com/world/2021/mar/10/china-could-invade-taiwan-in-next-six-years-top-us-admiral-warns
// https://en.wikipedia.org/wiki/Lazarus_Group (use chinese connections)
if ((!gRuntimeConfig.crypto.allowChineseCerts) &&
(stricmp(issuer.c_str(), "cn") == 0) || // mainland and countries the communists decided are theirs. often used by the dprk
(stricmp(issuer.c_str(), "mo") == 0) || // macau, china special admin region
(stricmp(issuer.c_str(), "hk") == 0) || // hong kong
/*(stricmp(issuer.c_str(), "tw") == 0)*/ false) // tehe yes we will be ready to invade by 2020. i suppose taiwan is safe enough for.now
{
SysPushErrorCrypt("The funny western yellow bear in the east is behind you");
return true;
}
// The intersection between technical threats and countries we can't do business with legally
// https://en.wikipedia.org/wiki/United_States_sanctions
// https://en.wikipedia.org/wiki/Communications_in_Iran
// https://www.gov.uk/government/collections/financial-sanctions-regime-specific-consolidated-lists-and-releases
// https://en.wikipedia.org/wiki/Lazarus_Group
// https://www.bbc.co.uk/news/stories-57520169
if ((stricmp(issuer.c_str(), "ir") == 0) || // iran - has own intranet. IXPs are owned by the state
(stricmp(issuer.c_str(), "iq") == 0) || // iraq
(stricmp(issuer.c_str(), "kp") == 0)) // north korea - has own intranet. IXPs are owned by the state
{
SysPushErrorCrypt("Service is unavailable in your country for legal and/or technical safety concerns");
return true;
}
// Russia is somewhat misunderstood and have their hands tied in a lot of cases, not to excuse blatent corruption
// Moscow wants MSK-IX IXP to be independent and have ran tests to validate their intranet could work without the rest of the world
// I wonder if Pavel Durov would trust russian certificates, probably not, right? Major states, especially Russia, shouldn't be trusted with foreign services
// allowRussianCerts is true by default; however, services targeting a market of close political enemies of russia should consider disallowing russian certs
// Further, private infrastructure around Russian territories should consider a heightened global pinning security policy
if ((!gRuntimeConfig.crypto.allowRussianCerts) &&
(stricmp(issuer.c_str(), "ru") == 0))
{
SysPushErrorCrypt("Service is unavailable in your country for technical safety concerns");
return true;
}
// The 5 eyes are smart enough to know MITM attacks would send alarms ringing at major services providers
// They are known to MITM plain text traffic and hoard vulns; however, we can design around these issues
// Do not use NIST curves, do not use plain text across public IXPs, don't save data in plain text in EU/US datacenters, etc
// There is nothing we can do about western powers. They seem to be playing... not fair... but smart
{
// obama bin listening
}
// TODO: removed <on pastebin>
// We need some kind of shim objects for IPinCertificate &
// some kind of plan on how intrastructure that has to trust public exchange points will deal with state sponsored attacks.
// this old check isnt it.
return false;
}
AUKN_SYM bool Validate(const Certificate &der, const Certificate &parentDer)
AUKN_SYM bool Validate(const AuMemoryViewRead &der, const AuMemoryViewRead &parentDer)
{
bool failed = false;
@ -511,7 +487,9 @@ namespace Aurora::Crypto::X509
return;
}
failed |= 0 > mbedtls_x509_crt_verify_restartable(&crt, &ca, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
uint32_t flags {};
failed |= 0 > mbedtls_x509_crt_verify_restartable(&crt, &ca, NULL, &mbedtls_x509_crt_profile_default, NULL, &flags, NULL, NULL, NULL);
failed |= flags != 0;
});
}) && !failed;
}

10
Source/Crypto/X509/AuX509.hpp Executable file
View File

@ -0,0 +1,10 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Aux509.hpp
Date: 2021-6-12
Author: Reece
***/
#pragma once
#include "x509.hpp"

View File

@ -1,13 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: GenerateCertificate.hpp
Date: 2022-11-18
Author: Reece
***/
#pragma once
namespace Aurora::Crypto::X509
{
}

View File

@ -12,7 +12,7 @@
namespace Aurora::Crypto::X509
{
struct DecodedCertificate;
struct CertificateDecoded;
void DecodeInternal(const mbedtls_x509_crt &crt, DecodedCertificate &out);
bool DecodeInternal(const mbedtls_x509_crt &crt, CertificateDecoded &out);
}

View File

@ -13,6 +13,7 @@
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ssl.h>
#include <mbedtls/debug.h>
#include <mbedtls/x509.h>
#include <mbedtls/error.h>
#include <mbedtls/timing.h> // TODO: deprecate me

View File

@ -1,209 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: TLSCertificateChain.cpp
Date: 2022-8-27
Author: Reece
***/
#include "TLS.hpp"
#include "TLSCertificateChain.hpp"
#include <Source/Crypto/X509/x509.hpp>
namespace Aurora::IO::TLS
{
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;
}
AuSPtr<AuMemoryViewRead> CertificateChain::GetCertificate(AuUInt32 idx)
{
AuUInt32 ret {};
auto pCert = this->pCertificate;
if (!pCert)
{
return {};
}
do
{
auto index = ret++;
if (index == idx)
{
struct View : AuMemoryViewRead
{
View(const AuMemoryViewRead &in, AuSPtr<void> pin) :
AuMemoryViewRead(in),
pin(pin)
{ }
AuSPtr<void> pin;
};
return AuMakeSharedThrow<View>(AuMemoryViewRead { pCert->raw.p, pCert->raw.len}, AuSharedFromThis());
}
}
while ((pCert = pCert->next));
return {};
}
Crypto::X509::DecodedCertificate CertificateChain::GetCertificateDetails(AuUInt32 idx)
{
AuUInt32 ret {};
auto pCert = this->pCertificate;
if (!pCert)
{
return {};
}
do
{
auto index = ret++;
if (index == idx)
{
Crypto::X509::DecodedCertificate cert;
AuCrypto::X509::DecodeInternal(*pCert, cert);
return cert;
}
}
while ((pCert = pCert->next));
return {};
}
bool CertificateChain::Init(const AuList<AuByteBuffer> &certs)
{
int iRet {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
for (const auto &cert : certs)
{
iRet = ::mbedtls_x509_crt_parse(&this->ownCertificate,
(const unsigned char *)cert.base,
cert.length);
if (iRet != 0)
{
this->pCertificate = nullptr;
SysPushErrorCrypto("Failed to parse certificate chain: {}", iRet);
return false;
}
}
return this->Precache();
}
bool CertificateChain::Init(const AuList<AuMemoryViewRead> &certs)
{
int iRet {};
this->pCertificate = &this->ownCertificate;
::mbedtls_x509_crt_init(&this->ownCertificate);
for (const auto &cert : certs)
{
iRet = ::mbedtls_x509_crt_parse(&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);
iRet = ::mbedtls_x509_crt_parse(&this->ownCertificate,
(const unsigned char *)cert.ToPointer(),
cert.length);
if (iRet != 0)
{
SysPushErrorCrypto("Failed to parse certificate chain: {}", iRet);
return false;
}
return this->Precache();
}
bool CertificateChain::Init(const mbedtls_x509_crt *pCert)
{
this->pCertificate = (mbedtls_x509_crt *)pCert;
return this->Precache();
}
bool CertificateChain::Precache()
{
return true;
}
AUKN_SYM AuSPtr<ICertificateChain> ChainFromOne(const AuMemoryViewRead &read)
{
auto pCertificateChain = AuMakeShared<CertificateChain>();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init(read))
{
return {};
}
return pCertificateChain;
}
AUKN_SYM AuSPtr<ICertificateChain> ChainFromMany(const AuList<AuMemoryViewRead> &read)
{
auto pCertificateChain = AuMakeShared<CertificateChain>();
if (!pCertificateChain)
{
SysPushErrorMemory();
return {};
}
if (!pCertificateChain->Init(read))
{
return {};
}
return pCertificateChain;
}
}

View File

@ -1,30 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: TLSCertificateChain.hpp
Date: 2022-8-27
Author: Reece
***/
#pragma once
namespace Aurora::IO::TLS
{
struct CertificateChain : ICertificateChain, AuEnableSharedFromThis<CertificateChain>
{
CertificateChain();
~CertificateChain();
virtual AuUInt32 GetCertificateCount() override;
virtual AuSPtr<AuMemoryViewRead> GetCertificate(AuUInt32 idx) override;
virtual Crypto::X509::DecodedCertificate GetCertificateDetails(AuUInt32 idx) override;
bool Init(const AuList<AuByteBuffer> &certs);
bool Init(const AuList<AuMemoryViewRead> &certs);
bool Init(const AuMemoryViewRead &cert);
bool Init(const mbedtls_x509_crt *pCert);
bool Precache();
mbedtls_x509_crt *pCertificate;
mbedtls_x509_crt ownCertificate {};
};
}

View File

@ -11,7 +11,8 @@
#include <Aurora/IO/Net/NetExperimental.hpp>
#include <Source/IO/Net/AuNetSocket.hpp>
#include <Source/Crypto/X509/x509.hpp>
#include "TLSCertificateChain.hpp"
#include <Source/Crypto/X509/AuCertificateChain.hpp>
#include <Source/Crypto/KeyPair/AuPrivateKeyPair.hpp>
namespace Aurora::IO::TLS
{
@ -22,7 +23,7 @@ namespace Aurora::IO::TLS
AuString TLSErrorToString(int iError)
{
char description[1024];
char description[1024] { 0 };
::mbedtls_strerror(iError, description, AuArraySize(description));
return description;
}
@ -84,6 +85,7 @@ namespace Aurora::IO::TLS
TLSContext::~TLSContext()
{
this->Destroy();
AuMemset(&this->ssl, 0, sizeof(this->ssl));
}
//
@ -132,12 +134,7 @@ namespace Aurora::IO::TLS
bool TLSContext::CheckCertificate(mbedtls_x509_crt const *child, const AuMemoryViewRead &read)
{
if (!this->meta_.pCertPin)
{
return true;
}
auto pCertChain = AuMakeShared<CertificateChain>();
auto pCertChain = AuMakeShared<AuCrypto::X509::CertificateChain>();
if (!pCertChain)
{
SysPushErrorMemory();
@ -146,11 +143,94 @@ namespace Aurora::IO::TLS
pCertChain->Init(child);
auto bRet = this->meta_.pCertPin->CheckCertificate(pCertChain, read);
bool bRet;
if (this->meta_.pCertPin)
{
bRet = this->meta_.pCertPin->CheckCertificate(pCertChain, read);
}
else
{
// No release needed!
bRet = AuCrypto::CA::PinCheckGlobalNew()->CheckCertificate(pCertChain, read);
}
pCertChain->pCertificate = nullptr;
return bRet;
}
AuSPtr<Crypto::KeyPair::IPrivateKeyPair> TLSContext::GetKeyPairForSNI(const AuROString &name)
{
if (this->meta_.pKeyPairProvider)
{
if (auto pRet = this->meta_.pKeyPairProvider->FetchBySNI(name))
{
return pRet;
}
}
if (this->meta_.bIsClient || this->meta_.server.bAllowSNIToFallBackDefault)
{
return this->GetDefaultKeyPair();
}
else
{
return {};
}
}
AuSPtr<Crypto::KeyPair::IPrivateKeyPair> TLSContext::GetDefaultKeyPair()
{
if (this->meta_.pDefaultKeyPair)
{
return this->meta_.pDefaultKeyPair;
}
if (auto pRet = this->meta_.pKeyPairProvider->FetchBySNI({}))
{
return pRet;
}
return {};
}
bool TLSContext::SetBasicCerts()
{
if (this->meta_.bIsClient || this->meta_.server.bAllowSNILessUseDefaultCert)
{
this->pStoredPair = this->GetDefaultKeyPair();
}
return true;
}
void TLSContext::OnSNI(const AuROString &name)
{
this->pStoredPair = this->GetKeyPairForSNI(name);
}
bool TLSContext::DoFinalCerts()
{
auto pKeyVal = this->pStoredPair;
if (!pKeyVal)
{
if (true)
{
pKeyVal = this->GetDefaultKeyPair();
}
if (!pKeyVal)
{
AuLogWarn("no key val");
return false;
}
}
auto pKeyPairEx = AuStaticCast<AuCrypto::KeyPair::PrivateKeyPairImpl>(pKeyVal);
auto pPKContext = &pKeyPairEx->GetInternal();
auto pPublicChain = AuStaticCast<AuCrypto::X509::CertificateChain>(pKeyPairEx->GetChain());
auto pCertificate = pPublicChain ? pPublicChain->pCertificate : nullptr;
return mbedtls_ssl_set_hs_own_cert(&this->ssl, pCertificate, pPKContext) == 0;
}
//
// tls context
//
@ -187,6 +267,7 @@ namespace Aurora::IO::TLS
::mbedtls_ssl_init(&this->ssl);
::mbedtls_ssl_config_init(&this->conf);
::mbedtls_ssl_set_user_data_p(&this->ssl, this);
if ((iRet = ::mbedtls_ssl_config_defaults(&this->conf,
this->meta_.bIsClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
@ -216,30 +297,94 @@ namespace Aurora::IO::TLS
::mbedtls_ssl_conf_verify(&this->conf, [](void *p_ctx, mbedtls_x509_crt *crt,
int depth, uint32_t *flags)
{
*flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED;
if (depth != 0)
{
return 0;
}
((TLSContext *)p_ctx)->CheckCertificate(crt, { crt->raw.p, crt->raw.len }) ? 0 : -1;
if (!((TLSContext *)p_ctx)->CheckCertificate(crt, { crt->raw.p, crt->raw.len }))
{
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
}
else
{
*flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED;
}
return 0;
}, this);
//
#if 0
// todo: useful for clients or servers of single certs? p2p pinning?
::mbedtls_ssl_conf_ca_cb(&this->conf, [](void *p_ctx,
mbedtls_x509_crt const *child,
mbedtls_x509_crt **candidate_cas) -> int
{
return 0;// ((TLSContext *)p_ctx)->CheckCertificate(child, { child->raw.p, child->raw.len }) ? 0 : -1;
}, this);
#endif
::mbedtls_ssl_conf_rng(&this->conf, mbedtls_ctr_drbg_random, &gCtrDrbg);
::mbedtls_ssl_conf_dbg(&this->conf, [](void *, int, const char *as, int, const char *ad)
if (this->meta_.bEnableDebug)
{
//AuLogDbg("{} <--> {}", as, ad);
::mbedtls_ssl_conf_dbg(&this->conf, [](void *p_ctx, int, const char *file, int line, const char *message)
{
AuLogDbg("{} : {}\t {}", file, line, message);
}, nullptr);
mbedtls_debug_set_threshold(5);
}
if (!this->meta_.bIsClient)
{
::mbedtls_ssl_conf_sni(&this->conf, [](void *p_ctx, mbedtls_ssl_context *ssl,
const unsigned char *name, size_t name_len) -> int
{
auto pTlsContext = (TLSContext *)p_ctx;
pTlsContext->OnSNI( AuROString { (const char *)name, name_len});
if (!pTlsContext->DoFinalCerts())
{
return -1;
}
return 0;
}, this);
::mbedtls_ssl_conf_cert_cb(&this->conf, [](mbedtls_ssl_context *ssl) -> int
{
auto pTlsContext = (TLSContext *)::mbedtls_ssl_get_user_data_p(ssl);
if (!pTlsContext->pStoredPair)
{
if (!pTlsContext->SetBasicCerts())
{
return -1;
}
}
if (!pTlsContext->DoFinalCerts())
{
return -1;
}
return 0;
});
}
#if 1
else
{
::mbedtls_ssl_conf_ca_cb(&this->conf, [](void *p_ctx,
mbedtls_x509_crt const *child,
mbedtls_x509_crt **candidate_cas) -> int
{
return 0;
}, this);
}
#endif
if ((iRet = ::mbedtls_ssl_setup(&this->ssl, &this->conf)) != 0)
{

View File

@ -53,6 +53,14 @@ namespace Aurora::IO::TLS
AuString GetFatalErrorCodeAsString() override;
AuSPtr<Crypto::KeyPair::IPrivateKeyPair> GetKeyPairForSNI(const AuROString &name);
AuSPtr<Crypto::KeyPair::IPrivateKeyPair> GetDefaultKeyPair();
bool SetBasicCerts();
bool DoFinalCerts();
void OnSNI(const AuROString &name);
void OnClose();
void OnFatal();
@ -65,6 +73,7 @@ namespace Aurora::IO::TLS
mbedtls_ssl_context ssl {};
mbedtls_ssl_config conf {};
bool bDebugging {};
int Read(void *pOut, AuUInt length);
int Write(const void *pIn, AuUInt length);
@ -88,6 +97,7 @@ namespace Aurora::IO::TLS
AuList<int> cipherSuites_;
TLSMeta meta_;
AuSPtr<Crypto::KeyPair::IPrivateKeyPair> pStoredPair {};
AuWPtr<Net::ISocket> wpSocket_;
TLSProtocolRecv channelRecv_;
TLSProtocolSend channelSend_;

View File

@ -1,69 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: TLSPrivateKeyPair.cpp
Date: 2022-8-27
Author: Reece
***/
#include "TLS.hpp"
#include "TLSPrivateKeyPair.hpp"
namespace Aurora::IO::TLS
{
TLSPrivateKeyPairImpl::TLSPrivateKeyPairImpl()
{
::mbedtls_pk_init(&this->privateKey_);
}
TLSPrivateKeyPairImpl::~TLSPrivateKeyPairImpl()
{
::mbedtls_pk_free(&this->privateKey_);
}
AuSPtr<ICertificateChain> TLSPrivateKeyPairImpl::GetChain()
{
return AuSPtr<ICertificateChain>(AuSharedFromThis(), &this->chain_);
}
CertificateChain *TLSPrivateKeyPairImpl::ToChain()
{
return &this->chain_;
}
mbedtls_pk_context &TLSPrivateKeyPairImpl::GetInternal()
{
return this->privateKey_;
}
AUKN_SYM AuSPtr<ITLSPrivateKeyPair> ImportPrivateKeyPair(const TLSPrivateKeyPair &keyPair)
{
int iRet {};
auto pPrivateKey = AuMakeShared<TLSPrivateKeyPairImpl>();
if (!pPrivateKey)
{
SysPushErrorMemory();
return {};
}
if (!pPrivateKey->ToChain()->Init(keyPair.certificateChain))
{
// Not going to bother with a nested push
return {};
}
iRet = ::mbedtls_pk_parse_key(&pPrivateKey->GetInternal(),
(const unsigned char *)keyPair.privateKey.readPtr,
keyPair.privateKey.RemainingBytes(),
keyPair.sPassword.size() ? (const unsigned char *)keyPair.sPassword.c_str() : nullptr,
keyPair.sPassword.size(),
mbedtls_ctr_drbg_random,
&gCtrDrbg);
if (iRet != 0)
{
SysPushErrorCrypto("Invalid Private Key: {} ({})", TLSErrorToString(iRet), iRet);
return {};
}
return pPrivateKey;
}
}

View File

@ -1,28 +0,0 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: TLSPrivateKeyPair.hpp
Date: 2022-8-27
Author: Reece
***/
#pragma once
#include "TLSCertificateChain.hpp"
namespace Aurora::IO::TLS
{
struct TLSPrivateKeyPairImpl : ITLSPrivateKeyPair, AuEnableSharedFromThis<TLSPrivateKeyPairImpl>
{
TLSPrivateKeyPairImpl();
~TLSPrivateKeyPairImpl();
virtual AuSPtr<ICertificateChain> GetChain() override;
CertificateChain *ToChain();
mbedtls_pk_context &GetInternal();
private:
CertificateChain chain_;
mbedtls_pk_context privateKey_;
};
}