Add post-quantum cryptography support with PqSoftCryptoProvider
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
wine-csp-build / Build Wine CSP Image (push) Has been cancelled

- Implemented PqSoftCryptoProvider for software-only post-quantum algorithms (Dilithium3, Falcon512) using BouncyCastle.
- Added PqSoftProviderOptions and PqSoftKeyOptions for configuration.
- Created unit tests for Dilithium3 and Falcon512 signing and verification.
- Introduced EcdsaPolicyCryptoProvider for compliance profiles (FIPS/eIDAS) with explicit allow-lists.
- Added KcmvpHashOnlyProvider for KCMVP baseline compliance.
- Updated project files and dependencies for new libraries and testing frameworks.
This commit is contained in:
StellaOps Bot
2025-12-07 15:04:19 +02:00
parent 862bb6ed80
commit 98e6b76584
119 changed files with 11436 additions and 1732 deletions

173
ops/wine-csp/Dockerfile Normal file
View File

@@ -0,0 +1,173 @@
# syntax=docker/dockerfile:1.7
# Wine CSP Service - GOST cryptographic operations via Wine-hosted CryptoPro CSP
#
# WARNING: For TEST VECTOR GENERATION ONLY - not for production signing
#
# Build:
# docker buildx build -f ops/wine-csp/Dockerfile -t wine-csp:latest .
#
# Run:
# docker run -p 5099:5099 -e WINE_CSP_MODE=limited wine-csp:latest
# ==============================================================================
# Stage 1: Build .NET application for Windows x64
# ==============================================================================
ARG SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:10.0-preview-bookworm-slim
FROM ${SDK_IMAGE} AS build
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 \
DOTNET_NOLOGO=1 \
DOTNET_ROLL_FORWARD=LatestMajor \
SOURCE_DATE_EPOCH=1704067200
WORKDIR /src
# Copy solution files and NuGet configuration
COPY Directory.Build.props Directory.Build.rsp NuGet.config ./
# Copy local NuGet packages if available
COPY local-nugets/ ./local-nugets/
# Copy Wine CSP Service source
COPY src/__Tools/WineCspService/ ./src/__Tools/WineCspService/
# Copy GostCryptography fork dependency
COPY third_party/forks/AlexMAS.GostCryptography/ ./third_party/forks/AlexMAS.GostCryptography/
# Restore and publish for Windows x64 (runs under Wine)
RUN --mount=type=cache,target=/root/.nuget/packages \
dotnet restore src/__Tools/WineCspService/WineCspService.csproj && \
dotnet publish src/__Tools/WineCspService/WineCspService.csproj \
-c Release \
-r win-x64 \
--self-contained true \
-o /app/publish \
/p:PublishSingleFile=true \
/p:EnableCompressionInSingleFile=true \
/p:DebugType=none \
/p:DebugSymbols=false
# ==============================================================================
# Stage 2: Runtime with Wine and CryptoPro CSP support
# ==============================================================================
FROM ubuntu:22.04 AS runtime
# OCI Image Labels
LABEL org.opencontainers.image.title="StellaOps Wine CSP Service" \
org.opencontainers.image.description="GOST cryptographic test vector generation via Wine-hosted CryptoPro CSP" \
org.opencontainers.image.vendor="StellaOps" \
org.opencontainers.image.source="https://git.stella-ops.org/stellaops/router" \
com.stellaops.component="wine-csp" \
com.stellaops.security.production-signing="false" \
com.stellaops.security.test-vectors-only="true"
# Wine CSP service configuration
ARG WINE_CSP_PORT=5099
ARG APP_USER=winecsp
ARG APP_UID=10001
ARG APP_GID=10001
ENV DEBIAN_FRONTEND=noninteractive \
# Wine configuration
WINEDEBUG=-all \
WINEPREFIX=/home/${APP_USER}/.wine \
WINEARCH=win64 \
# Service configuration
WINE_CSP_PORT=${WINE_CSP_PORT} \
ASPNETCORE_URLS=http://+:${WINE_CSP_PORT} \
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 \
# CSP configuration
WINE_CSP_MODE=limited \
WINE_CSP_INSTALLER_PATH=/opt/cryptopro/csp-installer.msi \
WINE_CSP_LOG_LEVEL=Information \
# Display for Wine (headless)
DISPLAY=:99
# Install Wine and dependencies
# Using WineHQ stable repository for consistent Wine version
RUN set -eux; \
dpkg --add-architecture i386; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
curl \
gnupg2 \
software-properties-common \
wget \
xvfb \
cabextract \
p7zip-full \
procps; \
# Add WineHQ repository key
mkdir -pm755 /etc/apt/keyrings; \
wget -O /etc/apt/keyrings/winehq-archive.key \
https://dl.winehq.org/wine-builds/winehq.key; \
# Add WineHQ repository
wget -NP /etc/apt/sources.list.d/ \
https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources; \
apt-get update; \
# Install Wine stable
apt-get install -y --no-install-recommends \
winehq-stable; \
# Install winetricks for runtime dependencies
wget -O /usr/local/bin/winetricks \
https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks; \
chmod +x /usr/local/bin/winetricks; \
# Cleanup
apt-get clean; \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Create non-root user for Wine service
# Note: Wine requires writable home directory for prefix
RUN groupadd -r -g ${APP_GID} ${APP_USER} && \
useradd -r -u ${APP_UID} -g ${APP_GID} -m -d /home/${APP_USER} -s /bin/bash ${APP_USER} && \
mkdir -p /app /opt/cryptopro /var/log/wine-csp /var/run/wine-csp && \
chown -R ${APP_UID}:${APP_GID} /app /home/${APP_USER} /opt/cryptopro /var/log/wine-csp /var/run/wine-csp
WORKDIR /app
# Copy application from build stage
COPY --from=build --chown=${APP_UID}:${APP_GID} /app/publish/ ./
# Copy supporting scripts
COPY --chown=${APP_UID}:${APP_GID} ops/wine-csp/entrypoint.sh /usr/local/bin/entrypoint.sh
COPY --chown=${APP_UID}:${APP_GID} ops/wine-csp/healthcheck.sh /usr/local/bin/healthcheck.sh
COPY --chown=${APP_UID}:${APP_GID} ops/wine-csp/install-csp.sh /usr/local/bin/install-csp.sh
RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/healthcheck.sh /usr/local/bin/install-csp.sh
# Switch to non-root user for Wine prefix initialization
USER ${APP_UID}:${APP_GID}
# Initialize Wine prefix (creates .wine directory with Windows environment)
# This must run as the app user to set correct ownership
# Using xvfb-run for headless Wine initialization
RUN set -eux; \
# Start virtual framebuffer and initialize Wine
xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" \
wine64 wineboot --init; \
wineserver --wait; \
# Install Visual C++ 2019 runtime via winetricks (required for .NET)
xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" \
winetricks -q vcrun2019 || true; \
wineserver --wait; \
# Set Windows version to Windows 10 for compatibility
wine64 reg add "HKCU\\Software\\Wine\\Version" /v Windows /d "win10" /f || true; \
wineserver --wait; \
# Cleanup Wine temp files
rm -rf /home/${APP_USER}/.cache/winetricks /tmp/.X* /tmp/winetricks* || true
EXPOSE ${WINE_CSP_PORT}
# Health check using custom script that probes /health endpoint
# Extended start_period due to Wine initialization time
HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --retries=3 \
CMD /usr/local/bin/healthcheck.sh
# Volumes for persistence and CSP installer
# - Wine prefix: stores CSP installation, certificates, keys
# - CSP installer: mount customer-provided CryptoPro MSI here
# - Logs: service logs
VOLUME ["/home/${APP_USER}/.wine", "/opt/cryptopro", "/var/log/wine-csp"]
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["wine64", "/app/WineCspService.exe"]

227
ops/wine-csp/entrypoint.sh Normal file
View File

@@ -0,0 +1,227 @@
#!/bin/bash
# Wine CSP Service Entrypoint
#
# Initializes Wine environment and starts the WineCspService under Wine.
# For TEST VECTOR GENERATION ONLY - not for production signing.
set -euo pipefail
# ------------------------------------------------------------------------------
# Configuration
# ------------------------------------------------------------------------------
WINE_CSP_PORT="${WINE_CSP_PORT:-5099}"
WINE_CSP_MODE="${WINE_CSP_MODE:-limited}"
WINE_CSP_INSTALLER_PATH="${WINE_CSP_INSTALLER_PATH:-/opt/cryptopro/csp-installer.msi}"
WINE_CSP_LOG_LEVEL="${WINE_CSP_LOG_LEVEL:-Information}"
WINE_PREFIX="${WINEPREFIX:-$HOME/.wine}"
DISPLAY="${DISPLAY:-:99}"
# Marker files
CSP_INSTALLED_MARKER="${WINE_PREFIX}/.csp_installed"
WINE_INITIALIZED_MARKER="${WINE_PREFIX}/.wine_initialized"
# Log prefix for structured logging
log() {
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] [entrypoint] $*"
}
log_error() {
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] [entrypoint] [ERROR] $*" >&2
}
# ------------------------------------------------------------------------------
# Virtual Framebuffer Management
# ------------------------------------------------------------------------------
start_xvfb() {
if ! pgrep -x Xvfb > /dev/null; then
log "Starting Xvfb virtual framebuffer on display ${DISPLAY}"
Xvfb "${DISPLAY}" -screen 0 1024x768x24 &
sleep 2
fi
}
stop_xvfb() {
if pgrep -x Xvfb > /dev/null; then
log "Stopping Xvfb"
pkill -x Xvfb || true
fi
}
# ------------------------------------------------------------------------------
# Wine Initialization
# ------------------------------------------------------------------------------
initialize_wine() {
if [[ -f "${WINE_INITIALIZED_MARKER}" ]]; then
log "Wine prefix already initialized"
return 0
fi
log "Initializing Wine prefix at ${WINE_PREFIX}"
start_xvfb
# Initialize Wine prefix
wine64 wineboot --init 2>/dev/null || true
wineserver --wait
# Set Windows version for CryptoPro compatibility
wine64 reg add "HKCU\\Software\\Wine\\Version" /v Windows /d "win10" /f 2>/dev/null || true
wineserver --wait
# Create marker
touch "${WINE_INITIALIZED_MARKER}"
log "Wine prefix initialized successfully"
}
# ------------------------------------------------------------------------------
# CryptoPro CSP Installation
# ------------------------------------------------------------------------------
install_cryptopro() {
# Check if already installed
if [[ -f "${CSP_INSTALLED_MARKER}" ]]; then
log "CryptoPro CSP already installed"
return 0
fi
# Check if installer is available
if [[ ! -f "${WINE_CSP_INSTALLER_PATH}" ]]; then
log "CryptoPro CSP installer not found at ${WINE_CSP_INSTALLER_PATH}"
log "Service will run in limited mode without CSP"
return 0
fi
log "Installing CryptoPro CSP from ${WINE_CSP_INSTALLER_PATH}"
start_xvfb
# Run the CSP installation script
if /usr/local/bin/install-csp.sh; then
touch "${CSP_INSTALLED_MARKER}"
log "CryptoPro CSP installed successfully"
else
log_error "CryptoPro CSP installation failed"
return 1
fi
}
# ------------------------------------------------------------------------------
# Service Configuration
# ------------------------------------------------------------------------------
configure_service() {
log "Configuring Wine CSP service"
log " Mode: ${WINE_CSP_MODE}"
log " Port: ${WINE_CSP_PORT}"
log " Log Level: ${WINE_CSP_LOG_LEVEL}"
# Configure Wine debug output based on log level
case "${WINE_CSP_LOG_LEVEL}" in
Trace|Debug)
export WINEDEBUG="warn+all"
;;
Information)
export WINEDEBUG="-all"
;;
Warning|Error|Critical)
export WINEDEBUG="-all"
;;
*)
export WINEDEBUG="-all"
;;
esac
# Set ASP.NET Core environment
export ASPNETCORE_URLS="http://+:${WINE_CSP_PORT}"
export ASPNETCORE_ENVIRONMENT="${ASPNETCORE_ENVIRONMENT:-Production}"
export Logging__LogLevel__Default="${WINE_CSP_LOG_LEVEL}"
# Check if CSP is available
if [[ -f "${CSP_INSTALLED_MARKER}" ]]; then
export WINE_CSP_CSP_AVAILABLE="true"
log "CryptoPro CSP is available"
else
export WINE_CSP_CSP_AVAILABLE="false"
log "Running without CryptoPro CSP (limited mode)"
fi
}
# ------------------------------------------------------------------------------
# Startup Validation
# ------------------------------------------------------------------------------
validate_environment() {
log "Validating environment"
# Check Wine is available
if ! command -v wine64 &> /dev/null; then
log_error "wine64 not found in PATH"
exit 1
fi
# Check application exists
if [[ ! -f "/app/WineCspService.exe" ]]; then
log_error "WineCspService.exe not found at /app/"
exit 1
fi
# Verify Wine prefix is writable
if [[ ! -w "${WINE_PREFIX}" ]]; then
log_error "Wine prefix ${WINE_PREFIX} is not writable"
exit 1
fi
log "Environment validation passed"
}
# ------------------------------------------------------------------------------
# Signal Handlers
# ------------------------------------------------------------------------------
cleanup() {
log "Received shutdown signal, cleaning up..."
# Stop Wine server gracefully
wineserver -k 15 2>/dev/null || true
sleep 2
wineserver -k 9 2>/dev/null || true
stop_xvfb
log "Cleanup complete"
exit 0
}
trap cleanup SIGTERM SIGINT SIGQUIT
# ------------------------------------------------------------------------------
# Main Entry Point
# ------------------------------------------------------------------------------
main() {
log "=========================================="
log "Wine CSP Service Entrypoint"
log "=========================================="
log "WARNING: For TEST VECTOR GENERATION ONLY"
log "=========================================="
validate_environment
initialize_wine
# Only attempt CSP installation in full mode
if [[ "${WINE_CSP_MODE}" == "full" ]]; then
install_cryptopro
fi
configure_service
# Start Xvfb for the main process
start_xvfb
log "Starting WineCspService..."
log "Listening on port ${WINE_CSP_PORT}"
# Execute the command passed to the container (or default)
if [[ $# -gt 0 ]]; then
exec "$@"
else
exec wine64 /app/WineCspService.exe
fi
}
main "$@"

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Wine CSP Service Health Check
#
# Probes the /health endpoint to determine if the service is healthy.
# Returns 0 (healthy) or 1 (unhealthy).
set -euo pipefail
WINE_CSP_PORT="${WINE_CSP_PORT:-5099}"
HEALTH_ENDPOINT="http://127.0.0.1:${WINE_CSP_PORT}/health"
TIMEOUT_SECONDS=8
# Perform health check
response=$(wget -q -O - --timeout="${TIMEOUT_SECONDS}" "${HEALTH_ENDPOINT}" 2>/dev/null) || exit 1
# Verify response contains expected status
if echo "${response}" | grep -q '"status":"Healthy"'; then
exit 0
elif echo "${response}" | grep -q '"status":"Degraded"'; then
# Degraded is acceptable (e.g., CSP not installed but service running)
exit 0
else
exit 1
fi

215
ops/wine-csp/install-csp.sh Normal file
View File

@@ -0,0 +1,215 @@
#!/bin/bash
# CryptoPro CSP Installation Script for Wine
#
# Installs customer-provided CryptoPro CSP MSI under Wine environment.
# This script is called by entrypoint.sh when CSP installer is available.
#
# IMPORTANT: CryptoPro CSP is commercial software. The installer MSI must be
# provided by the customer with appropriate licensing. StellaOps does not
# distribute CryptoPro CSP.
set -euo pipefail
# ------------------------------------------------------------------------------
# Configuration
# ------------------------------------------------------------------------------
WINE_CSP_INSTALLER_PATH="${WINE_CSP_INSTALLER_PATH:-/opt/cryptopro/csp-installer.msi}"
WINE_PREFIX="${WINEPREFIX:-$HOME/.wine}"
DISPLAY="${DISPLAY:-:99}"
# Expected CSP installation paths (under Wine prefix)
CSP_PROGRAM_FILES="${WINE_PREFIX}/drive_c/Program Files/Crypto Pro"
CSP_MARKER="${WINE_PREFIX}/.csp_installed"
CSP_VERSION_FILE="${WINE_PREFIX}/.csp_version"
# Installation timeout (5 minutes)
INSTALL_TIMEOUT=300
# Log prefix
log() {
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] [install-csp] $*"
}
log_error() {
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] [install-csp] [ERROR] $*" >&2
}
# ------------------------------------------------------------------------------
# Pre-Installation Checks
# ------------------------------------------------------------------------------
check_prerequisites() {
log "Checking installation prerequisites"
# Check installer exists
if [[ ! -f "${WINE_CSP_INSTALLER_PATH}" ]]; then
log_error "CSP installer not found: ${WINE_CSP_INSTALLER_PATH}"
return 1
fi
# Verify file is an MSI
if ! file "${WINE_CSP_INSTALLER_PATH}" | grep -qi "microsoft installer"; then
log_error "File does not appear to be an MSI installer"
return 1
fi
# Check Wine is available
if ! command -v wine64 &> /dev/null; then
log_error "wine64 not found"
return 1
fi
# Check Wine prefix exists
if [[ ! -d "${WINE_PREFIX}" ]]; then
log_error "Wine prefix not initialized: ${WINE_PREFIX}"
return 1
fi
log "Prerequisites check passed"
return 0
}
# ------------------------------------------------------------------------------
# Installation
# ------------------------------------------------------------------------------
install_csp() {
log "Starting CryptoPro CSP installation"
log "Installer: ${WINE_CSP_INSTALLER_PATH}"
# Create installation log directory
local log_dir="${WINE_PREFIX}/csp_install_logs"
mkdir -p "${log_dir}"
local install_log="${log_dir}/install_$(date -u '+%Y%m%d_%H%M%S').log"
# Run MSI installer silently
# /qn = silent mode, /norestart = don't restart, /l*v = verbose logging
log "Running msiexec installer (this may take several minutes)..."
timeout "${INSTALL_TIMEOUT}" wine64 msiexec /i "${WINE_CSP_INSTALLER_PATH}" \
/qn /norestart /l*v "${install_log}" \
AGREETOLICENSE=Yes \
2>&1 | tee -a "${install_log}" || {
local exit_code=$?
log_error "MSI installation failed with exit code: ${exit_code}"
log_error "Check installation log: ${install_log}"
return 1
}
# Wait for Wine to finish
wineserver --wait
log "MSI installation completed"
return 0
}
# ------------------------------------------------------------------------------
# Post-Installation Verification
# ------------------------------------------------------------------------------
verify_installation() {
log "Verifying CryptoPro CSP installation"
# Check for CSP program files
if [[ -d "${CSP_PROGRAM_FILES}" ]]; then
log "Found CSP directory: ${CSP_PROGRAM_FILES}"
else
log_error "CSP program directory not found"
return 1
fi
# Check for key CSP DLLs
local csp_dll="${WINE_PREFIX}/drive_c/windows/system32/cpcspi.dll"
if [[ -f "${csp_dll}" ]]; then
log "Found CSP DLL: ${csp_dll}"
else
log "Warning: CSP DLL not found at expected location"
# This might be OK depending on CSP version
fi
# Try to query CSP registry entries
local csp_registry
csp_registry=$(wine64 reg query "HKLM\\SOFTWARE\\Crypto Pro" 2>/dev/null || true)
if [[ -n "${csp_registry}" ]]; then
log "CSP registry entries found"
else
log "Warning: CSP registry entries not found"
fi
# Extract version if possible
local version="unknown"
if [[ -f "${CSP_PROGRAM_FILES}/CSP/version.txt" ]]; then
version=$(cat "${CSP_PROGRAM_FILES}/CSP/version.txt" 2>/dev/null || echo "unknown")
fi
echo "${version}" > "${CSP_VERSION_FILE}"
log "CSP version: ${version}"
log "Installation verification completed"
return 0
}
# ------------------------------------------------------------------------------
# Cleanup on Failure
# ------------------------------------------------------------------------------
cleanup_failed_install() {
log "Cleaning up failed installation"
# Try to uninstall via msiexec
wine64 msiexec /x "${WINE_CSP_INSTALLER_PATH}" /qn 2>/dev/null || true
wineserver --wait
# Remove any partial installation directories
rm -rf "${CSP_PROGRAM_FILES}" 2>/dev/null || true
# Remove marker files
rm -f "${CSP_MARKER}" "${CSP_VERSION_FILE}" 2>/dev/null || true
log "Cleanup completed"
}
# ------------------------------------------------------------------------------
# Main
# ------------------------------------------------------------------------------
main() {
log "=========================================="
log "CryptoPro CSP Installation Script"
log "=========================================="
# Check if already installed
if [[ -f "${CSP_MARKER}" ]]; then
log "CryptoPro CSP is already installed"
if [[ -f "${CSP_VERSION_FILE}" ]]; then
log "Installed version: $(cat "${CSP_VERSION_FILE}")"
fi
return 0
fi
# Run prerequisite checks
if ! check_prerequisites; then
log_error "Prerequisites check failed"
return 1
fi
# Perform installation
if ! install_csp; then
log_error "Installation failed"
cleanup_failed_install
return 1
fi
# Verify installation
if ! verify_installation; then
log_error "Installation verification failed"
cleanup_failed_install
return 1
fi
# Create installation marker
touch "${CSP_MARKER}"
log "=========================================="
log "CryptoPro CSP installation successful"
log "=========================================="
return 0
}
main "$@"