Sign inSign up

dimahkiin/cryptopro-extract-service

By dimahkiin

•Updated 9 months ago

HTTP API for extracting keys from CryptoPro containers and GOST R 34.10-2012 CMS signing

Image
Security
Integration & delivery
Developer tools
0

553

dimahkiin/cryptopro-extract-service repository overview

⁠dimahkiin/cryptopro-extract-service

HTTP API that extracts a GOST private key, public key and certificate from a CryptoPro CSP key container, and signs arbitrary messages as CMS/PKCS#7 SignedData using GOST R 34.10-2012 (256-bit) with Streebog-256 hashing. Implemented in pure Go - no CryptoPro CSP installation and no patched OpenSSL required. Intended for ESIA (Russian government SSO) OAuth clients that must sign the client_secret string.

Source code: https://github.com/LdDl/esia-potato⁠

⁠Configuration

No config file and no application environment variables - the server is configured by two command-line flags appended after the image name:

FlagDefaultMeaning
-host0.0.0.0Listen address
-port8080Listen port

The default 0.0.0.0 is already correct for a container; if you pass -host 127.0.0.1, the published port will not be reachable from the host.

Minimal working example:

docker run -d --name cryptopro-extract-service -p 8080:8080 --tmpfs /tmp \
  dimahkiin/cryptopro-extract-service:latest

--tmpfs /tmp is required. The image is built FROM scratch, so it has no /tmp directory; POST /api/v1/extract unpacks the uploaded archive into a temp directory and fails with 500 {"error":"failed to create temp dir"} without a writable temp location. Alternatively point the temp directory at the (writable) working directory with -e TMPDIR=/app.

Logs are structured JSON on stdout.

⁠Usage

docker run -d --name cryptopro-extract-service \
  -p 8080:8080 \
  --tmpfs /tmp \
  --read-only \
  dimahkiin/cryptopro-extract-service:latest

The service keeps no state and writes nothing outside the temp directory, so --read-only works as long as --tmpfs /tmp is present. No volume is needed: containers are uploaded over HTTP, not mounted.

Health check:

curl http://localhost:8080/health
# {"status":"ok"}

Extract a key. container.zip must contain the CryptoPro container directory with header.key, masks.key and primary.key; certificate.cer, if present, is returned as base64. Accepted archive formats are .zip, .tar.gz and .tgz; the upload limit is 10 MB.

curl -X POST http://localhost:8080/api/v1/extract \
  -F "[email protected]" \
  -F "pin=12345"
{
  "private_key_hex": "a1b2c3d4...",
  "public_key_hex": "e5f6a7b8...",
  "fingerprint": "0123456789abcdef",
  "curve_oid": "1.2.643.2.2.35.1",
  "certificate_base64": "MIIBkTCB..."
}

Sign a message with the values returned above:

curl -X POST http://localhost:8080/api/v1/sign \
  -H "Content-Type: application/json" \
  -d '{
    "private_key_hex": "a1b2c3d4...",
    "certificate_base64": "MIIBkTCB...",
    "message": "openid2025.01.01 12:00:00 +0000CLIENT_ID12345"
  }'
# {"signature_base64":"MIIBygYJKoZIhvcNAQc..."}

Run on a different port inside the container (the flag must match the published port):

docker run -d -p 9000:9000 --tmpfs /tmp \
  dimahkiin/cryptopro-extract-service:latest -port 9000

⁠Ports

PortProtocolPurpose
8080HTTP/TCPREST API, OpenAPI docs and health check (EXPOSE 8080; overridable with -port)

⁠Paths inside the container

PathPurposeNotes
/appWorking directoryContains the single static binary
/app/cryptopro_extract_serviceEntrypoint binary-
/tmpTemp unpacking of uploaded archivesDoes not exist in the image - mount --tmpfs /tmp or set TMPDIR

⁠Endpoints

MethodPathRequestResponse
GET/health-{"status":"ok"}
POST/api/v1/extractmultipart/form-data: file (.zip/.tar.gz/.tgz, ≤10 MB), pinprivate_key_hex, public_key_hex, fingerprint, curve_oid, certificate_base64
POST/api/v1/signapplication/json: private_key_hex, certificate_base64, messagesignature_base64 (CMS/PKCS#7 SignedData)
GET/docs-RapiDoc UI (HTML)
GET/docs/swagger.json-OpenAPI specification (JSON)

Errors are returned as {"error":"..."} with status 400, 405 or 500.

⁠Environment

The image defines no application environment variables. TMPDIR is honoured by the Go runtime and can be used to relocate the temp directory (see Configuration).

⁠Image

Multi-stage build: docker.io/golang:alpine compiles a fully static binary (CGO_ENABLED=0, -ldflags "-s -w"), the final stage is FROM scratch and contains nothing but that binary. Consequences: no shell, no package manager, no CA certificates, no /tmp. Platform: linux/amd64 only. Size: ~6.4 MB.

⁠License

POTATO LICENSE, Version 2 - the code is released into the public domain. https://github.com/LdDl/esia-potato/blob/master/LICENSE⁠

(Note: the OpenAPI metadata in the source still declares MIT; the repository LICENSE file above is authoritative.)

Tag summary

Content type

Image

Digest

sha256:fc7b257e9…

Size

2.6 MB

Last updated

9 months ago

docker pull dimahkiin/cryptopro-extract-service