Remote OpenSSL GOST Signer (OSS) · 2025-12-11

A portable, open-source recipe for signing with GOST R 34.10/34.11 using the rnix/openssl-gost image, for operators who need GOST signing where CryptoPro CSP is unavailable. It pairs with the in-process local GOST provider (ru.openssl.gost), which is the shipping component; the remote HTTP/TCP gateway here is a draft operator recipe, not a platform-integrated service — read the status banner before relying on it.

For GOST key configuration and the RootPack validation flow, see rootpack_ru_validation.md and crypto-compliance.md.

Status (verified against src/ on 2026-05-30). The local OpenSSL/Bouncy GOST provider (ru.openssl.gost) is fully implemented — see Implemented today: local provider. The remote HTTP gateway described in the Quickstart/Client sections and the STELLAOPS_RU_OPENSSL_REMOTE_URL toggle are a Draft / roadmap operator recipe only: no code under src/__Libraries/StellaOps.Cryptography.Plugin.OpenSslGost reads STELLAOPS_RU_OPENSSL_REMOTE_URL or routes ru.openssl.gost signing over the network. The shell snippets below are a manual, copy-paste illustration, not a shipped component. Do not assume the platform will dispatch signing to a remote host automatically.

Goals

Quickstart (remote host) · Draft recipe

Manual operator recipe — not a shipped service. The signature wire protocol below is raw TCP carrying a single JSON line via netcat, not HTTP, despite the curl in the client section (a quirk of this illustration). Note also that the gateway listens on 9090 (nc -l -p 9090); the -p 8088:8080 published port on the container is unrelated and unused by the gateway.

# 1) Run the OpenSSL GOST container on the remote host
docker run --rm -p 8088:8080 --name gost-remote rnix/openssl-gost:latest sleep 365d

# 2) Start the lightweight gateway (one-liner, no deps; raw TCP + JSON, not HTTP)
cat > /tmp/gost-remote.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
msg_file="$(mktemp)"
sig_file="$(mktemp)"
pub_file="$(mktemp)"
trap 'rm -f "$msg_file" "$sig_file" "$pub_file"' EXIT

while true; do
  # Simple netcat JSON protocol: {"message_b64":"..."}
  nc -l -p 9090 -q 1 | {
    read payload
    msg_b64="$(echo "$payload" | jq -r .message_b64)"
    echo "$msg_b64" | base64 -d > "$msg_file"
    # Generate key once per container (persist by volume if desired)
    if [ ! -f /tmp/gost.key.pem ]; then
      openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:A -out /tmp/gost.key.pem >/dev/null
      openssl pkey -engine gost -in /tmp/gost.key.pem -pubout -out /tmp/gost.pub.pem >/dev/null
    fi
    # Sign (nonce-driven, signatures differ each call)
    openssl dgst -engine gost -md_gost12_256 -sign /tmp/gost.key.pem -out "$sig_file" "$msg_file"
    # Respond with signature/public key (base64)
    jq -n --arg sig_b64 "$(base64 -w0 "$sig_file")" \
          --arg pub_pem "$(base64 -w0 /tmp/gost.pub.pem)" \
          '{signature_b64:$sig_b64, public_key_pem_b64:$pub_pem}'
  }
done
EOF
chmod +x /tmp/gost-remote.sh
/tmp/gost-remote.sh

Client invocation (any host) · Draft recipe

The gateway speaks raw TCP, so curl works only because it sends the request line/body and the gateway ignores HTTP framing and reads the first line as JSON. Treat this as a smoke-test convenience, not a stable protocol.

MESSAGE="stellaops-remote-gost-smoke"
curl -s -X POST http://REMOTE_HOST:9090 \
  -d "{\"message_b64\":\"$(printf '%s' \"$MESSAGE\" | base64 -w0)\"}" \
  | tee /tmp/gost-remote-response.json

sig_b64=$(jq -r .signature_b64 /tmp/gost-remote-response.json)
pub_pem_b64=$(jq -r .public_key_pem_b64 /tmp/gost-remote-response.json)
printf '%s' "$pub_pem_b64" | base64 -d > /tmp/gost-remote.pub.pem
printf '%s' "$MESSAGE" > /tmp/gost-remote.msg
printf '%s' "$sig_b64" | base64 -d > /tmp/gost-remote.sig

# Verify locally
openssl dgst -engine gost -md_gost12_256 \
  -verify /tmp/gost-remote.pub.pem \
  -signature /tmp/gost-remote.sig /tmp/gost-remote.msg

Configuration toggle (Draft / NOT IMPLEMENTED)

Implemented today: local provider

The shipping component is the in-process provider OpenSslGostProvider (Name = "ru.openssl.gost") in src/__Libraries/StellaOps.Cryptography.Plugin.OpenSslGost. Register it with services.AddOpenSslGostProvider(...) (OpenSslCryptoServiceCollectionExtensions).

Determinism

Operational notes

Attach to sprint evidence