Skip to content

Code Signing Certificates

Stentor supports Authenticode code signing for generated payloads. Code signing certificates are uploaded as PFX (PKCS#12) files, stored with encrypted passwords in the database, and used to sign payloads via the relay's osslsigncode tool. Signed payloads carry a valid Authenticode signature that satisfies Windows SmartScreen, application whitelisting policies, and user trust prompts.


Architecture

sequenceDiagram
    participant Operator as Operator
    participant API as Stentor API
    participant DB as PostgreSQL
    participant Relay as Relay (Kali)

    Note over Operator,DB: Certificate Upload
    Operator->>API: POST /certificates (multipart PFX + password)
    API->>API: Parse PFX, extract metadata
    API->>API: Encrypt password (AES-256-GCM)
    API->>DB: Store PFX + encrypted password + metadata
    API-->>Operator: CertificateResponse (no sensitive fields)

    Note over Operator,Relay: Payload Signing
    Operator->>API: POST /sign {payload_id, certificate_id}
    API->>DB: Load payload binary + certificate PFX
    API->>API: Decrypt certificate password
    API->>Relay: sign_payload command (PFX + password + payload)
    Relay->>Relay: osslsigncode sign
    Relay-->>API: Signed payload bytes
    API-->>Operator: {success, signed_size}

Certificate Management

Upload a Certificate

POST /api/v1/certificates

Upload a PFX (PKCS#12) file containing a code signing certificate and private key. The API parses the PFX to extract certificate metadata (subject, issuer, validity period), encrypts the password with AES-256-GCM, and stores everything in the database.

Form fields:

Field Type Required Description
name string Yes Human-readable name for the certificate
description string No Optional description
pfx_file file Yes PFX (PKCS#12) file containing certificate and private key
password string Yes Password protecting the PFX file

Size limit: 1 MB maximum for the PFX file.

curl -s -X POST https://stentor.app/api/v1/certificates \
  -H "Authorization: Bearer $TOKEN" \
  -F "name=Contoso Code Signing" \
  -F "description=EV code signing cert for payload signing" \
  -F "pfx_file=@/path/to/certificate.pfx" \
  -F "password=pfx-password-here"

Response (201 Created):

{
  "id": "b2c3d4e5-...",
  "name": "Contoso Code Signing",
  "description": "EV code signing cert for payload signing",
  "subject": "CN=Contoso Ltd, O=Contoso Ltd, L=Redmond, ST=Washington, C=US",
  "issuer": "CN=DigiCert SHA2 Extended Validation Code Signing CA, OU=www.digicert.com, O=DigiCert Inc, C=US",
  "valid_from": "2025-01-15T00:00:00Z",
  "valid_until": "2027-01-14T23:59:59Z",
  "created_by": "USER_UUID",
  "created_at": "2026-02-21T10:00:00Z"
}

PFX Validation

The API decodes the PFX using Go's pkcs12.Decode to verify the file is valid and the password is correct before storing. Invalid PFX files or incorrect passwords return a 400 Bad Request error with a descriptive message.

List Certificates

GET /api/v1/certificates

List all stored certificates. Sensitive fields (PFX binary data, encrypted password) are excluded from the response. Certificates are returned in reverse chronological order.

curl -s https://stentor.app/api/v1/certificates \
  -H "Authorization: Bearer $TOKEN"

Response fields:

Field Type Description
id string Certificate UUID
name string Certificate name
description string Optional description
subject string Certificate subject DN
issuer string Certificate issuer DN
valid_from string Validity start (ISO 8601)
valid_until string Validity end (ISO 8601)
created_by string UUID of the user who uploaded
created_at string Upload timestamp (ISO 8601)

Get Certificate

GET /api/v1/certificates/:id

Retrieve a single certificate by ID. Same response format as the list endpoint (no sensitive fields).

curl -s https://stentor.app/api/v1/certificates/CERT_UUID \
  -H "Authorization: Bearer $TOKEN"

Delete Certificate

DELETE /api/v1/certificates/:id

Delete a certificate and all associated data (PFX binary, encrypted password) from the database.

curl -s -X DELETE https://stentor.app/api/v1/certificates/CERT_UUID \
  -H "Authorization: Bearer $TOKEN"

Response: 204 No Content on success.


Signing Payloads

POST /api/v1/sign

Sign a generated payload with a stored code signing certificate. The signing operation is performed on the relay using osslsigncode, which supports Authenticode signatures for PE (EXE/DLL) files.

Request body:

Field Type Required Description
payload_id string (UUID) Yes UUID of the payload to sign
certificate_id string (UUID) Yes UUID of the code signing certificate
description string No Authenticode signature description (appears in file properties)
url string No URL embedded in the Authenticode signature
timestamp_url string No RFC 3161 timestamp server URL for countersigning

Timestamp Countersigning

Providing a timestamp_url adds a trusted timestamp to the signature, which ensures the signature remains valid even after the certificate expires. Common timestamp servers: http://timestamp.digicert.com, http://timestamp.sectigo.com.

curl -s -X POST https://stentor.app/api/v1/sign \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "payload_id": "PAYLOAD_UUID",
    "certificate_id": "CERT_UUID",
    "description": "Contoso Updater Service",
    "url": "https://contoso.com",
    "timestamp_url": "http://timestamp.digicert.com"
  }'

Response (200 OK):

{
  "success": true,
  "payload_id": "PAYLOAD_UUID",
  "signed_size": 524288
}

Error responses:

Status Condition
400 Bad Request Missing required fields or invalid UUIDs
404 Not Found Payload or certificate not found
503 Service Unavailable No relay connected (signing requires relay)
504 Gateway Timeout Signing operation timed out (60 second limit)
500 Internal Server Error Signing failed on relay (error message included)

Signing Flow

  1. The API validates the request and loads the payload binary and certificate PFX from the database.
  2. The certificate password is decrypted from AES-256-GCM storage.
  3. A sign_payload command is sent to the first connected relay with the payload bytes, PFX data, decrypted password, and signing options.
  4. The relay executes osslsigncode to apply the Authenticode signature.
  5. The signed payload bytes are returned to the API via a correlation-based request/response channel.
  6. The API returns the result to the operator.

Relay Requirement

Signing requires at least one connected relay. The osslsigncode tool runs on the Kali relay -- the Stentor API server does not perform signing directly. If no relay is connected, the endpoint returns 503 Service Unavailable.


Encrypted Storage

Certificate passwords are encrypted at rest using AES-256-GCM with a 32-byte server-side key configured via the C2_CERTIFICATE_ENCRYPTION_KEY environment variable.

Component Storage Encryption
PFX binary data certificates.pfx_data (BYTEA) None (raw bytes in database)
PFX password certificates.password_encrypted (BYTEA) AES-256-GCM (12-byte nonce prepended)
Certificate metadata certificates.* None (plaintext -- not sensitive)

The encryption scheme uses a random 12-byte nonce for each encryption operation. The nonce is prepended to the ciphertext, so the stored value is [12-byte nonce][ciphertext + GCM tag].

Key rotation is supported via the MigrateEncryptedPassword utility, which decrypts with the old key and re-encrypts with a new key using a fresh nonce.

Encryption Key Management

The C2_CERTIFICATE_ENCRYPTION_KEY must be exactly 32 bytes (256 bits). If the key is lost or changed without migrating existing passwords, all stored certificates become unusable (the PFX data is intact but the password cannot be decrypted). Store the key securely and include it in your backup procedures.


OPSEC Considerations

Detection Surface

Code-signed payloads are significantly more likely to bypass initial execution controls, but the certificate itself becomes an indicator of compromise (IOC) if the payload is captured and analyzed.

  • MITRE ATT&CK: T1553.002 (Subvert Trust Controls: Code Signing)
Concern Details
SmartScreen bypass Signed EXEs bypass the "Windows protected your PC" SmartScreen warning. EV certificates provide immediate reputation. Standard certificates build reputation over time.
Application whitelisting Some application whitelisting policies allow execution of signed binaries. Signing with a trusted publisher certificate can bypass these controls.
Certificate as IOC If a signed payload is captured, the certificate's serial number, subject, and thumbprint become IOCs. Defenders can block execution of all binaries signed with that certificate.
Certificate revocation A compromised or detected certificate may be reported to the CA for revocation. Check CRL/OCSP status before relying on a certificate for ongoing operations.
Timestamp persistence Countersigned payloads remain trusted even after the certificate expires or is revoked (depending on the revocation reason). Always use a timestamp server for long-running engagements.

Certificate Sources

For red team engagements, code signing certificates can be obtained from:

  • Legitimate purchase: Buy a standard or EV code signing certificate from a public CA. Provides the strongest trust signal but creates a paper trail.
  • Self-signed: Generate a self-signed certificate for testing. Does not bypass SmartScreen but satisfies some application whitelisting policies that only check for a valid signature chain.
  • Expired/stolen: Certificates found during post-exploitation can be extracted and used for signing. Time-stamp countersigning extends usability beyond expiration.