diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8f7d771
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.vs/*
+OpenLumina/x64/*
+OpenLumina/*.user
+x64/*
diff --git a/OpenLumina.sln b/OpenLumina.sln
new file mode 100644
index 0000000..21bda9f
--- /dev/null
+++ b/OpenLumina.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.10.34707.107
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenLumina", "OpenLumina\OpenLumina.vcxproj", "{0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ ida32 Debug|x64 = ida32 Debug|x64
+ ida32 Release|x64 = ida32 Release|x64
+ ida64 Debug|x64 = ida64 Debug|x64
+ ida64 Release|x64 = ida64 Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida32 Debug|x64.ActiveCfg = ida32 Debug|x64
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida32 Debug|x64.Build.0 = ida32 Debug|x64
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida32 Release|x64.ActiveCfg = ida32 Release|x64
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida32 Release|x64.Build.0 = ida32 Release|x64
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida64 Debug|x64.ActiveCfg = ida64 Debug|x64
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida64 Debug|x64.Build.0 = ida64 Debug|x64
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida64 Release|x64.ActiveCfg = ida64 Release|x64
+ {0C1F1447-DAE4-4FA1-BB44-CD3FEE29462F}.ida64 Release|x64.Build.0 = ida64 Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {643F44C8-D40B-411D-996F-F5211E79422E}
+ EndGlobalSection
+EndGlobal
diff --git a/OpenLumina/OpenLumina.cpp b/OpenLumina/OpenLumina.cpp
new file mode 100644
index 0000000..c68f0d1
--- /dev/null
+++ b/OpenLumina/OpenLumina.cpp
@@ -0,0 +1,150 @@
+#include "pch.h"
+
+#define PLUGIN_NAME "OpenLumina"
+#define PLUGIN_DESC "Allows IDA to connect to third party Lumina servers"
+#define PLUGIN_PREFIX "OpenLumina: "
+
+void load_and_decode_certificate(bytevec_t* buffer, const char* certFilePath)
+{
+ auto certFile = fopenRT(certFilePath);
+
+ if (certFile != nullptr)
+ {
+ qstring cert;
+ qstring line;
+
+ if (qgetline(&line, certFile) >= 0)
+ {
+ do
+ {
+ if (strcmp(line.c_str(), "-----BEGIN CERTIFICATE-----"))
+ {
+ if (!strcmp(line.c_str(), "-----END CERTIFICATE-----"))
+ break;
+
+ if (line.length())
+ cert += line;
+ }
+ } while (qgetline(&line, certFile) >= 0);
+ }
+
+ qfclose(certFile);
+
+ if ((debug & IDA_DEBUG_LUMINA) != 0)
+ msg(PLUGIN_PREFIX "cert read: %s\n", cert.c_str());
+
+ if (!base64_decode(buffer, cert.c_str(), cert.length()))
+ buffer->resize(0);
+ }
+}
+
+static plugin_ctx_t* s_plugin_ctx = nullptr;
+
+static BOOL(WINAPI* TrueCertAddEncodedCertificateToStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType, const BYTE* pbCertEncoded, DWORD cbCertEncoded, DWORD dwAddDisposition, PCCERT_CONTEXT* ppCertContext) = CertAddEncodedCertificateToStore;
+
+static BOOL WINAPI HookedCertAddEncodedCertificateToStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType, const BYTE* pbCertEncoded, DWORD cbCertEncoded, DWORD dwAddDisposition, PCCERT_CONTEXT* ppCertContext)
+{
+ if ((debug & IDA_DEBUG_LUMINA) != 0)
+ msg(PLUGIN_PREFIX "HookedCertAddEncodedCertificateToStore called\n");
+
+ if (s_plugin_ctx != nullptr && s_plugin_ctx->decodedCert.size() != 0)
+ {
+ // inject our root certificate to certificate store
+ if (!TrueCertAddEncodedCertificateToStore(hCertStore, X509_ASN_ENCODING, &s_plugin_ctx->decodedCert[0], s_plugin_ctx->decodedCert.size(), CERT_STORE_ADD_USE_EXISTING, nullptr))
+ {
+ msg(PLUGIN_PREFIX "failed to add our root certificate to certificate store!\n");
+ }
+ else
+ {
+ if ((debug & IDA_DEBUG_LUMINA) != 0)
+ msg(PLUGIN_PREFIX "added our root certificate to certificate store\n");
+ }
+ }
+
+ return TrueCertAddEncodedCertificateToStore(hCertStore, dwCertEncodingType, pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
+}
+
+bool idaapi plugin_ctx_t::run(size_t arg)
+{
+ msg(PLUGIN_PREFIX "plugin run called\n");
+ return true;
+}
+
+bool plugin_ctx_t::init_hook()
+{
+ char fileNameBuffer[MAX_PATH];
+
+ auto certFileName = getsysfile(fileNameBuffer, sizeof(fileNameBuffer), "hexrays.crt", nullptr);
+
+ if (certFileName == nullptr)
+ {
+ msg(PLUGIN_PREFIX "can't find hexrays.crt file in your IDA folder!\n");
+ return false;
+ }
+
+ if ((debug & IDA_DEBUG_LUMINA) != 0)
+ msg(PLUGIN_PREFIX "using certificate file \"%s\"\n", certFileName);
+
+ load_and_decode_certificate(&decodedCert, certFileName);
+
+ if (decodedCert.size() == 0)
+ {
+ msg(PLUGIN_PREFIX "failed to decode certificate file!\n");
+ return false;
+ }
+
+ DetourTransactionBegin();
+ DetourUpdateThread(GetCurrentThread());
+ DetourAttach(&(PVOID&)TrueCertAddEncodedCertificateToStore, HookedCertAddEncodedCertificateToStore);
+ DetourTransactionCommit();
+
+ if ((debug & IDA_DEBUG_LUMINA) != 0)
+ msg(PLUGIN_PREFIX "certificate hook applied\n");
+
+ return true;
+}
+
+plugin_ctx_t::~plugin_ctx_t()
+{
+ DetourTransactionBegin();
+ DetourUpdateThread(GetCurrentThread());
+ DetourDetach(&(PVOID&)TrueCertAddEncodedCertificateToStore, HookedCertAddEncodedCertificateToStore);
+ DetourTransactionCommit();
+}
+
+static plugmod_t* idaapi init()
+{
+ auto ctx = new plugin_ctx_t;
+
+ if (ctx == nullptr)
+ {
+ msg(PLUGIN_PREFIX "plugin ctx create failed!\n");
+ return nullptr;
+ }
+
+ if (!ctx->init_hook())
+ {
+ msg(PLUGIN_PREFIX "plugin init_hook failed!\n");
+ return nullptr;
+ }
+
+ s_plugin_ctx = ctx;
+
+ return ctx;
+}
+
+plugin_t PLUGIN =
+{
+ IDP_INTERFACE_VERSION,
+ // PLUGIN_HIDE - Plugin should not appear in the Edit, Plugins menu.
+ // PLUGIN_FIX - Load plugin when IDA starts and keep it in the memory until IDA stops
+ // PLUGIN_MULTI - The plugin can work with multiple idbs in parallel
+ PLUGIN_HIDE | PLUGIN_FIX | PLUGIN_MULTI, // Plugin flags
+ init, // Initialize plugin
+ nullptr, // Terminate plugin
+ nullptr, // Invoke plugin
+ PLUGIN_DESC, // Long comment about the plugin
+ nullptr, // Multiline help about the plugin
+ PLUGIN_NAME, // Preferred short name of the plugin
+ nullptr, // Preferred hotkey to run the plugin
+};
diff --git a/OpenLumina/OpenLumina.vcxproj b/OpenLumina/OpenLumina.vcxproj
new file mode 100644
index 0000000..3da2ecb
--- /dev/null
+++ b/OpenLumina/OpenLumina.vcxproj
@@ -0,0 +1,205 @@
+
+
+
+
+ ida32 Debug
+ x64
+
+
+ ida32 Release
+ x64
+
+
+ ida64 Debug
+ x64
+
+
+ ida64 Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {0c1f1447-dae4-4fa1-bb44-cd3fee29462f}
+ OpenLumina
+ 10.0
+ openlumina
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(IDADIR)\plugins\
+
+
+ true
+ $(IDADIR)\plugins\
+ $(ProjectName)64
+
+
+ false
+ $(IDADIR)\plugins\
+
+
+ false
+ $(IDADIR)\plugins\
+ $(ProjectName)64
+
+
+
+ Level3
+ false
+ _DEBUG;OPENLUMINA_EXPORTS;_WINDOWS;_USRDLL;__NT__;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(IDASDK)\include;%(AdditionalIncludeDirectories)
+ stdcpp20
+
+
+ Windows
+ true
+ false
+ /EXPORT:PLUGIN %(AdditionalOptions)
+ ida.lib;version.lib;crypt32.lib;%(AdditionalDependencies)
+ $(IDASDK)\lib\x64_win_vc_32;$(IDASDK)\lib\x64_win_vc_32_pro
+
+
+
+
+ Level3
+ false
+ _DEBUG;OPENLUMINA_EXPORTS;_WINDOWS;_USRDLL;__NT__;__EA64__;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(IDASDK)\include;%(AdditionalIncludeDirectories)
+ stdcpp20
+
+
+ Windows
+ true
+ false
+ /EXPORT:PLUGIN %(AdditionalOptions)
+ ida.lib;version.lib;crypt32.lib;%(AdditionalDependencies)
+ $(IDASDK)\lib\x64_win_vc_64;$(IDASDK)\lib\x64_win_vc_64_pro
+
+
+
+
+ Level3
+ true
+ true
+ false
+ NDEBUG;OPENLUMINA_EXPORTS;_WINDOWS;_USRDLL;__NT__;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(IDASDK)\include;%(AdditionalIncludeDirectories)
+ false
+ false
+ false
+ stdcpp20
+
+
+ Windows
+ true
+ true
+ false
+ false
+ /EXPORT:PLUGIN %(AdditionalOptions)
+ ida.lib;version.lib;crypt32.lib;%(AdditionalDependencies)
+ $(IDASDK)\lib\x64_win_vc_32;$(IDASDK)\lib\x64_win_vc_32_pro
+
+
+
+
+ Level3
+ true
+ true
+ false
+ NDEBUG;OPENLUMINA_EXPORTS;_WINDOWS;_USRDLL;__NT__;__EA64__;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(IDASDK)\include;%(AdditionalIncludeDirectories)
+ false
+ false
+ false
+ stdcpp20
+
+
+ Windows
+ true
+ true
+ false
+ false
+ /EXPORT:PLUGIN %(AdditionalOptions)
+ ida.lib;version.lib;crypt32.lib;%(AdditionalDependencies)
+ $(IDASDK)\lib\x64_win_vc_64;$(IDASDK)\lib\x64_win_vc_64_pro
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenLumina/OpenLumina.vcxproj.filters b/OpenLumina/OpenLumina.vcxproj.filters
new file mode 100644
index 0000000..2ee6598
--- /dev/null
+++ b/OpenLumina/OpenLumina.vcxproj.filters
@@ -0,0 +1,36 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/OpenLumina/PropertySheet.props b/OpenLumina/PropertySheet.props
new file mode 100644
index 0000000..9a61bb5
--- /dev/null
+++ b/OpenLumina/PropertySheet.props
@@ -0,0 +1,20 @@
+
+
+
+
+ ..\$(Platform)\$(Configuration)
+ e:\ida77\idasdk77
+
+
+
+
+
+ $(IDADIR)
+ true
+
+
+ $(IDASDK)
+ true
+
+
+
\ No newline at end of file
diff --git a/OpenLumina/dllmain.cpp b/OpenLumina/dllmain.cpp
new file mode 100644
index 0000000..d72b8df
--- /dev/null
+++ b/OpenLumina/dllmain.cpp
@@ -0,0 +1,16 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ if (ul_reason_for_call == DLL_PROCESS_ATTACH)
+ {
+ char mutexName[32] = "";
+ sprintf_s(mutexName, "openlumina_v1_%X", GetCurrentProcessId());
+ return CreateMutexA(nullptr, FALSE, mutexName) && GetLastError() != ERROR_ALREADY_EXISTS;
+ }
+ return TRUE;
+}
diff --git a/OpenLumina/framework.h b/OpenLumina/framework.h
new file mode 100644
index 0000000..d7beaec
--- /dev/null
+++ b/OpenLumina/framework.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+#include
diff --git a/OpenLumina/pch.cpp b/OpenLumina/pch.cpp
new file mode 100644
index 0000000..64b7eef
--- /dev/null
+++ b/OpenLumina/pch.cpp
@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/OpenLumina/pch.h b/OpenLumina/pch.h
new file mode 100644
index 0000000..fabf212
--- /dev/null
+++ b/OpenLumina/pch.h
@@ -0,0 +1,25 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+#include "framework.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "detours/detours.h"
+
+#include "plugin_ctx.h"
+
+#endif //PCH_H
diff --git a/OpenLumina/plugin_ctx.h b/OpenLumina/plugin_ctx.h
new file mode 100644
index 0000000..15f68a3
--- /dev/null
+++ b/OpenLumina/plugin_ctx.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "pch.h"
+
+struct plugin_ctx_t : public plugmod_t
+{
+ bytevec_t decodedCert;
+ bool idaapi run(size_t arg) override;
+ bool init_hook();
+ ~plugin_ctx_t() override;
+};
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3e20508
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+OpenLumina
+
+IDA plugin that allows connecting to third party Lumina servers.
+
+## Getting started
+
+1. Build or download precompiled version of the plugin and put it into your IDA\plugins directory
+2. Copy hexrays.crt certificate file provided by Lumina server owner to your IDA install directory
+
+## Building plugin
+
+1. Visual Studio 2022 is required for building plugin
+2. vcpkg package manager required if you don't want to configure dependencies yourself manually
+3. Install Microsoft Detours package through vcpkg `vcpkg install detours`
+4. Configure paths to your extracted IDA SDK directory and optionally your IDA install directory in PropertySheet.props file
+5. Open OpenLumina.sln in Visual Studio and build the plugin
+
+## Generating TLS certificates for your own Lumina server
+
+See scripts in lumina_ca folder. Generating certificates requires OpenSSL 3.x to be installed and be on the PATH environment variable.
diff --git a/lumina_ca/commands.cmd b/lumina_ca/commands.cmd
new file mode 100644
index 0000000..eebd2bc
--- /dev/null
+++ b/lumina_ca/commands.cmd
@@ -0,0 +1,43 @@
+chcp 65001
+mkdir rootCA\certs
+mkdir rootCA\crl
+mkdir rootCA\newcerts
+mkdir rootCA\private
+mkdir rootCA\csr
+mkdir intermediateCA\certs
+mkdir intermediateCA\crl
+mkdir intermediateCA\newcerts
+mkdir intermediateCA\private
+mkdir intermediateCA\csr
+echo 01 > ./rootCA/serial
+echo 01 > ./intermediateCA/serial
+echo 01 > ./rootCA/crlnumber
+echo 01 > ./intermediateCA/crlnumber
+type NUL > ./rootCA/index.txt
+type NUL > ./intermediateCA/index.txt
+openssl genrsa -out ./rootCA/private/ca.key.pem 4096
+echo chmod 400 ./rootCA/private/ca.key.pem
+openssl rsa -noout -text -in ./rootCA/private/ca.key.pem
+openssl req -config openssl_root.cnf -key ./rootCA/private/ca.key.pem -utf8 -new -x509 -days 7300 -sha512 -extensions v3_ca -out ./rootCA/certs/ca.cert.pem -subj "/C=BE/L=Liège/O=Hex-Rays SA./CN=Hex-Rays SA. Root CA"
+echo chmod 444 ./rootCA/certs/ca.cert.pem
+openssl x509 -noout -text -in ./rootCA/certs/ca.cert.pem
+openssl genrsa -out ./intermediateCA/private/intermediate.key.pem 4096
+echo chmod 400 ./intermediateCA/private/intermediate.key.pem
+openssl req -config openssl_intermediate.cnf -key ./intermediateCA/private/intermediate.key.pem -utf8 -new -sha512 -out ./intermediateCA/certs/intermediate.csr.pem -subj "/C=BE/L=Liège/O=Hex-Rays SA./CN=Hex-Rays SA. Intermediate CA 2"
+openssl ca -config openssl_root.cnf -extensions v3_intermediate_ca -days 3650 -utf8 -notext -md sha512 -in ./intermediateCA/certs/intermediate.csr.pem -out ./intermediateCA/certs/intermediate.cert.pem -batch
+echo chmod 444 ./intermediateCA/certs/intermediate.cert.pem
+openssl x509 -noout -text -in ./intermediateCA/certs/intermediate.cert.pem
+openssl verify -CAfile ./rootCA/certs/ca.cert.pem ./intermediateCA/certs/intermediate.cert.pem
+copy /b intermediateCA\certs\intermediate.cert.pem + rootCA\certs\ca.cert.pem intermediateCA\certs\ca-chain.cert.pem
+openssl verify -CAfile ./intermediateCA/certs/ca-chain.cert.pem ./intermediateCA/certs/intermediate.cert.pem
+openssl ecparam -name prime256v1 -genkey -out ./intermediateCA/private/vault.hex-rays.com.key.pem
+openssl req -config openssl_intermediate.cnf -key ./intermediateCA/private/vault.hex-rays.com.key.pem -utf8 -new -sha256 -out ./intermediateCA/csr/vault.hex-rays.com.csr.pem -subj "/C=BE/L=Liège/O=Hex-Rays SA./CN=vault.hex-rays.com"
+openssl ca -config openssl_intermediate.cnf -extensions server_cert -days 375 -utf8 -notext -md sha256 -in ./intermediateCA/csr/vault.hex-rays.com.csr.pem -out ./intermediateCA/certs/vault.hex-rays.com.cert.pem -batch
+openssl x509 -noout -text -in ./intermediateCA/certs/vault.hex-rays.com.cert.pem
+openssl verify -CAfile ./intermediateCA/certs/ca-chain.cert.pem ./intermediateCA/certs/vault.hex-rays.com.cert.pem
+copy /b intermediateCA\certs\vault.hex-rays.com.cert.pem + intermediateCA\certs\intermediate.cert.pem intermediateCA\certs\vault.hex-rays.com.chain.cert.pem
+openssl verify -CAfile ./intermediateCA/certs/ca-chain.cert.pem ./intermediateCA/certs/vault.hex-rays.com.chain.cert.pem
+mkdir out
+copy rootCA\certs\ca.cert.pem out\hexrays.crt
+copy intermediateCA\certs\vault.hex-rays.com.chain.cert.pem out\lumina.crt
+copy intermediateCA\private\vault.hex-rays.com.key.pem out\lumina.key
diff --git a/lumina_ca/commands.sh b/lumina_ca/commands.sh
new file mode 100644
index 0000000..7faaa4d
--- /dev/null
+++ b/lumina_ca/commands.sh
@@ -0,0 +1,34 @@
+mkdir -p ./rootCA/{certs,crl,newcerts,private,csr}
+mkdir -p ./intermediateCA/{certs,crl,newcerts,private,csr}
+echo 01 > ./rootCA/serial
+echo 01 > ./intermediateCA/serial
+echo 01 > ./rootCA/crlnumber
+echo 01 > ./intermediateCA/crlnumber
+touch ./rootCA/index.txt
+touch ./intermediateCA/index.txt
+openssl genrsa -out ./rootCA/private/ca.key.pem 4096
+chmod 400 ./rootCA/private/ca.key.pem
+openssl rsa -noout -text -in ./rootCA/private/ca.key.pem
+openssl req -config openssl_root.cnf -key ./rootCA/private/ca.key.pem -utf8 -new -x509 -days 7300 -sha512 -extensions v3_ca -out ./rootCA/certs/ca.cert.pem -subj "/C=BE/L=Liège/O=Hex-Rays SA./CN=Hex-Rays SA. Root CA"
+chmod 444 ./rootCA/certs/ca.cert.pem
+openssl x509 -noout -text -in ./rootCA/certs/ca.cert.pem
+openssl genrsa -out ./intermediateCA/private/intermediate.key.pem 4096
+chmod 400 ./intermediateCA/private/intermediate.key.pem
+openssl req -config openssl_intermediate.cnf -key ./intermediateCA/private/intermediate.key.pem -utf8 -new -sha512 -out ./intermediateCA/certs/intermediate.csr.pem -subj "/C=BE/L=Liège/O=Hex-Rays SA./CN=Hex-Rays SA. Intermediate CA 2"
+openssl ca -config openssl_root.cnf -extensions v3_intermediate_ca -days 3650 -utf8 -notext -md sha512 -in ./intermediateCA/certs/intermediate.csr.pem -out ./intermediateCA/certs/intermediate.cert.pem
+chmod 444 ./intermediateCA/certs/intermediate.cert.pem
+openssl x509 -noout -text -in ./intermediateCA/certs/intermediate.cert.pem
+openssl verify -CAfile ./rootCA/certs/ca.cert.pem ./intermediateCA/certs/intermediate.cert.pem
+cat ./intermediateCA/certs/intermediate.cert.pem ./rootCA/certs/ca.cert.pem > ./intermediateCA/certs/ca-chain.cert.pem
+openssl verify -CAfile ./intermediateCA/certs/ca-chain.cert.pem ./intermediateCA/certs/intermediate.cert.pem
+openssl ecparam -name prime256v1 -genkey -out ./intermediateCA/private/vault.hex-rays.com.key.pem
+openssl req -config openssl_intermediate.cnf -key ./intermediateCA/private/vault.hex-rays.com.key.pem -utf8 -new -sha256 -out ./intermediateCA/csr/vault.hex-rays.com.csr.pem -subj "/C=BE/L=Liège/O=Hex-Rays SA./CN=vault.hex-rays.com"
+openssl ca -config openssl_intermediate.cnf -extensions server_cert -days 375 -utf8 -notext -md sha256 -in ./intermediateCA/csr/vault.hex-rays.com.csr.pem -out ./intermediateCA/certs/vault.hex-rays.com.cert.pem
+openssl x509 -noout -text -in ./intermediateCA/certs/vault.hex-rays.com.cert.pem
+openssl verify -CAfile ./intermediateCA/certs/ca-chain.cert.pem ./intermediateCA/certs/vault.hex-rays.com.cert.pem
+cat ./intermediateCA/certs/vault.hex-rays.com.cert.pem ./intermediateCA/certs/intermediate.cert.pem > ./intermediateCA/certs/vault.hex-rays.com.chain.cert.pem
+openssl verify -CAfile ./intermediateCA/certs/ca-chain.cert.pem ./intermediateCA/certs/vault.hex-rays.com.chain.cert.pem
+mkdir out
+cp ./rootCA/certs/ca.cert.pem out/hexrays.crt
+cp ./intermediateCA/certs/vault.hex-rays.com.chain.cert.pem out/lumina.crt
+cp ./intermediateCA/private/vault.hex-rays.com.key.pem out/lumina.key
diff --git a/lumina_ca/openssl_intermediate.cnf b/lumina_ca/openssl_intermediate.cnf
new file mode 100644
index 0000000..c5b4f3c
--- /dev/null
+++ b/lumina_ca/openssl_intermediate.cnf
@@ -0,0 +1,76 @@
+[ ca ] # The default CA section
+default_ca = CA_default # The default CA name
+
+[ CA_default ] # Default settings for the intermediate CA
+dir = ./intermediateCA # Intermediate CA directory
+certs = $dir/certs # Certificates directory
+crl_dir = $dir/crl # CRL directory
+new_certs_dir = $dir/newcerts # New certificates directory
+database = $dir/index.txt # Certificate index file
+serial = $dir/serial # Serial number file
+RANDFILE = $dir/private/.rand # Random number file
+private_key = $dir/private/intermediate.key.pem # Intermediate CA private key
+certificate = $dir/certs/intermediate.cert.pem # Intermediate CA certificate
+crl = $dir/crl/intermediate.crl.pem # Intermediate CA CRL
+crlnumber = $dir/crlnumber # Intermediate CA CRL number
+crl_extensions = crl_ext # CRL extensions
+default_crl_days = 30 # Default CRL validity days
+default_md = sha512 # Default message digest
+preserve = no # Preserve existing extensions
+email_in_dn = no # Exclude email from the DN
+name_opt = ca_default # Formatting options for names
+cert_opt = ca_default # Certificate output options
+policy = policy_loose # Certificate policy
+unique_subject = no # Allow multiple certs with the same DN
+x509_extensions = v3_intermediate_ca # Extensions for intermediate CA certificate
+
+[ policy_loose ] # Policy for less strict validation
+countryName = optional # Country is optional
+stateOrProvinceName = optional # State or province is optional
+localityName = optional # Locality is optional
+organizationName = optional # Organization is optional
+organizationalUnitName = optional # Organizational unit is optional
+commonName = supplied # Must provide a common name
+emailAddress = optional # Email address is optional
+
+[ req ] # Request settings
+default_bits = 4096 # Default key size
+distinguished_name = req_distinguished_name # Default DN template
+string_mask = utf8only # UTF-8 encoding
+default_md = sha512 # Default message digest
+prompt = no # Non-interactive mode
+x509_extensions = v3_intermediate_ca # Extensions for intermediate CA certificate
+
+[ req_distinguished_name ] # Template for the DN in the CSR
+countryName = BE
+countryName_default = BE
+#stateOrProvinceName = State or Province Name
+localityName = Liège
+localityName_default = Liège
+0.organizationName = Hex-Rays SA.
+0.organizationName_default = Hex-Rays SA.
+#organizationalUnitName = Organizational Unit Name
+commonName = Hex-Rays SA. Intermediate CA 2
+commonName_default = Hex-Rays SA. Intermediate CA 2
+#emailAddress = Email Address
+
+[ v3_intermediate_ca ] # Intermediate CA certificate extensions
+#subjectKeyIdentifier = hash # Subject key identifier
+authorityKeyIdentifier = keyid:always # Authority key identifier
+basicConstraints = critical, CA:true, pathlen:0 # Basic constraints for a CA
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign # Key usage for a CA
+crlDistributionPoints = crldp1_section
+
+[crldp1_section]
+fullname = URI:http://crl.hex-rays.com/intermediate_ca_2.crl
+
+[ crl_ext ] # CRL extensions
+authorityKeyIdentifier=keyid:always # Authority key identifier
+
+[ server_cert ] # Server certificate extensions
+#nsCertType = server # Server certificate type
+#keyUsage = critical, digitalSignature, keyEncipherment # Key usage for a server cert
+extendedKeyUsage = critical, serverAuth # Extended key usage for server authentication purposes (e.g., TLS/SSL servers).
+basicConstraints = critical, CA:FALSE # Not a CA certificate
+authorityKeyIdentifier = keyid # Authority key identifier linking the certificate to the issuer's public key.
+subjectKeyIdentifier = none # Subject key identifier
diff --git a/lumina_ca/openssl_root.cnf b/lumina_ca/openssl_root.cnf
new file mode 100644
index 0000000..1cdfecc
--- /dev/null
+++ b/lumina_ca/openssl_root.cnf
@@ -0,0 +1,73 @@
+[ ca ] # The default CA section
+default_ca = CA_default # The default CA name
+
+[ CA_default ] # Default settings for the CA
+dir = ./rootCA # CA directory
+certs = $dir/certs # Certificates directory
+crl_dir = $dir/crl # CRL directory
+new_certs_dir = $dir/newcerts # New certificates directory
+database = $dir/index.txt # Certificate index file
+serial = $dir/serial # Serial number file
+RANDFILE = $dir/private/.rand # Random number file
+private_key = $dir/private/ca.key.pem # Root CA private key
+certificate = $dir/certs/ca.cert.pem # Root CA certificate
+crl = $dir/crl/ca.crl.pem # Root CA CRL
+crlnumber = $dir/crlnumber # Root CA CRL number
+crl_extensions = crl_ext # CRL extensions
+default_crl_days = 30 # Default CRL validity days
+default_md = sha512 # Default message digest
+preserve = no # Preserve existing extensions
+email_in_dn = no # Exclude email from the DN
+name_opt = ca_default # Formatting options for names
+cert_opt = ca_default # Certificate output options
+policy = policy_strict # Certificate policy
+unique_subject = no # Allow multiple certs with the same DN
+
+[ policy_strict ] # Policy for stricter validation
+countryName = match # Must match the issuer's country
+stateOrProvinceName = optional # State or Province is optional
+localityName = match
+organizationName = match # Must match the issuer's organization
+organizationalUnitName = optional # Organizational unit is optional
+commonName = supplied # Must provide a common name
+emailAddress = optional # Email address is optional
+
+[ req ] # Request settings
+default_bits = 4096 # Default key size
+distinguished_name = req_distinguished_name # Default DN template
+string_mask = utf8only # UTF-8 encoding
+default_md = sha512 # Default message digest
+prompt = no # Non-interactive mode
+x509_extensions = v3_ca
+
+[ req_distinguished_name ] # Template for the DN in the CSR
+countryName = BE
+#stateOrProvinceName = State or Province Name (full name)
+localityName = Liège
+0.organizationName = Hex-Rays SA.
+#organizationalUnitName = Organizational Unit Name (section)
+commonName = Hex-Rays SA. Root CA
+#emailAddress = Email Address
+
+[ v3_ca ] # Root CA certificate extensions
+subjectKeyIdentifier = hash # Subject key identifier
+authorityKeyIdentifier = keyid:always,issuer # Authority key identifier
+basicConstraints = critical, CA:true # Basic constraints for a CA
+keyUsage = critical, digitalSignature, keyCertSign, cRLSign # Key usage for a CA
+crlDistributionPoints = crldp1_section
+
+[ crl_ext ] # CRL extensions
+authorityKeyIdentifier = keyid:always,issuer # Authority key identifier
+
+[ v3_intermediate_ca ]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+crlDistributionPoints = crldp2_section
+
+[crldp1_section]
+fullname = URI:http://crl.hex-rays.com/root_ca.crl
+
+[crldp2_section]
+fullname = URI:http://crl.hex-rays.com/intermediate_ca_2.crl
diff --git a/lumina_ca/readme.txt b/lumina_ca/readme.txt
new file mode 100644
index 0000000..5275c7d
--- /dev/null
+++ b/lumina_ca/readme.txt
@@ -0,0 +1,4 @@
+Run commands.cmd (on Windows) or commands.sh (on Linux) to generate TLS certificates for your Lumina server
+
+Use lumina.crt and lumina.key on you Lumina server
+Use hexrays.crt on your IDA clients