Create a keypair and sign a file hash
6 minute read
Keypairs are the foundation of code signing in Software Trust Manager. A keypair consists of a private key securely stored in an HSM (Hardware Security Module) and a corresponding public key used to verify signatures. By signing file hashes with your keypair, you cryptographically prove the authenticity and integrity of your software artifacts.
In this tutorial, you will:
- Create a signing keypair in Software Trust Manager.
- Sign a file hash using your new keypair.
- Verify the signature was recorded successfully.
Before you begin
Before you begin, make sure you have:
A user account with one of the following roles:
SSM_SIGNER- Sign files with assigned keypairsSSM_BUILD_ENGINEER- Sign files as part of build processes
openssl version to verify.Endpoint overview
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/keypairs | Create a new signing keypair |
| POST | /api/v1/keypairs/{keypair_id}/sign | Sign a file hash |
| GET | /api/v1/signatures/{signature_id} | Get signature details |
Key algorithms
Select a key algorithm based on your signing requirements:
| Algorithm | Description | Use case |
|---|---|---|
RSA | RSA algorithm, requires key_size property | Windows Authenticode, general signing |
ECDSA | Elliptic Curve DSA, requires curve property | Modern applications, smaller signatures |
EdDSA | Edwards-curve DSA, requires curve property | High-performance signing |
Signature algorithms
Select a signature algorithm compatible with your key algorithm:
| Key Algorithm | Signature Algorithms |
|---|---|
| RSA | SHA256WithRSA, SHA384WithRSA, SHA512WithRSA |
| ECDSA | SHA256WithECDSA, SHA384WithECDSA, SHA512WithECDSA |
| EdDSA | ED25519 |
Step 1: Create a signing keypair
Create a keypair that will be used to sign your files. The private key is generated and stored securely in Software Trust Manager—it never leaves the HSM.
Request:
curl -X POST "https://demo.one.digicert.com/api/v1/keypairs" \
-H "x-api-key: MTLS" \
-H "Content-Type: application/json" \
-d '{
"alias": "my_new_keypair",
"key_alg": "KEY_ALG_VALUE",
"key_storage": "KEY_STORAGE_VALUE",
"key_type": "KEY_TYPE_VALUE",
"properties": {
"key_size": 0,
"curve": "curve_value"
},
"status": "STATUS_VALUE"
}' \
| jq '.'import requests
response = requests.post(
"https://demo.one.digicert.com/api/v1/keypairs",
headers={"x-api-key": "MTLS", "Content-Type": "application/json"},
json={
"alias": "my_new_keypair",
"key_alg": "KEY_ALG_VALUE",
"key_storage": "KEY_STORAGE_VALUE",
"key_type": "KEY_TYPE_VALUE",
"properties": {
"key_size": 0,
"curve": "curve_value"
},
"status": "STATUS_VALUE"
}
)
print(f"Status: {response.status_code}")
if response.status_code != 204:
print(response.json())import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://demo.one.digicert.com/api/v1/keypairs"))
.header("x-api-key", "MTLS")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"alias\": \"my_new_keypair\", \"key_alg\": \"KEY_ALG_VALUE\", \"key_storage\": \"KEY_STORAGE_VALUE\", \"key_type\": \"KEY_TYPE_VALUE\", \"properties\": {\"key_size\": 0, \"curve\": \"curve_value\"}, \"status\": \"STATUS_VALUE\"}"))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println(response.body());using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "MTLS");
var content = new StringContent(@"{
""alias"": ""my_new_keypair"",
""key_alg"": ""KEY_ALG_VALUE"",
""key_storage"": ""KEY_STORAGE_VALUE"",
""key_type"": ""KEY_TYPE_VALUE"",
""properties"": {
""key_size"": 0,
""curve"": ""curve_value""
},
""status"": ""STATUS_VALUE""
}",
Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://demo.one.digicert.com/api/v1/keypairs", content);
Console.WriteLine($"Status: {(int)response.StatusCode}");
Console.WriteLine(await response.Content.ReadAsStringAsync());Configure the keypair with these fields:
alias- A unique name for your keypair (e.g.,my-signing-key)key_alg- Algorithm:RSA,ECDSA, orEdDSAkey_storage- Storage location:HSM(recommended) orDISKkey_type- Purpose:PRODUCTIONorTESTproperties- Algorithm-specific settings (see example below)status- Availability:ONLINE(ready to sign) orOFFLINE
For an RSA keypair, set properties to include key_size:
{
"properties": {
"key_size": 2048
}
}
For an ECDSA keypair, set properties to include curve:
{
"properties": {
"curve": "P-256"
}
}
Successful response (201 Created):
{
"id": "01234567-89ab-cdef-0123-456789abcdef",
"status": "active",
"_note": "Response schema not fully documented in API spec"
}
From the response, save the keypair id. You will need this in Step 2 when signing your file hash.
Step 2: Sign a file hash
Before signing, you need to compute the hash of your file. Software Trust Manager signs the hash, not the file itself. This approach is more efficient and secure—your file content never leaves your environment.
Generate the file hash:
openssl dgst -sha256 -binary myfile.exe | openssl base64
This outputs a base64-encoded SHA-256 hash of your file.
Request:
curl -X POST "https://demo.one.digicert.com/api/v1/keypairs/KEYPAIR_ID/sign" \
-H "x-api-key: MTLS" \
-H "Content-Type: application/json" \
-d '{
"hash": "eeUnw3ky7+hI7Kawc9NnZ4CCCenu8rDDfV+YTwNutt+JHXX3LZsVRRjBzViDUobR",
"sig_alg": "SHA3-512WithRSA/PSS"
}' \
| jq '.'import requests
KEYPAIR_ID = "KEYPAIR_ID"
response = requests.post(
f"https://demo.one.digicert.com/api/v1/keypairs/{KEYPAIR_ID}/sign",
headers={"x-api-key": "MTLS", "Content-Type": "application/json"},
json={
"hash": "eeUnw3ky7+hI7Kawc9NnZ4CCCenu8rDDfV+YTwNutt+JHXX3LZsVRRjBzViDUobR",
"sig_alg": "SHA3-512WithRSA/PSS"
}
)
print(f"Status: {response.status_code}")
if response.status_code != 204:
print(response.json())import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://demo.one.digicert.com/api/v1/keypairs/KEYPAIR_ID/sign"))
.header("x-api-key", "MTLS")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"hash\": \"eeUnw3ky7+hI7Kawc9NnZ4CCCenu8rDDfV+YTwNutt+JHXX3LZsVRRjBzViDUobR\", \"sig_alg\": \"SHA3-512WithRSA/PSS\"}"))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println(response.body());using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "MTLS");
var content = new StringContent(@"{
""hash"": ""eeUnw3ky7+hI7Kawc9NnZ4CCCenu8rDDfV+YTwNutt+JHXX3LZsVRRjBzViDUobR"",
""sig_alg"": ""SHA3-512WithRSA/PSS""
}",
Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://demo.one.digicert.com/api/v1/keypairs/KEYPAIR_ID/sign", content);
Console.WriteLine($"Status: {(int)response.StatusCode}");
Console.WriteLine(await response.Content.ReadAsStringAsync());Replace {keypair_id} with the keypair ID from Step 1.
Configure the signing request with:
hash- The base64-encoded file hash from the OpenSSL commandsig_alg- Signature algorithm matching your key type (e.g.,SHA256WithRSA)
Successful response (200 OK):
{
"id": "01234567-89ab-cdef-0123-456789abcdef",
"status": "active",
"_note": "Response schema not fully documented in API spec"
}
From the response, save the signature id and the signature value. The id is used in Step 3 to verify the signature was recorded. The signature value is the cryptographic signature you can use to verify your file.
Step 3: Verify the signature
Retrieve the signature record to confirm it was created successfully and review the signing details.
Request:
curl -X GET "https://demo.one.digicert.com/api/v1/signatures/SIGNATURE_ID" \
-H "x-api-key: MTLS" \
| jq '.'import requests
SIGNATURE_ID = "SIGNATURE_ID"
response = requests.get(
f"https://demo.one.digicert.com/api/v1/signatures/{SIGNATURE_ID}",
headers={"x-api-key": "MTLS"}
)
print(f"Status: {response.status_code}")
if response.status_code != 204:
print(response.json())import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://demo.one.digicert.com/api/v1/signatures/SIGNATURE_ID"))
.header("x-api-key", "MTLS")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println(response.body());using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "MTLS");
var response = await client.GetAsync("https://demo.one.digicert.com/api/v1/signatures/SIGNATURE_ID");
Console.WriteLine($"Status: {(int)response.StatusCode}");
Console.WriteLine(await response.Content.ReadAsStringAsync());Replace {signature_id} with the signature ID from Step 2.
Successful response (200 OK):
{
"id": "01234567-89ab-cdef-0123-456789abcdef",
"keypair_id": "01234567-89ab-cdef-0123-456789abcdef",
"key_pair": "KEY_PAIR_VALUE",
"signature": "...(signature string)...",
"sig_alg": "SIG_ALG_VALUE",
"hash": "eeUnw3ky7+hI7Kawc9NnZ4CCCenu8rDDfV+YTwNutt+JHXX3LZsVRRjBzViDUobR",
"signing_status": "SIGNING_STATUS_VALUE",
"account": [
"01234567-89ab-cdef-0123-456789abcdef"
],
"created_on": "CREATED_ON_VALUE",
"created_by": "CREATED_BY_VALUE",
"created_by_user": "CREATED_BY_USER_VALUE",
"modified_on": "MODIFIED_ON_VALUE",
"modified_by": "MODIFIED_BY_VALUE",
"modified_by_user": "MODIFIED_BY_USER_VALUE",
"client_ip": "211.22.33.44",
"certificate_id": "01234567-89ab-cdef-0123-456789abcdef",
"client_type": "SigningManager-PKCS11/1.31.0 (linux; amd64)",
"signature_type": "SIGNATURE_TYPE_VALUE"
}
Verify the response shows signing_status as SUCCESS. The response also includes:
keypair_id- Confirms which keypair was usedsig_alg- The signature algorithm usedhash- The original hash that was signedcreated_on- Timestamp of when the signature was createdsignature- The cryptographic signature value
Common errors and solutions
For general API errors (authentication, rate limits), see the API error reference.
Invalid key algorithm
{
"errors": [
{
"code": "INVALID_KEY_ALG",
"message": "Invalid key algorithm specified"
}
]
}
The key_alg value is not valid. Use one of: RSA, ECDSA, or EdDSA.
Missing required properties
{
"errors": [
{
"code": "INVALID_PROPERTIES",
"message": "Key properties are required for the specified algorithm"
}
]
}
You must include the properties object with algorithm-specific settings. RSA requires key_size, while ECDSA and EdDSA require curve.
Signature algorithm mismatch
{
"errors": [
{
"code": "INVALID_SIG_ALG",
"message": "Signature algorithm is not compatible with keypair algorithm"
}
]
}
The signature algorithm must match the keypair’s key algorithm. For example, use SHA256WithRSA with RSA keys, not SHA256WithECDSA.
Keypair not found or not accessible
{
"errors": [
{
"code": "KEYPAIR_NOT_FOUND",
"message": "Keypair not found or you do not have access"
}
]
}
The keypair ID is invalid or you don’t have permission to use it for signing. Verify the ID and ensure your user has the SSM_SIGNER or SSM_BUILD_ENGINEER role.