-
Notifications
You must be signed in to change notification settings - Fork 1
LINUX_MODULE_SIGNING
Linux has mehrere Mechanismen für Signierung und Verifikation von shared libraries (.so), die ähnlich zu Windows Authenticode funktionieren, aber anders implementiert sind.
| Feature | Windows | Linux |
|---|---|---|
| Binary Format | PE (Portable Executable) | ELF (Executable and Linkable Format) |
| Signature Embedding | Authenticode (in PE Certificate Table) | GPG detached signatures (.sig files) |
| Download Marking | Zone.Identifier (NTFS ADS) | Extended attributes (xattr) |
| Metadata | Version resources in PE | ELF notes / .comment section |
| System Integration | Built-in (WinVerifyTrust API) | Package manager dependent |
Ähnlich zu: Authenticode, aber als separate Datei
How it works:
# Sign a shared library
gpg --detach-sign --armor themis_storage.so
# Creates: themis_storage.so.asc (or .sig)
# Verify signature
gpg --verify themis_storage.so.asc themis_storage.soFile structure:
/opt/themisdb/lib/
themis_storage.so # Binary
themis_storage.so.asc # Signature (armored)
Vorteile:
- ✅ Standard Linux approach
- ✅ Works with package managers (dpkg, rpm)
- ✅ Widely supported tooling
- ✅ No binary modification needed
Nachteile:
- ❌ Separate file (can be separated)
- ❌ Not embedded in binary
- ❌ Requires GPG keyring management
Ähnlich zu: Authenticode (embedded)
Tool: osslsigncode (OpenSSL-based signing tool)
# Install
apt-get install osslsigncode
# Sign (creates new signed file)
osslsigncode sign \
-certs themisdb-cert.pem \
-key themisdb-key.pem \
-in themis_storage.so \
-out themis_storage.so.signed
# Verify
osslsigncode verify themis_storage.so.signedVorteile:
- ✅ Embedded in binary (like Authenticode)
- ✅ Single file
- ✅ X.509 certificates
Nachteile:
- ❌ Less common on Linux
- ❌ Modifies binary
- ❌ Limited distro support
Ähnlich zu: Windows Code Integrity / Device Guard
What it is: Linux Integrity Measurement Architecture
# Enable IMA
echo "1" > /sys/kernel/security/ima/policy
# Sign with IMA signature
evmctl ima_sign --key /path/to/key.pem themis_storage.so
# Signature stored in extended attribute
getfattr -d -m security.ima themis_storage.soVorteile:
- ✅ Kernel-enforced integrity
- ✅ Cannot be bypassed in userspace
- ✅ Used in secure boot chains
Nachteile:
- ❌ Requires kernel support (CONFIG_IMA)
- ❌ Complex setup
- ❌ Not portable across systems
Linux kann extended attributes (xattr) nutzen, ähnlich zu NTFS Alternate Data Streams.
Example:
# Mark file as "downloaded from internet"
setfattr -n user.download.source -v "https://github.com/makr-code/ThemisDB" themis_storage.so
setfattr -n user.download.timestamp -v "2025-12-17T22:00:00Z" themis_storage.so
# Read attributes
getfattr -d themis_storage.so
# Output:
# user.download.source="https://github.com/makr-code/ThemisDB"
# user.download.timestamp="2025-12-17T22:00:00Z"Browser Integration:
- Firefox/Chrome on Linux DO NOT automatically add download markers (unlike Windows)
- Custom solution needed for download tracking
File System Support:
- ext4, XFS, Btrfs: ✅ Full xattr support
- FAT, exFAT: ❌ No xattr support
# Add metadata to .comment section
echo "ThemisDB GmbH - themis_storage v1.4.0" > comment.txt
objcopy --add-section .comment=comment.txt themis_storage.so themis_storage.so.new
# Read metadata
readelf -p .comment themis_storage.so# Add custom note section
objcopy --add-section .note.themisdb=metadata.bin themis_storage.so
# Read notes
readelf -n themis_storage.so# GCC/Clang automatically generates build ID
gcc -Wl,--build-id=sha1 ...
# Read build ID
readelf -n themis_storage.so | grep "Build ID"CMake Integration:
# Add build ID and metadata
if(UNIX)
target_link_options(themis_storage PRIVATE
-Wl,--build-id=sha1
)
# Add custom section with metadata
add_custom_command(TARGET themis_storage POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "ThemisDB ${PROJECT_VERSION}" > ${CMAKE_BINARY_DIR}/metadata.txt
COMMAND objcopy --add-section .themis.metadata=${CMAKE_BINARY_DIR}/metadata.txt
$<TARGET_FILE:themis_storage>
$<TARGET_FILE:themis_storage>.tmp
COMMAND ${CMAKE_COMMAND} -E rename $<TARGET_FILE:themis_storage>.tmp $<TARGET_FILE:themis_storage>
)
endif()Debian/Ubuntu (dpkg):
# Packages (.deb) are signed with GPG
dpkg-sig --sign builder themisdb_1.4.0_amd64.deb
# Verify
dpkg-sig --verify themisdb_1.4.0_amd64.debRed Hat/Fedora (rpm):
# RPM packages include GPG signatures
rpm --addsign themisdb-1.4.0-1.x86_64.rpm
# Verify
rpm --checksig themisdb-1.4.0-1.x86_64.rpm1. GPG Detached Signatures (Primary)
- Sign all .so files with GPG
- Distribute .sig files alongside binaries
- ModuleLoader verifies GPG signatures
2. Extended Attributes (Download Tracking)
- Add xattr for download source
- Check in ModuleLoader
- Warn if from untrusted source
3. ELF Metadata (Version Info)
- Build ID via linker
- Custom .themis.metadata section
- Version, copyright, build info
include/themis/base/module_loader.h:
class ModuleLoader {
public:
// ... existing methods ...
#ifdef __linux__
/**
* @brief Verify GPG signature of module
* @param modulePath Path to .so file
* @param signaturePath Path to .sig/.asc file (optional, auto-detected)
* @return true if signature valid
*/
bool verifyGPGSignature(const std::string& modulePath,
const std::string& signaturePath = "") const;
/**
* @brief Check extended attributes (download marker)
* @param modulePath Path to .so file
* @return Map of attribute name → value
*/
std::map<std::string, std::string> getExtendedAttributes(const std::string& modulePath) const;
/**
* @brief Read ELF metadata (Build ID, .comment, custom sections)
* @param modulePath Path to .so file
* @return Metadata structure
*/
ELFMetadata readELFMetadata(const std::string& modulePath) const;
/**
* @brief Check IMA signature (if kernel supports)
* @param modulePath Path to .so file
* @return true if IMA signature valid
*/
bool verifyIMASignature(const std::string& modulePath) const;
#endif
};Implementation:
#ifdef __linux__
#include <sys/xattr.h>
#include <elf.h>
#include <gelf.h>
#include <libelf.h>
bool ModuleLoader::verifyGPGSignature(const std::string& modulePath,
const std::string& signaturePath) const {
// Auto-detect signature file if not provided
std::string sigPath = signaturePath;
if (sigPath.empty()) {
// Try .asc first, then .sig
if (std::filesystem::exists(modulePath + ".asc")) {
sigPath = modulePath + ".asc";
} else if (std::filesystem::exists(modulePath + ".sig")) {
sigPath = modulePath + ".sig";
} else {
spdlog::warn("No GPG signature file found for {}", modulePath);
return false;
}
}
// Verify using gpgme library
gpgme_ctx_t ctx;
gpgme_error_t err;
err = gpgme_new(&ctx);
if (err) {
spdlog::error("GPG context creation failed: {}", gpgme_strerror(err));
return false;
}
// Open signature and data files
gpgme_data_t sig, text;
FILE* sigFile = fopen(sigPath.c_str(), "r");
FILE* dataFile = fopen(modulePath.c_str(), "r");
gpgme_data_new_from_stream(&sig, sigFile);
gpgme_data_new_from_stream(&text, dataFile);
// Verify
err = gpgme_op_verify(ctx, sig, text, nullptr);
bool verified = false;
if (!err) {
gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
if (result && result->signatures) {
gpgme_signature_t s = result->signatures;
verified = (s->status == GPG_ERR_NO_ERROR);
if (verified) {
spdlog::info("GPG signature verified: {} (key: {})",
modulePath, s->fpr);
} else {
spdlog::error("GPG signature invalid: {}", gpgme_strerror(s->status));
}
}
}
// Cleanup
gpgme_data_release(sig);
gpgme_data_release(text);
gpgme_release(ctx);
fclose(sigFile);
fclose(dataFile);
return verified;
}
std::map<std::string, std::string> ModuleLoader::getExtendedAttributes(
const std::string& modulePath) const {
std::map<std::string, std::string> attrs;
// List all extended attributes
ssize_t buflen = listxattr(modulePath.c_str(), nullptr, 0);
if (buflen <= 0) {
return attrs; // No attributes
}
std::vector<char> buf(buflen);
listxattr(modulePath.c_str(), buf.data(), buflen);
// Parse attribute list (null-separated)
size_t pos = 0;
while (pos < buf.size()) {
std::string attrName(&buf[pos]);
if (attrName.empty()) break;
// Read attribute value
ssize_t vallen = getxattr(modulePath.c_str(), attrName.c_str(), nullptr, 0);
if (vallen > 0) {
std::vector<char> val(vallen + 1);
getxattr(modulePath.c_str(), attrName.c_str(), val.data(), vallen);
val[vallen] = '\0';
attrs[attrName] = std::string(val.data());
}
pos += attrName.length() + 1;
}
return attrs;
}
ELFMetadata ModuleLoader::readELFMetadata(const std::string& modulePath) const {
ELFMetadata meta;
// Initialize libelf
if (elf_version(EV_CURRENT) == EV_NONE) {
return meta;
}
int fd = open(modulePath.c_str(), O_RDONLY);
if (fd < 0) {
return meta;
}
Elf* elf = elf_begin(fd, ELF_C_READ, nullptr);
if (!elf) {
close(fd);
return meta;
}
// Read Build ID from notes
Elf_Scn* scn = nullptr;
while ((scn = elf_nextscn(elf, scn)) != nullptr) {
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
if (shdr.sh_type == SHT_NOTE) {
Elf_Data* data = elf_getdata(scn, nullptr);
if (data) {
// Parse note section for Build ID
GElf_Nhdr nhdr;
size_t name_offset, desc_offset;
size_t offset = 0;
while ((offset = gelf_getnote(data, offset, &nhdr,
&name_offset, &desc_offset)) > 0) {
if (nhdr.n_type == NT_GNU_BUILD_ID) {
const unsigned char* build_id =
(const unsigned char*)data->d_buf + desc_offset;
std::stringstream ss;
for (size_t i = 0; i < nhdr.n_descsz; i++) {
ss << std::hex << std::setw(2) << std::setfill('0')
<< (int)build_id[i];
}
meta.buildId = ss.str();
}
}
}
}
}
// Read .comment section
scn = nullptr;
while ((scn = elf_nextscn(elf, scn)) != nullptr) {
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
char* name = elf_strptr(elf, elf_getshdrstrndx(elf, nullptr), shdr.sh_name);
if (name && std::string(name) == ".comment") {
Elf_Data* data = elf_getdata(scn, nullptr);
if (data) {
meta.comment = std::string((char*)data->d_buf, data->d_size);
}
}
}
elf_end(elf);
close(fd);
return meta;
}
#endif# Linux: GPG signing and metadata
if(UNIX AND NOT APPLE)
# Function to sign a module with GPG
function(sign_module_gpg TARGET_NAME)
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND gpg --detach-sign --armor $<TARGET_FILE:${TARGET_NAME}>
COMMENT "Signing ${TARGET_NAME} with GPG"
)
endfunction()
# Function to add ELF metadata
function(add_elf_metadata TARGET_NAME)
# Add build ID
target_link_options(${TARGET_NAME} PRIVATE -Wl,--build-id=sha1)
# Add custom metadata section
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo
"ThemisDB GmbH - ${TARGET_NAME} v${PROJECT_VERSION}"
> ${CMAKE_BINARY_DIR}/${TARGET_NAME}_meta.txt
COMMAND objcopy
--add-section .themis.metadata=${CMAKE_BINARY_DIR}/${TARGET_NAME}_meta.txt
$<TARGET_FILE:${TARGET_NAME}>
COMMENT "Adding metadata to ${TARGET_NAME}"
)
endfunction()
# Apply to all modules
sign_module_gpg(themis_storage)
sign_module_gpg(themis_query)
# ... etc
add_elf_metadata(themis_storage)
add_elf_metadata(themis_query)
# ... etc
endif()debian/control:
Package: themisdb
Version: 1.4.0
Architecture: amd64
Maintainer: ThemisDB GmbH <info@themisdb.com>
Description: ThemisDB Database Server
Multi-model database with modular architecture
Signing:
# Sign package
dpkg-sig --sign builder themisdb_1.4.0_amd64.deb
# Verify
dpkg-sig --verify themisdb_1.4.0_amd64.debthemisdb.spec:
Name: themisdb
Version: 1.4.0
Release: 1%{?dist}
Summary: ThemisDB Database Server
License: MIT
URL: https://github.com/makr-code/ThemisDB
%description
ThemisDB multi-model database with modular architecture
%files
%{_libdir}/themis_*.so
%{_libdir}/themis_*.so.ascSigning:
# Sign RPM
rpm --addsign themisdb-1.4.0-1.x86_64.rpm
# Verify
rpm --checksig themisdb-1.4.0-1.x86_64.rpm| Security Feature | Windows | Linux |
|---|---|---|
| Embedded Signatures | ✅ Authenticode in PE | |
| Detached Signatures | ❌ Not standard | ✅ GPG (.sig files) |
| Download Marking | ✅ Zone.Identifier (ADS) | |
| Version Info | ✅ PE resources | ✅ ELF notes/.comment |
| System Integration | ✅ Built-in (WinVerifyTrust) | |
| Kernel Enforcement | ✅ Code Integrity | ✅ IMA/EVM (opt-in) |
| Package Manager | ❌ No standard | ✅ dpkg/rpm signing |
- GPG Detached Signatures für alle .so Dateien
- ELF Build ID automatisch via Linker
- ModuleLoader GPG Verification in Linux builds
- Package Repository mit GPG-signierten Packages
- IMA/EVM Support für high-security deployments
- Extended Attributes für download tracking
Production Build:
# Build with signing
cmake -DTHEMIS_BUILD_MODULAR=ON -DTHEMIS_SIGN_MODULES=ON ..
make
# Result:
# lib/themis_storage.so
# lib/themis_storage.so.asc (GPG signature)Verification:
themis::modules::ModuleLoader loader;
#ifdef __linux__
// Linux: GPG verification
auto result = loader.loadModule("/opt/themisdb/lib/themis_storage.so", "themis_storage");
// Automatically checks for themis_storage.so.asc
#endif
#ifdef _WIN32
// Windows: Authenticode verification
auto result = loader.loadModule("C:\\Program Files\\ThemisDB\\themis_storage.dll", "themis_storage");
// Checks embedded Authenticode signature
#endif
if (!result.success) {
spdlog::critical("Module verification failed: {}", result.errorMessage);
return 1;
}Ja, es gibt Linux-Äquivalente zu Windows Authenticode:
| Windows Feature | Linux Equivalent | Implementation |
|---|---|---|
| Authenticode signatures | GPG detached signatures (.asc/.sig) | ✅ Recommended |
| PE Certificate Table | osslsigncode (embedded) | |
| Zone.Identifier | Extended attributes (xattr) | ✅ Feasible |
| Version resources | ELF notes + .comment section | ✅ Standard |
| WinVerifyTrust API | gpgme library | ✅ Available |
| Code Integrity | IMA/EVM kernel subsystem |
Empfehlung: GPG detached signatures als Primary-Methode für Linux, analog zu Authenticode für Windows.
- GPG Signing: https://www.gnupg.org/documentation/
- GPGME Library: https://gnupg.org/software/gpgme/
- ELF Format: https://refspecs.linuxfoundation.org/elf/elf.pdf
- IMA/EVM: https://www.kernel.org/doc/html/latest/security/IMA-templates.html
- Extended Attributes: https://man7.org/linux/man-pages/man7/xattr.7.html
- Debian Package Signing: https://wiki.debian.org/SecureApt
- RPM Signing: https://rpm-software-management.github.io/rpm/manual/signatures.html
- Architecture-ACCESS-MODEL-IMPLEMENTATION-SUMMARY
- Architecture-ADR-003-pg-dump-sql-parser
- Architecture-BASEENTITY-PRINCIPLE
- Architecture-CACHE-STORAGE-INTEGRATION
- Architecture-CMAKE-ARCHITECTURE
- Architecture-CMAKE-FLAGS-REFERENCE
- Architecture-CMAKE-MODULAR-ARCHITECTURE
- Architecture-CONCERNS-ARCHITECTURE-DIAGRAM
- Architecture-CONCERNS-IMPLEMENTATION-SUMMARY
- Architecture-CONTENT-MODEL
- Architecture-COPILOT-THEMISDB-GRAPH-RAG-BACKEND-ARCHITECTURE
- Architecture-CRYPTO-AND-KEYS
- Architecture-FEATURE-FLAGS-REFERENCE
- Architecture-GPU-ARCHITECTURE-REVIEW-TEMPLATE
- Architecture-HTTP-SHUTDOWN-HARDENING
- Architecture-MIGRATION-GUIDE-CONCERNS
- Architecture-MIGRATION-GUIDE-v13-v14
- Architecture-MODULARIZATION-GUIDE
- Architecture-MODULAR-ARCHITECTURE-ROADMAP
- Architecture-MODULE-ARCHITECTURE-INDEX
- Architecture-P1D01-ISSMPLUGIN-DESIGN-REVIEW
- Architecture-P1-D01-ISSMPLUGIN-DESIGN-REVIEW
- Architecture-P1-D08-MAMBA-GOVERNANCE-CONTRACT
- Architecture-P1-P2-IMPLEMENTATION-COMPLETION-INDEX
- Architecture-PHASE0-COMPLETION-ASSESSMENT
- Architecture-PHASE3-QUERYENGINE-DI-ARCHITECTURE
- Architecture-PHASE4-INDEX-MANAGER-DI
- Architecture-POSTGRESQL-WIRE-PROTOCOL
- Architecture-QUERYENGINE-IMPLEMENTATION-GUIDE
- Architecture-QUERY-SCHEDULING
- Architecture-RAFT-CONSENSUS-DESIGN
- Architecture-README
- Architecture-README-SSM-HYBRID-IMPLEMENTATION
- Architecture-REFACTORING-SUMMARY
- Architecture-RESOURCE-POOLING
- Architecture-SOURCE-DIRECTORY-GUIDE
- Architecture-THEMIS-CORE-GUIDE
- Architecture-UNIFIED-ACCESS-MODEL
- Architecture-WAL-GRPC-MTLS-CONFIGURATION
- Architecture-WIRE-PROTOCOL-RETRY
- Architecture-boltzmann-observability-draft
- Architecture-experimental-logarithmic-vector-storage
- Architecture-llm-wiki-mvp-adr
- Architecture-rewrite-engine-architecture
- Architecture-rope-api-architecture
- Architecture-ssm-gguf-mamba-status
- Architecture-ssm-hybrid-analysis
- Architecture-ssm-hybrid-rollout-plan
- Architecture-ssm-plugin-interface-design-review
- Architecture-transaction-coordinators
- Architecture-wiki-secondary-index
- Architecture-wire-protocol
- Governance-DISABLED-STUB-POLICY
- Governance-DOCS-PR-POLICY
- Governance-GA-PROMOTION-SIGN-OFF
- Governance-GITHUB-MILESTONES-SETUP
- Governance-MATURITY-CLAIM-VERIFICATION-CHECKLIST
- Governance-MATURITY-EVIDENCE-REGISTRY
- Governance-MERGE-GATE-BOT-CONFIG
- Governance-MERGE-GATE-STATUS-LIVE
- Governance-PHASE3-ENFORCEMENT-RUNBOOK
- Governance-PHASE-1-CLOSURE-REPORT
- Governance-PHASE-CLOSURE-POLICY
- Governance-PHASE-DEPENDENCY-GRAPH
- Governance-PLUGIN-SUBMODULE-ROLLBACK
- Governance-PRODUCTION-READY-2026-DELIVERY-PLAN
- Governance-PR-VERSION-TARGETING
- Governance-PR-VERSION-TARGETING-BACKFILL
- Governance-QUERY-MODULE-STATUS
- Governance-README
- Governance-RELEASE-PROMOTION-GATE-POLICY
- Governance-RELEASE-VALIDATION-CHECKLIST
- Governance-SECURITY-MODULE-5671-EVIDENCE-SUMMARY
- Governance-SHARDING-P6-RESIDUAL-RISK-ACCEPTANCE
- Governance-SOURCECODE-COMPLIANCE-GOVERNANCE
- Governance-UPDATES-DEVELOPMENT-STATUS-SIGN-OFF
- Governance-WAVE-C-IMPLEMENTATION-COMPLETE
- Module-acceleration-Roadmap
- Module-access-model-Roadmap
- Module-ai-Roadmap
- Module-analytics-Roadmap
- Module-api-Roadmap
- Module-aql-Roadmap
- Module-auth-Roadmap
- Module-base-Roadmap
- Module-cache-Roadmap
- Module-cdc-Roadmap
- Module-chaos-Roadmap
- Module-chimera-Roadmap
- Module-config-Roadmap
- Module-content-Roadmap
- Module-core-Roadmap
- Module-distributed-knowledge-Roadmap
- Module-distributed-tensor-Roadmap
- Module-document-Roadmap
- Module-ethics-ai-Roadmap
- Module-evaluation-Roadmap
- Module-execution-Roadmap
- Module-exporters-Roadmap
- Module-failover-Roadmap
- Module-geo-Roadmap
- Module-governance-Roadmap
- Module-gpu-Roadmap
- Module-graph-Roadmap
- Module-image-analysis-Roadmap
- Module-importers-Roadmap
- Module-index-Roadmap
- Module-ingestion-Roadmap
- Module-llama-cpp-Roadmap
- Module-llm-Roadmap
- Module-llm-streaming-Roadmap
- Module-llm-wiki-Roadmap
- Module-maintenance-Roadmap
- Module-metadata-Roadmap
- Module-network-Roadmap
- Module-observability-Roadmap
- Module-onnx-clip-Roadmap
- Module-performance-Roadmap
- Module-plugins-Roadmap
- Module-process-Roadmap
- Module-projects-Roadmap
- Module-prompt-engineering-Roadmap
- Module-query-Roadmap
- Module-rag-Roadmap
- Module-replication-Roadmap
- Module-retrieval-Roadmap
- Module-rpc-grpc-Roadmap
- Module-scheduler-Roadmap
- Module-scraper-Roadmap
- Module-search-Roadmap
- Module-security-Roadmap
- Module-server-Roadmap
- Module-sharding-Roadmap
- Module-stable-diffusion-Roadmap
- Module-storage-Roadmap
- Module-temporal-Roadmap
- Module-tensor-Roadmap
- Module-themis-Roadmap
- Module-timeseries-Roadmap
- Module-toolbox-Roadmap
- Module-training-Roadmap
- Module-transaction-Roadmap
- Module-updates-Roadmap
- Module-user-storage-encrypted-Roadmap
- Module-utils-Roadmap
- Module-vector-search-Roadmap
- Module-voice-Roadmap
- Module-whisper-Roadmap