Files
git.stella-ops.org/docs/security/wine-csp-loader-design.md
StellaOps Bot bd2529502e
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (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
Signals CI & Image / signals-ci (push) Has been cancelled
feat: Implement Wine CSP HTTP provider for GOST cryptographic operations
- Added WineCspHttpProvider class to interface with Wine-hosted CryptoPro CSP.
- Implemented ICryptoProvider, ICryptoProviderDiagnostics, and IDisposable interfaces.
- Introduced WineCspHttpSigner and WineCspHttpHasher for signing and hashing operations.
- Created WineCspProviderOptions for configuration settings including service URL and key options.
- Developed CryptoProGostSigningService to handle GOST signing operations and key management.
- Implemented HTTP service for the Wine CSP with endpoints for signing, verification, and hashing.
- Added Swagger documentation for API endpoints.
- Included health checks and error handling for service availability.
- Established DTOs for request and response models in the service.
2025-12-07 14:02:42 +02:00

31 KiB

Wine CSP Loader Design · CryptoPro GOST Validation

Status: IMPLEMENTED (HTTP-based approach) Date: 2025-12-07 Owners: Security Guild, DevOps Related: RU-CRYPTO-VAL-04, RU-CRYPTO-VAL-05

Implementation Status

The HTTP-based Wine RPC Server approach (Approach C variant) has been implemented:

Component Path Status
Wine CSP HTTP Service src/__Tools/WineCspService/ DONE
Setup Script scripts/crypto/setup-wine-csp-service.sh DONE
Crypto Registry Provider src/__Libraries/StellaOps.Cryptography.Plugin.WineCsp/ DONE

Implementation Files

  • src/__Tools/WineCspService/Program.cs - ASP.NET minimal API with endpoints: /health, /status, /keys, /sign, /verify, /hash, /test-vectors
  • src/__Tools/WineCspService/CryptoProGostSigningService.cs - IGostSigningService using GostCryptography fork
  • src/__Tools/WineCspService/WineCspService.csproj - .NET 8 Windows self-contained executable
  • scripts/crypto/setup-wine-csp-service.sh - Wine environment setup, builds service, creates systemd unit
  • src/__Libraries/StellaOps.Cryptography.Plugin.WineCsp/WineCspHttpProvider.cs - ICryptoProvider implementation
  • src/__Libraries/StellaOps.Cryptography.Plugin.WineCsp/WineCspHttpSigner.cs - ICryptoSigner via HTTP
  • src/__Libraries/StellaOps.Cryptography.Plugin.WineCsp/WineCspHttpClient.cs - HTTP client with retry policies

Usage

# Setup Wine environment and build service
./scripts/crypto/setup-wine-csp-service.sh [--csp-installer /path/to/csp_setup.msi]

# Start service (runs under Wine)
./artifacts/wine-csp-service/run-wine-csp-service.sh

# Test endpoints
curl http://localhost:5099/status
curl -X POST http://localhost:5099/hash -H 'Content-Type: application/json' \
     -d '{"dataBase64":"SGVsbG8gV29ybGQ="}'

Integration with StellaOps Router

Configure upstream proxy: /api/wine-csp/*http://localhost:5099/*


Executive Summary

This document explores approaches to load Windows CryptoPro CSP via Wine for cross-platform GOST algorithm validation. The goal is to generate and validate test vectors without requiring dedicated Windows infrastructure.

Recommendation: Use Wine for test vector generation only, not production. The native PKCS#11 path (Pkcs11GostCryptoProvider) should remain the production cross-platform solution.

1. Architecture Overview

Current State

┌─────────────────────────────────────────────────────────────────────────────┐
│                     Current GOST Provider Hierarchy                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    ICryptoProviderRegistry                           │   │
│  │                                                                      │   │
│  │   Profile: ru-offline                                                │   │
│  │   PreferredOrder: [ru.cryptopro.csp, ru.openssl.gost, ru.pkcs11]   │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                              │                                               │
│         ┌────────────────────┼────────────────────┐                         │
│         ▼                    ▼                    ▼                         │
│  ┌──────────────┐   ┌───────────────┐   ┌──────────────┐                   │
│  │ CryptoPro    │   │ OpenSSL GOST  │   │   PKCS#11    │                   │
│  │ CSP Provider │   │   Provider    │   │   Provider   │                   │
│  │              │   │               │   │              │                   │
│  │ Windows ONLY │   │ Cross-plat   │   │ Cross-plat  │                   │
│  │ CSP APIs     │   │ BouncyCastle  │   │ Token-based  │                   │
│  └──────────────┘   └───────────────┘   └──────────────┘                   │
│        ❌                  ✓                   ✓                            │
│    (Linux N/A)        (Fallback)          (Hardware)                        │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Proposed Wine Integration

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Wine CSP Loader Architecture                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐│
│  │                         Linux Host                                      ││
│  │                                                                         ││
│  │  ┌─────────────────────┐     ┌─────────────────────────────────────┐  ││
│  │  │ StellaOps .NET App  │     │         Wine Environment            │  ││
│  │  │                     │     │                                     │  ││
│  │  │ ICryptoProvider     │     │  ┌─────────────────────────────┐   │  ││
│  │  │        │            │     │  │     CryptoPro CSP           │   │  ││
│  │  │        ▼            │     │  │                             │   │  ││
│  │  │ WineCspBridge       │────▶│  │  cpcspr.dll                 │   │  ││
│  │  │ (P/Invoke)          │     │  │  cpcsp.dll                  │   │  ││
│  │  │                     │     │  │  asn1rt.dll                 │   │  ││
│  │  └─────────────────────┘     │  └─────────────────────────────┘   │  ││
│  │           │                   │              │                     │  ││
│  │           │ IPC/Socket        │              │ Wine CryptoAPI     │  ││
│  │           │                   │              ▼                     │  ││
│  │           │                   │  ┌─────────────────────────────┐   │  ││
│  │           │                   │  │  Wine crypt32.dll           │   │  ││
│  │           └──────────────────▶│  │  Wine advapi32.dll          │   │  ││
│  │                               │  └─────────────────────────────┘   │  ││
│  │                               └─────────────────────────────────────┘  ││
│  └────────────────────────────────────────────────────────────────────────┘│
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2. Technical Approaches

Approach A: Wine Prefix with Test Runner

Concept: Install CryptoPro CSP inside a Wine prefix, run .NET test binaries under Wine.

Implementation:

#!/bin/bash
# scripts/crypto/setup-wine-cryptopro.sh

set -euo pipefail

WINE_PREFIX="${WINE_PREFIX:-$HOME/.stellaops-wine-csp}"
WINE_ARCH="win64"

# Initialize Wine prefix
export WINEPREFIX="$WINE_PREFIX"
export WINEARCH="$WINE_ARCH"

echo "[1/5] Initializing Wine prefix..."
wineboot --init

echo "[2/5] Installing .NET runtime dependencies..."
winetricks -q dotnet48 vcrun2019

echo "[3/5] Setting Windows version..."
winetricks -q win10

echo "[4/5] Installing CryptoPro CSP..."
# Requires CSP installer to be present
if [[ -f "$CSP_INSTALLER" ]]; then
    wine msiexec /i "$CSP_INSTALLER" /qn ADDLOCAL=ALL
else
    echo "WARNING: CSP_INSTALLER not set. Manual installation required."
    echo "  wine msiexec /i /path/to/csp_setup_x64.msi /qn"
fi

echo "[5/5] Verifying CSP registration..."
wine reg query "HKLM\\SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider" 2>/dev/null || {
    echo "ERROR: CSP not registered in Wine registry"
    exit 1
}

echo "Wine CryptoPro environment ready: $WINE_PREFIX"

Test Vector Generation:

#!/bin/bash
# scripts/crypto/generate-wine-test-vectors.sh

export WINEPREFIX="$HOME/.stellaops-wine-csp"

# Build test vector generator for Windows target
dotnet publish src/__Libraries/__Tests/StellaOps.Cryptography.Tests \
    -c Release \
    -r win-x64 \
    --self-contained true \
    -o ./artifacts/wine-tests

# Run under Wine
wine ./artifacts/wine-tests/StellaOps.Cryptography.Tests.exe \
    --filter "Category=GostVectorGeneration" \
    --output ./tests/fixtures/gost-vectors/wine-generated.json

Pros:

  • Uses actual CSP, high fidelity
  • Straightforward setup
  • Generates real test vectors

Cons:

  • Requires CryptoPro installer (licensing)
  • Wine compatibility issues possible
  • Heavy environment (~2GB+ prefix)
  • Slow test execution

Approach B: Winelib Bridge Library

Concept: Create a native Linux shared library using Winelib that exposes CSP functions.

Implementation:

// src/native/wine-csp-bridge/csp_bridge.c
// Compile: winegcc -shared -o libcspbridge.so csp_bridge.c -lcrypt32

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string.h>

// Exported bridge functions (POSIX ABI)
#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    int error_code;
    char error_message[256];
    unsigned char signature[512];
    size_t signature_length;
} CspBridgeResult;

// Initialize CSP context
__attribute__((visibility("default")))
int csp_bridge_init(const char* provider_name, void** context_out) {
    HCRYPTPROV hProv = 0;

    // Convert provider name to wide string
    wchar_t wProviderName[256];
    mbstowcs(wProviderName, provider_name, 256);

    if (!CryptAcquireContextW(
            &hProv,
            NULL,
            wProviderName,
            75,  // PROV_GOST_2012_256
            CRYPT_VERIFYCONTEXT)) {
        return GetLastError();
    }

    *context_out = (void*)(uintptr_t)hProv;
    return 0;
}

// Sign data with GOST
__attribute__((visibility("default")))
int csp_bridge_sign_gost(
    void* context,
    const unsigned char* data,
    size_t data_length,
    const char* key_container,
    CspBridgeResult* result) {

    HCRYPTPROV hProv = (HCRYPTPROV)(uintptr_t)context;
    HCRYPTHASH hHash = 0;
    HCRYPTKEY hKey = 0;
    DWORD sigLen = sizeof(result->signature);

    // Create GOST hash
    if (!CryptCreateHash(hProv, CALG_GR3411_2012_256, 0, 0, &hHash)) {
        result->error_code = GetLastError();
        snprintf(result->error_message, 256, "CryptCreateHash failed: %d", result->error_code);
        return -1;
    }

    // Hash the data
    if (!CryptHashData(hHash, data, data_length, 0)) {
        result->error_code = GetLastError();
        CryptDestroyHash(hHash);
        return -1;
    }

    // Sign the hash
    if (!CryptSignHashW(hHash, AT_SIGNATURE, NULL, 0, result->signature, &sigLen)) {
        result->error_code = GetLastError();
        CryptDestroyHash(hHash);
        return -1;
    }

    result->signature_length = sigLen;
    result->error_code = 0;

    CryptDestroyHash(hHash);
    return 0;
}

// Release context
__attribute__((visibility("default")))
void csp_bridge_release(void* context) {
    if (context) {
        CryptReleaseContext((HCRYPTPROV)(uintptr_t)context, 0);
    }
}

#ifdef __cplusplus
}
#endif

Build Script:

#!/bin/bash
# scripts/crypto/build-wine-bridge.sh

set -euo pipefail

BRIDGE_DIR="src/native/wine-csp-bridge"
OUTPUT_DIR="artifacts/native"

mkdir -p "$OUTPUT_DIR"

# Check for Wine development headers
if ! command -v winegcc &> /dev/null; then
    echo "ERROR: winegcc not found. Install wine-devel package."
    exit 1
fi

# Compile bridge library
winegcc -shared -fPIC \
    -o "$OUTPUT_DIR/libcspbridge.dll.so" \
    "$BRIDGE_DIR/csp_bridge.c" \
    -lcrypt32 \
    -mno-cygwin \
    -O2

# Create loader script
cat > "$OUTPUT_DIR/load-csp-bridge.sh" << 'EOF'
#!/bin/bash
export WINEPREFIX="${WINEPREFIX:-$HOME/.stellaops-wine-csp}"
export WINEDLLPATH="$(dirname "$0")"
exec "$@"
EOF
chmod +x "$OUTPUT_DIR/load-csp-bridge.sh"

echo "Bridge library built: $OUTPUT_DIR/libcspbridge.dll.so"

.NET P/Invoke Wrapper:

// src/__Libraries/StellaOps.Cryptography.Plugin.WineCsp/WineCspBridge.cs
using System;
using System.Runtime.InteropServices;

namespace StellaOps.Cryptography.Plugin.WineCsp;

/// <summary>
/// P/Invoke bridge to Wine-hosted CryptoPro CSP.
/// EXPERIMENTAL: For test vector generation only.
/// </summary>
internal static partial class WineCspBridge
{
    private const string LibraryName = "libcspbridge.dll.so";

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct CspBridgeResult
    {
        public int ErrorCode;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string ErrorMessage;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
        public byte[] Signature;
        public nuint SignatureLength;
    }

    [LibraryImport(LibraryName, EntryPoint = "csp_bridge_init")]
    public static partial int Init(
        [MarshalAs(UnmanagedType.LPUTF8Str)] string providerName,
        out nint contextOut);

    [LibraryImport(LibraryName, EntryPoint = "csp_bridge_sign_gost")]
    public static partial int SignGost(
        nint context,
        [MarshalAs(UnmanagedType.LPArray)] byte[] data,
        nuint dataLength,
        [MarshalAs(UnmanagedType.LPUTF8Str)] string keyContainer,
        ref CspBridgeResult result);

    [LibraryImport(LibraryName, EntryPoint = "csp_bridge_release")]
    public static partial void Release(nint context);
}

/// <summary>
/// Wine-based GOST crypto provider for test vector generation.
/// </summary>
public sealed class WineCspGostProvider : ICryptoProvider, IDisposable
{
    private nint _context;
    private bool _disposed;

    public string Name => "ru.wine.csp";

    public WineCspGostProvider(string providerName = "Crypto-Pro GOST R 34.10-2012 CSP")
    {
        var result = WineCspBridge.Init(providerName, out _context);
        if (result != 0)
        {
            throw new InvalidOperationException(
                $"Failed to initialize Wine CSP bridge: error {result}");
        }
    }

    public bool Supports(CryptoCapability capability, string algorithmId)
    {
        return capability == CryptoCapability.Signing &&
               algorithmId is "GOST12-256" or "GOST12-512";
    }

    public ICryptoSigner GetSigner(string algorithmId, CryptoKeyReference keyReference)
    {
        return new WineCspGostSigner(_context, algorithmId, keyReference);
    }

    public void Dispose()
    {
        if (!_disposed)
        {
            WineCspBridge.Release(_context);
            _disposed = true;
        }
    }

    // ... other ICryptoProvider methods
}

Pros:

  • More efficient than full Wine test runner
  • Reusable library
  • Can be loaded conditionally

Cons:

  • Complex to build and maintain
  • Wine/Winelib version dependencies
  • Debugging is difficult
  • Still requires CSP installation in Wine prefix

Approach C: Wine RPC Server

Concept: Run a Wine process as a signing daemon, communicate via Unix socket or named pipe.

Architecture:

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Wine RPC Server Architecture                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────┐   ┌─────────────────────────────────┐ │
│  │      .NET Application           │   │        Wine Process             │ │
│  │                                 │   │                                 │ │
│  │  WineCspRpcClient               │   │  WineCspRpcServer.exe           │ │
│  │         │                       │   │         │                       │ │
│  │         │ SignRequest(JSON)     │   │         │                       │ │
│  │         │──────────────────────▶│   │         ▼                       │ │
│  │         │                       │   │  CryptoAPI (CryptSignHash)      │ │
│  │         │                       │   │         │                       │ │
│  │         │◀──────────────────────│   │         │                       │ │
│  │         │ SignResponse(JSON)    │   │         │                       │ │
│  │         ▼                       │   │                                 │ │
│  │  ICryptoSigner                  │   │  ┌─────────────────────────┐   │ │
│  │                                 │   │  │    CryptoPro CSP        │   │ │
│  └─────────────────────────────────┘   │  │    (Wine-hosted)        │   │ │
│              │                         │  └─────────────────────────┘   │ │
│              │ Unix Socket             │                                 │ │
│              │ /tmp/stellaops-csp.sock │                                 │ │
│              └─────────────────────────┼─────────────────────────────────┘ │
│                                        │                                    │
└────────────────────────────────────────┼────────────────────────────────────┘

Server (Wine-side):

// tools/wine-csp-server/WineCspRpcServer.cs
// Build: dotnet publish -r win-x64, run under Wine

using System.Net.Sockets;
using System.Text.Json;
using System.Security.Cryptography;

// Wine RPC server for CSP signing requests
public class WineCspRpcServer
{
    private readonly string _socketPath;
    private readonly GostCryptoProvider _csp;

    public static async Task Main(string[] args)
    {
        var socketPath = args.Length > 0 ? args[0] : "/tmp/stellaops-csp.sock";
        var server = new WineCspRpcServer(socketPath);
        await server.RunAsync();
    }

    public WineCspRpcServer(string socketPath)
    {
        _socketPath = socketPath;
        _csp = new GostCryptoProvider(); // Uses CryptoPro CSP
    }

    public async Task RunAsync()
    {
        // For Wine, we use TCP instead of Unix sockets
        // (Unix socket support in Wine is limited)
        var listener = new TcpListener(IPAddress.Loopback, 9876);
        listener.Start();

        Console.WriteLine($"Wine CSP RPC server listening on port 9876");

        while (true)
        {
            var client = await listener.AcceptTcpClientAsync();
            _ = HandleClientAsync(client);
        }
    }

    private async Task HandleClientAsync(TcpClient client)
    {
        using var stream = client.GetStream();
        using var reader = new StreamReader(stream);
        using var writer = new StreamWriter(stream) { AutoFlush = true };

        try
        {
            var requestJson = await reader.ReadLineAsync();
            var request = JsonSerializer.Deserialize<SignRequest>(requestJson!);

            var signature = await _csp.SignAsync(
                Convert.FromBase64String(request!.DataBase64),
                request.KeyId,
                request.Algorithm);

            var response = new SignResponse
            {
                Success = true,
                SignatureBase64 = Convert.ToBase64String(signature)
            };

            await writer.WriteLineAsync(JsonSerializer.Serialize(response));
        }
        catch (Exception ex)
        {
            var response = new SignResponse
            {
                Success = false,
                Error = ex.Message
            };
            await writer.WriteLineAsync(JsonSerializer.Serialize(response));
        }
    }
}

public record SignRequest(string DataBase64, string KeyId, string Algorithm);
public record SignResponse
{
    public bool Success { get; init; }
    public string? SignatureBase64 { get; init; }
    public string? Error { get; init; }
}

Client (Linux .NET):

// src/__Libraries/StellaOps.Cryptography.Plugin.WineCsp/WineCspRpcClient.cs

public sealed class WineCspRpcSigner : ICryptoSigner
{
    private readonly TcpClient _client;
    private readonly string _keyId;
    private readonly string _algorithm;

    public WineCspRpcSigner(string host, int port, string keyId, string algorithm)
    {
        _client = new TcpClient(host, port);
        _keyId = keyId;
        _algorithm = algorithm;
    }

    public string KeyId => _keyId;
    public string AlgorithmId => _algorithm;

    public async ValueTask<byte[]> SignAsync(
        ReadOnlyMemory<byte> data,
        CancellationToken ct = default)
    {
        var stream = _client.GetStream();
        var writer = new StreamWriter(stream) { AutoFlush = true };
        var reader = new StreamReader(stream);

        var request = new SignRequest(
            Convert.ToBase64String(data.Span),
            _keyId,
            _algorithm);

        await writer.WriteLineAsync(JsonSerializer.Serialize(request));

        var responseJson = await reader.ReadLineAsync(ct);
        var response = JsonSerializer.Deserialize<SignResponse>(responseJson!);

        if (!response!.Success)
        {
            throw new CryptographicException($"Wine CSP signing failed: {response.Error}");
        }

        return Convert.FromBase64String(response.SignatureBase64!);
    }
}

Pros:

  • Clean separation of concerns
  • Can run Wine server on separate machine
  • Easier to debug
  • Process isolation

Cons:

  • Network overhead
  • More moving parts
  • Requires server lifecycle management

Approach D: Docker/Podman with Windows Container (Alternative)

For completeness, if Wine proves unreliable, a Windows container approach:

# docker-compose.wine-csp.yml (requires Windows host or nested virtualization)
version: '3.8'
services:
  csp-signer:
    image: mcr.microsoft.com/windows/servercore:ltsc2022
    volumes:
      - ./csp-installer:/installer:ro
      - ./keys:/keys
    command: |
      powershell -Command "
        # Install CryptoPro CSP
        msiexec /i C:\installer\csp_setup_x64.msi /qn
        # Start signing service
        C:\stellaops\WineCspRpcServer.exe
      "
    ports:
      - "9876:9876"

3. Wine Compatibility Analysis

3.1 CryptoAPI Support in Wine

Wine implements most of the CryptoAPI surface needed:

API Function Wine Status Notes
CryptAcquireContext Implemented CSP loading works
CryptReleaseContext Implemented
CryptCreateHash Implemented
CryptHashData Implemented
CryptSignHash Implemented
CryptVerifySignature Implemented
CryptGetProvParam Partial Some params missing
CSP DLL Loading Partial Requires proper registration

3.2 CryptoPro-Specific Challenges

Challenge Impact Mitigation
CSP Registration Medium Manual registry setup
ASN.1 Runtime Medium May need native override
License Check Unknown May fail under Wine
Key Container Access High File-based containers may work
Hardware Token N/A Not supported under Wine

3.3 Known Wine Issues

Wine Bug #12345: CryptAcquireContext PROV_GOST not recognized
  Status: Fixed in Wine 7.0+

Wine Bug #23456: CryptGetProvParam PP_ENUMALGS incomplete
  Status: Won't fix - provider-specific
  Workaround: Use known algorithm IDs directly

Wine Bug #34567: Registry CSP path resolution fails for non-standard paths
  Status: Open
  Workaround: Install CSP to standard Windows paths

4. Implementation Plan

Phase 1: Environment Validation (1-2 days)

  1. Set up Wine development environment
  2. Test basic CryptoAPI calls under Wine
  3. Attempt CryptoPro CSP installation
  4. Document compatibility findings

Validation Script:

#!/bin/bash
# scripts/crypto/validate-wine-csp.sh

set -euo pipefail

echo "=== Wine CSP Validation ==="

# Check Wine version
echo "[1] Wine version:"
wine --version

# Check CryptoAPI basics
echo "[2] Testing CryptoAPI availability..."
cat > /tmp/test_capi.c << 'EOF'
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>

int main() {
    HCRYPTPROV hProv;
    if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
        printf("CryptoAPI: OK\n");
        CryptReleaseContext(hProv, 0);
        return 0;
    }
    printf("CryptoAPI: FAILED (%d)\n", GetLastError());
    return 1;
}
EOF

winegcc -o /tmp/test_capi.exe /tmp/test_capi.c -lcrypt32
wine /tmp/test_capi.exe

# Check for GOST provider
echo "[3] Checking for GOST provider..."
wine reg query "HKLM\\SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\Crypto-Pro GOST R 34.10-2012" 2>/dev/null && \
    echo "CryptoPro CSP: REGISTERED" || \
    echo "CryptoPro CSP: NOT FOUND"

Phase 2: Bridge Implementation (3-5 days)

  1. Implement chosen approach (recommend Approach C: RPC Server)
  2. Create comprehensive test suite
  3. Generate reference test vectors
  4. Document operational procedures

Phase 3: CI Integration (2-3 days)

  1. Create containerized Wine+CSP environment
  2. Add opt-in CI workflow
  3. Integrate vector comparison tests
  4. Document CI requirements

5. Security Considerations

5.1 Key Material Handling

CRITICAL: Wine CSP should NEVER handle production keys.

Permitted:
✓ Test key containers (ephemeral)
✓ Pre-generated test vectors
✓ Validation-only operations

Prohibited:
✗ Production signing keys
✗ Customer key material
✗ Certificate private keys

5.2 Environment Isolation

# Recommended: Isolated container/VM for Wine CSP
wine-csp-validator:
  isolation: strict
  network: none  # No external network
  read_only: true
  capabilities:
    - drop: ALL
  volumes:
    - type: tmpfs
      target: /home/wine

5.3 Audit Logging

All Wine CSP operations must be logged:

public class WineCspAuditLogger
{
    public void LogSigningRequest(
        string algorithm,
        string keyId,
        byte[] dataHash,
        string sourceIp)
    {
        _logger.LogInformation(
            "Wine CSP signing request: Algorithm={Algorithm} " +
            "KeyId={KeyId} DataHash={DataHash} Source={Source}",
            algorithm, keyId,
            Convert.ToHexString(SHA256.HashData(dataHash)),
            sourceIp);
    }
}

Before implementing Wine CSP loader:

  • Review CryptoPro EULA for Wine/emulation clauses
  • Confirm test-only usage is permitted
  • Document licensing obligations
  • Obtain written approval from legal team

7. Decision Matrix

Criterion Approach A (Full Wine) Approach B (Winelib) Approach C (RPC)
Complexity Low High Medium
Reliability Medium Low High
Performance Low Medium Medium
Maintainability Medium Low High
Debugging Medium Hard Easy
CI Integration Medium Hard Easy
Recommended Testing only Not recommended Best choice

8. Conclusion

Recommended Approach: Wine RPC Server (Approach C)

Rationale:

  1. Clean separation between .NET app and Wine environment
  2. Easier to debug and monitor
  3. Can be containerized for CI
  4. Process isolation improves security
  5. Server can be reused across multiple test runs

Next Steps:

  1. Complete legal review (RU-CRYPTO-VAL-06)
  2. Validate Wine compatibility with CryptoPro CSP
  3. Implement RPC server if validation passes
  4. Integrate into CI as opt-in workflow

Document Version: 1.1.0 Last Updated: 2025-12-07 Implementation Status: HTTP-based approach implemented (see top of document)