Skip to content

Latest commit

 

History

History
353 lines (271 loc) · 10.9 KB

File metadata and controls

353 lines (271 loc) · 10.9 KB

RSA-SHA256 Signature Verification - Usage Guide

Overview

The signature verification system provides production-ready cryptographic verification for LoRA adapters and model weights using OpenSSL. It implements RSA-SHA256 signature verification with X.509 certificate validation.

Architecture

The system uses the Chain of Responsibility and Builder patterns:

┌─────────────────────────────────────────────────────────┐
│              SignatureVerifierBuilder                   │
│  (Fluent interface for building verification chains)   │
└─────────────────────┬───────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────┐
│            ISignatureVerifier (Base Class)              │
└─────┬───────────────────┬──────────────────┬────────────┘
      │                   │                  │
      ▼                   ▼                  ▼
┌──────────────┐  ┌──────────────────┐  ┌──────────┐
│ RSA_SHA256   │  │ CertificateChain │  │   CRL    │
│  Verifier    │→ │    Verifier      │→ │ Checker  │
└──────────────┘  └──────────────────┘  └──────────┘

Quick Start

Basic RSA-SHA256 Verification

#include "llm/security/signature_verifier.h"

using namespace themis::llm::security;

// Create verifier
RSA_SHA256_Verifier verifier;

// Load data and signature
std::vector<uint8_t> data = /* your data */;
std::vector<uint8_t> signature = /* signature bytes */;
std::string cert_pem = /* X.509 certificate in PEM format */;

// Verify
auto result = verifier.verify(data, signature, cert_pem);

if (result.is_valid) {
    std::cout << "Signature valid!" << std::endl;
    std::cout << "Signer: " << result.signer_identity << std::endl;
} else {
    std::cerr << "Signature invalid: " << result.error_message << std::endl;
}

Full Verification Chain with Builder

#include "llm/security/signature_verifier.h"

using namespace themis::llm::security;

// Build verification chain with RSA, certificate chain, and CRL checks
SignatureVerifierBuilder builder;
auto verifier = builder
    .withRSA_SHA256()
    .withCertificateChainValidation("/etc/ssl/certs/ca-certificates.crt")
    .withCRLCheck("http://crl.example.com/adapter.crl")
    .build();

// Verify with full chain
auto result = verifier->verify(data, signature, cert_pem);

if (result.is_valid && result.chain_valid) {
    std::cout << "Full verification passed!" << std::endl;
} else {
    std::cerr << "Verification failed: " << result.error_message << std::endl;
}

Components

1. RSA_SHA256_Verifier

Performs cryptographic RSA-SHA256 signature verification.

Features:

  • Loads X.509 certificates from PEM format
  • Extracts and validates RSA public keys
  • Enforces minimum 2048-bit key size
  • Computes SHA-256 hash of data
  • Verifies signature using OpenSSL EVP API

Usage:

RSA_SHA256_Verifier verifier;
auto result = verifier.verify(data, signature, cert_pem);

2. CertificateChainVerifier

Validates X.509 certificate chains against trusted CAs.

Features:

  • Loads CA bundles from system or custom paths
  • Validates certificate chain to trusted root
  • Checks certificate expiration
  • Detects self-signed certificates
  • Reports specific validation errors

Usage:

CertificateChainVerifier verifier("/etc/ssl/certs/ca-certificates.crt");
auto result = verifier.verify(data, signature, cert_pem);

if (!result.chain_valid) {
    std::cerr << "Chain validation failed" << std::endl;
}

Supported CA Bundle Paths (auto-detected):

  • /etc/ssl/certs/ca-certificates.crt (Debian/Ubuntu)
  • /etc/pki/tls/certs/ca-bundle.crt (RHEL/CentOS)
  • /etc/ssl/ca-bundle.pem (OpenSUSE)
  • /usr/local/share/certs/ca-root-nss.crt (FreeBSD)
  • System default paths

3. CRLChecker

Checks if certificates are revoked via Certificate Revocation Lists.

Features:

  • CRL checking framework
  • Graceful handling of unavailable CRLs
  • Certificate serial number extraction
  • Falls back on error (doesn't block validation)

Usage:

CRLChecker checker("http://crl.example.com/adapter.crl");
auto result = checker.verify(data, signature, cert_pem);

Note: Full CRL download requires HTTP client integration (planned).

4. SignatureVerifierBuilder

Fluent interface for building verification chains.

Usage:

SignatureVerifierBuilder builder;

// Add verifiers in desired order
auto verifier = builder
    .withRSA_SHA256()                              // Step 1: RSA verification
    .withCertificateChainValidation("/path/to/ca") // Step 2: Chain validation
    .withCRLCheck("http://crl.url")                // Step 3: Revocation check
    .build();

// Execute verification chain
auto result = verifier->verify(data, signature, cert_pem);

Result Structure

struct SignatureVerificationResult {
    bool is_valid;                      // Overall validity
    std::string algorithm;              // Algorithm used (e.g., "RSA-SHA256")
    std::string signer_identity;        // Subject from certificate
    std::string error_message;          // Error details if invalid
    std::vector<std::string> chain_fingerprints; // Chain cert fingerprints
    bool chain_valid;                   // Certificate chain validity
};

Integration with LoRA Security Validator

The signature verifier is integrated with LoRASecurityValidator:

#include "llm/lora_security_validator.h"

using namespace themis::llm;

LoRASecurityConfig config;
config.require_signature = true;
config.trusted_signers = {"cert_fingerprint_1", "cert_fingerprint_2"};

LoRASecurityValidator validator(config);

// Verify LoRA adapter signature
auto result = validator.verifyEmbeddedSignature("path/to/adapter.safetensors");

if (result.is_valid) {
    std::cout << "LoRA adapter signature verified" << std::endl;
} else {
    std::cerr << "Invalid signature: " << result.error_message << std::endl;
}

Security Considerations

Key Requirements

  • ✅ Minimum 2048-bit RSA keys (enforced)
  • ✅ SHA-256 hash algorithm (not SHA-1)
  • ✅ X.509 v3 certificates
  • ✅ Certificate chain to trusted CA
  • ✅ Detailed error messages

Threat Mitigation

Threat Mitigation
Data tampering Signature verification fails on modified data
Malicious adapter Unsigned or improperly signed adapter rejected
Compromised key CRL check fails (when CRL available)
Man-in-the-middle Certificate chain validation fails
Weak keys 1024-bit and smaller keys rejected

TODO: Security Enhancements

  • Constant-time comparison (timing attack resistance)
  • Certificate pinning (optional)
  • Rate limiting for verification (DoS prevention)
  • Full CRL download/caching

Testing

Generate Test Certificates

cd tests/data/certificates
./generate_test_certs.sh

This creates:

  • CA certificate and key
  • Test certificates (2048, 3072, 4096-bit)
  • Self-signed certificate
  • Expired certificate
  • Weak 1024-bit certificate
  • Test data and signatures

Run Tests

Minimal standalone test (no dependencies):

cd tests
./test_signature_minimal.sh

GTest suite (requires full build):

cd build
ctest -R SignatureVerifierTests

Example: Signing and Verifying a LoRA Adapter

1. Generate Key Pair

# Generate 2048-bit RSA key
openssl genrsa -out lora_key.pem 2048

# Create certificate signing request
openssl req -new -key lora_key.pem -out lora.csr \
    -subj "/C=US/ST=CA/O=YourOrg/CN=lora-signer"

# Sign with your CA (or create self-signed for testing)
openssl x509 -req -in lora.csr -CA ca_cert.pem -CAkey ca_key.pem \
    -CAcreateserial -out lora_cert.pem -days 365 -sha256

2. Sign LoRA Adapter

# Sign the adapter file
openssl dgst -sha256 -sign lora_key.pem \
    -out adapter_signature.bin adapter.safetensors

3. Verify in Code

// Load adapter, signature, and certificate
auto adapter_data = loadFile("adapter.safetensors");
auto signature = loadFile("adapter_signature.bin");
auto cert_pem = loadFile("lora_cert.pem");

// Verify
RSA_SHA256_Verifier verifier;
auto result = verifier.verify(adapter_data, signature, cert_pem);

if (result.is_valid) {
    // Load and use the adapter
    loadLoRAAdapter("adapter.safetensors");
}

Performance

Typical verification times (on modern CPU):

  • RSA-2048 verification: < 1ms
  • RSA-4096 verification: < 5ms
  • Certificate chain validation: < 10ms
  • Full chain (RSA + chain + CRL): < 15ms

Error Messages

Common error messages and meanings:

Error Meaning
"Data is empty" Input data vector is empty
"Signature is empty" Signature vector is empty
"Certificate is empty" Certificate PEM string is empty
"Failed to load certificate" Invalid PEM format
"Failed to extract public key" Certificate doesn't contain valid public key
"RSA key size too small: X bits" Key is smaller than 2048 bits
"Signature verification failed: signature does not match" Signature is invalid (data tampered or wrong key)
"Certificate chain validation failed" Certificate not trusted by CA bundle
"Certificate has expired" Certificate validity period has ended
"Self-signed certificate" Certificate not signed by trusted CA

Best Practices

  1. Always validate certificate chains in production
  2. Use strong keys (≥2048 bits, prefer 3072 or 4096)
  3. Keep CA bundles updated for security
  4. Log verification failures for security auditing
  5. Use CRL checking when available
  6. Rotate keys regularly (annually recommended)
  7. Store private keys securely (HSM for production)
  8. Never commit private keys to source control

References

Support

For issues or questions:

  • Check error messages for specific failure reasons
  • Review test certificates in tests/data/certificates/
  • Run standalone tests to verify OpenSSL installation
  • Check system CA bundle paths are accessible

Version: 1.0
Status: Production Ready
Last Updated: 2026-04-06