Status: ✅ Produktiv
Version: 1.0 (November 2025)
Compliance: eIDAS Art. 26-35, DSGVO Art. 32
Die PKI-Signatur-Implementierung in ThemisDB ermöglicht kryptographisch sichere digitale Signaturen für:
- Audit-Logs (Manipulationsschutz)
- SAGA-Transaktionen (Nachvollziehbarkeit)
- Content-Blobs (Authentizität)
- Backup-Manifeste (Integritätssicherung)
| Algorithmus | Hash-Funktion | Key-Größe | Output-Größe | Empfehlung |
|---|---|---|---|---|
| RSA-SHA256 | SHA-256 | 2048-4096 bit | 256-512 Bytes | ✅ Standard (Produktion) |
| RSA-SHA384 | SHA-384 | 2048-4096 bit | 256-512 Bytes | ✅ Höhere Sicherheit |
| RSA-SHA512 | SHA-512 | 4096 bit | 512 Bytes | ✅ eIDAS-qualifiziert |
Konfiguration:
export THEMIS_PKI_SIGNING_ALGORITHM=RSA-SHA256 # Default
export THEMIS_PKI_SIGNING_ALGORITHM=RSA-SHA512 # Für eIDAS-konforme Signaturen┌─────────────────────┐
│ Input Data │
│ (arbitrary bytes) │
└──────────┬──────────┘
│
│ SHA256/384/512
▼
┌─────────────────────┐
│ Hash (32/48/64 B) │
└──────────┬──────────┘
│
│ RSA Private Key Sign
▼
┌─────────────────────┐
│ Signature (Base64) │
└──────────┬──────────┘
│
│ Attach Metadata
▼
┌─────────────────────────────────────┐
│ SignatureResult │
│ - signature_b64: "ABC..." │
│ - algorithm: "RSA-SHA256" │
│ - cert_serial: "1A2B3C4D" │
│ - signature_id: "sig_a1b2c3d4" │
│ - timestamp: 1731868800000 │
└─────────────────────────────────────┘
┌─────────────────────┐
│ Input Data │
│ (same as signed) │
└──────────┬──────────┘
│
│ SHA256/384/512
▼
┌─────────────────────┐
│ Hash (computed) │
└──────────┬──────────┘
│
│ RSA Public Key Verify
│ against signature_b64
▼
┌─────────────────────┐
│ Valid: true/false │
└─────────────────────┘
#include "utils/pki_client.h"
VCCPKIClient pki(cfg);
// Daten vorbereiten
std::vector<uint8_t> data = {'H', 'e', 'l', 'l', 'o'};
// Signieren
SignatureResult result = pki.sign(data);
if (result.ok) {
std::cout << "Signature: " << result.signature_b64 << std::endl;
std::cout << "Algorithm: " << result.algorithm << std::endl;
std::cout << "Cert Serial: " << result.cert_serial << std::endl;
std::cout << "Timestamp: " << result.timestamp << std::endl;
} else {
std::cerr << "Signing failed: " << result.error_message << std::endl;
}Output:
Signature: cGFkZGluZy4uLnNpZ25hdHVyZS4uLnBhZGRpbmc=
Algorithm: RSA-SHA256
Cert Serial: 1A2B3C4D5E6F
Timestamp: 1731868800000
#include "utils/pki_client.h"
VCCPKIClient pki(cfg);
std::vector<uint8_t> data = {'H', 'e', 'l', 'l', 'o'};
std::string signature_b64 = "cGFkZGluZy4uLnNpZ25hdHVyZS4uLnBhZGRpbmc=";
// Verifizieren
bool valid = pki.verify(data, signature_b64);
if (valid) {
std::cout << "✅ Signature is valid" << std::endl;
} else {
std::cout << "❌ Signature is INVALID" << std::endl;
}Für bereits gehashte Daten (z.B. von externer Quelle):
// SHA256-Hash bereits berechnet
std::vector<uint8_t> hash_bytes = {
0x2c, 0xf2, 0x4d, 0xba, // ... 32 Bytes total
};
SignatureResult result = pki.signHash(hash_bytes);Achtung: Hash-Länge muss zum Algorithmus passen:
- SHA256: 32 Bytes
- SHA384: 48 Bytes
- SHA512: 64 Bytes
std::vector<uint8_t> hash_bytes = {/* 32 bytes */};
std::string signature_b64 = "...";
bool valid = pki.verifyHash(hash_bytes, signature_b64);Request:
curl -X POST http://localhost:8080/api/pki/sign \
-H "Content-Type: application/json" \
-d '{
"data": "SGVsbG8gV29ybGQ=",
"algorithm": "RSA-SHA256"
}'Response:
{
"signature_b64": "cGFkZGluZy4uLnNpZ25hdHVyZS4uLnBhZGRpbmc=",
"signature_id": "sig_a1b2c3d4",
"algorithm": "RSA-SHA256",
"cert_serial": "1A2B3C4D5E6F",
"timestamp": 1731868800000,
"ok": true
}Request:
curl -X POST http://localhost:8080/api/pki/verify \
-H "Content-Type: application/json" \
-d '{
"data": "SGVsbG8gV29ybGQ=",
"signature_b64": "cGFkZGluZy4uLnNpZ25hdHVyZS4uLnBhZGRpbmc=",
"algorithm": "RSA-SHA256"
}'Response:
{
"valid": true,
"cert_serial": "1A2B3C4D5E6F",
"message": "Signature verification successful"
}Request:
curl http://localhost:8080/api/pki/certificateResponse:
{
"certificate": "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAKl...\n-----END CERTIFICATE-----",
"serial": "1A2B3C4D5E6F",
"subject": "/C=DE/ST=Bavaria/O=ThemisDB/CN=themis.example.com",
"issuer": "/C=DE/O=ThemisDB CA/CN=ThemisDB Root CA",
"valid_from": "2025-01-01T00:00:00Z",
"valid_to": "2035-01-01T00:00:00Z",
"key_size": 4096
}Audit-Logs verwenden das Encrypt-then-Sign-Muster für Compliance:
┌─────────────────┐
│ Sensitive Data │
└────────┬────────┘
│
│ AES-256-GCM Encrypt
▼
┌─────────────────┐
│ Encrypted Data │
└────────┬────────┘
│
│ Serialize to JSON
▼
┌─────────────────┐
│ JSON Log Entry │
└────────┬────────┘
│
│ RSA-SHA256 Sign
▼
┌─────────────────────────┐
│ Log Entry + Signature │
│ RocksDB: saga_log:* │
│ RocksDB: saga_signature:│
└─────────────────────────┘
#include "server/saga_logger.h"
SAGALogger logger(field_encryption, pki_client, config);
// Log-Operation (automatisch encrypted + signed)
logger.logOperation(
"saga_001", // SAGA ID
"step_1", // Step ID
"INSERT", // Operation
"users", // Collection
"user:alice", // Entity PK
entity.toJson() // Entity JSON
);Gespeicherte Signatur:
{
"saga_id": "saga_001",
"step_id": "step_1",
"signature": "cGFkZGluZy4uLnNpZ25hdHVyZS4uLnBhZGRpbmc=",
"algorithm": "RSA-SHA256",
"cert_serial": "1A2B3C4D5E6F",
"timestamp": 1731868800000,
"signed_data_hash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}RocksDB Keys:
- Log:
saga_log:saga_001:step_1 - Signatur:
saga_signature:saga_001:step_1
Für HSM-backed Signing kann ThemisDB HashiCorp Vault verwenden:
export THEMIS_PKI_VAULT_ADDR=https://vault.example.com:8200
export THEMIS_PKI_VAULT_TOKEN=s.abc123def456
export THEMIS_PKI_VAULT_SIGN_PATH=transit/sign/themis-key┌──────────────┐
│ ThemisDB │
└──────┬───────┘
│
│ POST /v1/transit/sign/themis-key
│ { "hash_b64": "...", "algorithm": "rsa-2048" }
▼
┌──────────────┐
│ Vault │
│ (HSM-backed) │
└──────┬───────┘
│
│ Signature (Base64)
▼
┌──────────────┐
│ ThemisDB │
│ (Receive Sig)│
└──────────────┘
Vorteile:
- Private Key verbleibt im HSM
- Audit-Trail in Vault
- Multi-Tenant-Key-Management
| Artikel | Anforderung | Umsetzung in ThemisDB |
|---|---|---|
| Art. 26 | Qualifizierte Signatur | RSA-SHA512 mit QTSP-Zertifikat |
| Art. 27 | Signaturprüfung | POST /api/pki/verify |
| Art. 28 | Signaturformat | Base64-encoded PKCS#1 v1.5 |
| Art. 32 | Langzeitarchivierung | Timestamp + Audit-Logs |
| Art. 34 | Validierung | X.509-Chain-Validierung (optional) |
| Artikel | Anforderung | Umsetzung |
|---|---|---|
| Art. 32 | Sicherheit der Verarbeitung | Encrypt-then-Sign, RSA-2048+ |
| Art. 25 | Datenschutz durch Technik | PKI-basierte Authentizität |
| Art. 5(1)(f) | Integrität und Vertraulichkeit | Signatur-basierte Tamper-Evidence |
| Key-Größe | Algorithmus | Ops/Sekunde | Latenz (ms) |
|---|---|---|---|
| 2048 bit | RSA-SHA256 | ~500 | ~2 |
| 4096 bit | RSA-SHA256 | ~150 | ~7 |
| 4096 bit | RSA-SHA512 | ~145 | ~7 |
Hardware: Intel Xeon E5-2680 v4 (2.4 GHz), 64 GB RAM
| Key-Größe | Algorithmus | Ops/Sekunde | Latenz (ms) |
|---|---|---|---|
| 2048 bit | RSA-SHA256 | ~15,000 | ~0.07 |
| 4096 bit | RSA-SHA256 | ~6,000 | ~0.17 |
| 4096 bit | RSA-SHA512 | ~5,900 | ~0.17 |
Optimierung: Verify ist ~30x schneller als Sign (Public Key Operation)
Symptom:
[ERROR] PKI Client: Failed to load private key from /etc/themis/pki/service.key
Lösung:
# Prüfe Key-Format
openssl rsa -in /etc/themis/pki/service.key -check -noout
# Konvertiere falls nötig
openssl rsa -in service.key.old -out service.key -outform PEMSymptom:
[WARN] PKI Client: Signature verification failed for data hash
Ursachen:
- Daten wurden modifiziert
- Falscher Public Key
- Algorithmus-Mismatch
Debug:
// Enable debug-Logging
std::setenv("THEMIS_DEBUG_PKI", "1", 1);
// Manuell verifizieren
openssl dgst -sha256 -verify pubkey.pem -signature sig.bin data.binSymptom:
[ERROR] PKI Client: Certificate serial does not match expected value
Lösung:
# Zeige Zertifikats-Serial
openssl x509 -in service.crt -serial -noout
# Erwarteter Serial muss mit PKI-Config übereinstimmen- Minimum: 2048 bit (für Entwicklung)
- Empfohlen: 4096 bit (für Produktion)
- eIDAS-qualifiziert: 4096 bit mit SHA-512
- Standard: RSA-SHA256 (Balance aus Sicherheit und Performance)
- High-Security: RSA-SHA512 (eIDAS-konform)
- Legacy: Avoid SHA1 (deprecated)
Speichere immer Timestamp mit Signatur:
SignatureResult result = pki.sign(data);
// result.timestamp ist automatisch gesetzt (Unix-Millisekunden)Bei Zertifikats-Rotation:
- Alte Signaturen bleiben verifizierbar (mit altem Zertifikat)
- Neue Signaturen verwenden neues Zertifikat
- Speichere Zertifikats-Serial mit jeder Signatur
Jede Signatur-Operation sollte geloggt werden:
logger.logSignatureOperation(
signature_id,
algorithm,
cert_serial,
data_hash,
timestamp
);#include <gtest/gtest.h>
#include "utils/pki_client.h"
TEST(PKIClientTest, SignAndVerify) {
PKIConfig cfg = PKIConfig::fromEnvironment();
VCCPKIClient pki(cfg);
std::vector<uint8_t> data = {'H', 'e', 'l', 'l', 'o'};
auto result = pki.sign(data);
ASSERT_TRUE(result.ok);
ASSERT_FALSE(result.signature_b64.empty());
bool valid = pki.verify(data, result.signature_b64);
EXPECT_TRUE(valid);
}
TEST(PKIClientTest, VerifyFailsOnModifiedData) {
PKIConfig cfg = PKIConfig::fromEnvironment();
VCCPKIClient pki(cfg);
std::vector<uint8_t> data = {'H', 'e', 'l', 'l', 'o'};
auto result = pki.sign(data);
// Modify data
data[0] = 'h';
bool valid = pki.verify(data, result.signature_b64);
EXPECT_FALSE(valid); // Should fail
}# Test mit echtem Zertifikat
export THEMIS_PKI_PRIVATE_KEY=/tmp/test.key
export THEMIS_PKI_CERTIFICATE=/tmp/test.crt
# Generiere Test-Zertifikat
openssl genrsa -out /tmp/test.key 2048
openssl req -new -x509 -key /tmp/test.key -out /tmp/test.crt -days 365 \
-subj "/C=DE/O=ThemisDB/CN=test"
# Run Tests
./build/tests/test_pki_client-
Standards:
- eIDAS Regulation (EU) No 910/2014
- PKCS#1 v2.1: RSA Cryptography Standard (RFC 3447)
- X.509 v3 Certificate Standard (RFC 5280)
- TSP (Time-Stamp Protocol) RFC 3161
-
Dateien:
src/utils/pki_client.cpp- Core Implementationinclude/utils/pki_client.h- Public APIsrc/server/pki_api_handler.cpp- HTTP-Endpunktetests/test_pki_client.cpp- Unit-Tests
-
Dependencies:
- OpenSSL 1.1+ (EVP, RSA, X.509, PEM)
- libcurl 7.x+ (Vault-Integration)
- nlohmann/json 3.x+ (JSON-Serialisierung)
Letzte Aktualisierung: 17. November 2025
Version: 1.0
Autor: ThemisDB Development Team