Solution manual
Validate device identity and code signing in a private trust stack
Configure and validate device identity and private code signing beneath a governed private root CA.
Solution summary
- Complexity
- Advanced
- Estimated time
- 3–5 hours
- API calls
- Approximately 29
- Phases
- 5
- Audience
- Enterprise PKI integrator, DevSecOps engineer, IoT and device engineer
Private device fleets can require two complementary trust controls: certificates that identify devices and private signatures that establish software provenance. This solution configures and validates both controls beneath a governed private public key infrastructure (PKI) root CA.
DigiCert® Account Manager provides the automation identity. DigiCert® Private CA provides the root trust anchor and issuing CAs. DigiCert® Device Trust Manager issues device certificates, and DigiCert® Software Trust Manager issues private code-signing certificates and signs a test hash.
The workloads share the account foundation and root trust anchor but remain operationally separate. Each workload has its own purpose-bound end-entity template and issuing-CA variable. Select two issuing CAs beneath the same root CA so each issuer can be constrained to the purpose it serves. A single issuing CA for both variables works where your PKI policy permits it, but a shared issuer cannot be constrained to one workload.
By the end, you will have
After you complete this manual, you can demonstrate that the tenant issues purpose-appropriate device and code-signing certificates and produces a verifiable private signature beneath the approved root CA. You will have:
- A service user with the roles required by the setup workflow, an API token, and a client authentication certificate.
- An active root CA certificate to distribute as the relying-party trust anchor.
- One or two active private issuing CAs assigned to your account.
- A device certificate template and a code-signing certificate template, each identified in its own product and validated against the purpose it serves. This workflow selects existing templates. It does not create them.
- A Device Trust Manager division, certificate profile, certificate policy, and device group configured for passcode-authenticated enrollment.
- A device certificate whose path validates to the private root CA.
- A Software Trust Manager keypair and private code-signing certificate, plus a signature produced over a known hash.
This workflow validates the DigiCert® ONE configuration and cryptographic outputs in a demo tenant. Production integration with device key stores, relying services, trust distribution, and artifact-specific signing systems is outside this workflow.
Before you start, review the additional requirements for production device provisioning and production signing. This validation does not make those production decisions for you.
One integrator can complete the demo workflow. A production implementation commonly involves separate identity, PKI, device-platform, and release-security owners. Coordinate the phase outputs with those owners.
Solution architecture
The root CA certificate is the trust anchor installed in relying-party trust stores. The issuing CA signs the two types of end-entity certificates. Each product has its own certificate template and profile.
flowchart TD
FOUNDATION["Shared foundation<br/>Setup identity: API token + client certificate<br/>Private root CA + workload issuing CA roles"]
DEVICE["Device identity<br/>Template + profile + policy + group<br/>Passcode-authenticated enrollment"]
SIGNING["Code signing<br/>Template + profile + keypair<br/>API token + client certificate for protected operations"]
DEVICE_OUT["Device identity outcome<br/>Device certificate issued<br/>Key and certificate path verified"]
SIGNING_OUT["Code-signing outcome<br/>Private signing certificate issued<br/>Certificate path and signature verified"]
TRUST["Relying-party trust stores<br/>Approved private root required"]
FOUNDATION -->|"device issuer + setup authentication"| DEVICE
FOUNDATION -->|"signing issuer + setup authentication"| SIGNING
FOUNDATION -->|"prepare root-ca.pem for distribution"| TRUST
DEVICE --> DEVICE_OUT
SIGNING --> SIGNING_OUT
DEVICE_OUT -. "validates to approved root" .-> TRUST
SIGNING_OUT -. "validates to approved root" .-> TRUSTProducts and APIs
| Product | API specification | Role in this solution |
|---|---|---|
| Account Manager | API reference | Identify the account and organization, find the required roles, and create the setup identity and credentials. |
| DigiCert Private CA | API reference | Identify the root and issuing CAs, assign each issuer to the account, and download the CA certificates. |
| Device Trust Manager | API reference | Select the device template, then create the division, certificate profile, policy, authentication configuration, and device group. Issue a device certificate. |
| Software Trust Manager | API reference | Select the code-signing template, create a private trust certificate profile, keypair, and signing certificate, and sign a hash. |
Data flow overview
| From | To | Data | Purpose |
|---|---|---|---|
| Establish the account foundation | Prepare the private trust domain, configure device identity, and configure code signing | account_id, organization_id, service_api_token | Identify the target account and organization and authenticate setup calls. |
| Establish the account foundation | Configure and test private code signing | client.crt, client.key | Provide the second authentication factor for protected Software Trust Manager operations. |
| Prepare the private trust domain | Trust stores | root-ca.pem | Establish the private trust anchor. |
| Prepare the private trust domain | Configure the device certificate infrastructure | device_ica_id, device-issuing-ca.pem | Configure and verify device-certificate issuance. |
| Prepare the private trust domain | Configure and test private code signing | signing_ica_id, signing-issuing-ca.pem | Configure and verify private code-signing certificate issuance. |
| Configure the device certificate infrastructure | Device certificate profile | device_certificate_template_id | Apply the device certificate constraints defined in Device Trust Manager. |
| Configure and test private code signing | Software Trust Manager certificate profile | code_signing_certificate_template_id | Apply the code-signing constraints defined in Software Trust Manager. |
| Configure the device certificate infrastructure | Enroll and verify a device | division_id, device_certificate_profile_id, certificate_policy_id | Configure passcode enrollment and issue a device certificate. |
When to use this manual
Use this manual when:
- Your organization needs both private device authentication certificates and private software signatures.
- Both workloads operate beneath the same approved private root and trust governance model, even when they use separate issuing CAs.
- You want to validate the cross-product configuration and cryptographic outputs in a demo tenant before integrating production systems.
If the workloads have different trust owners or require separate root CAs, implement them independently instead of treating them as one private trust stack.
Before you begin
Make sure you have:
TEST keypair generation and hash signing. Visible templates and effective role permissions do not by themselves prove that these licensed operations are enabled. Confirm the entitlement with your account administrator or DigiCert Support.GET /account/api/v1/role, and confirm the permissions they grant on the created service user. Do not copy role names from another tenant.curl, jq, OpenSSL, and Python 3 with the requests package for the examples.The following table lists the required capabilities. Role response key is the Account Manager product code that groups roles in the GET /account/api/v1/role response. The created service user’s response lists role names and effective permission codes separately. Do not test a role name as though it were a permission code.
| Product | Role response key | Required capability | How to verify it |
|---|---|---|---|
| Account Manager | account_manager | Manage users, plus view access to accounts, organizations, and roles. Required by the bootstrap user, not the service user. | Bootstrap-user permissions include MANAGE_AM_ACCOUNT_USER, VIEW_AM_ACCOUNT, VIEW_AM_ORGANIZATION, and VIEW_AM_ROLE. |
| DigiCert Private CA | ca_manager | View CA and Manage CA accounts | Effective permissions include VIEW_CM_CA and MANAGE_CM_CA_ACCOUNTS. |
| Device Trust Manager | device_trust_manager | Solution Administrator | The exact selected role name appears in applications[].roles; its effective permissions provide edit access to the resources this workflow creates. |
| Software Trust Manager | secure_software_manager | Manage certificate profiles, View certificate template, View keypair, Generate keypair, Generate certificate, and Sign | Effective permissions include MANAGE_SM_CERTIFICATE_PROFILE, VIEW_SM_CERTIFICATE_TEMPLATE, VIEW_SM_KEYPAIR, GENERATE_SM_KEYPAIR, GENERATE_SM_CERTIFICATE, and SIGN_SM_HASH. |
Each role selected for the other products also needs access to the target account.
Some stable API codes predate the current product names. ca_manager represents DigiCert Private CA, and secure_software_manager represents Software Trust Manager. The CM in VIEW_CM_CA and MANAGE_CM_CA_ACCOUNTS is the same legacy abbreviation for DigiCert Private CA. In the product interface, these permissions appear as View CA and Manage CA accounts.
device_trust_manager and verify that name under applications[].roles. The other default roles grant view-only access to divisions, certificate profiles, and certificate policies. Assign the administrator role to the setup service user for this workflow, and give production identities narrower roles.demo.one.digicert.com. Substitute the host for your tenant and region. Software Trust Manager operations that require multi-factor authentication use clientauth.<host>, the service user’s client certificate, and the service user’s API token in the x-api-key header.The cURL examples provide the complete guided path. Selected steps also include Python examples. This manual uses snake_case names for values passed between phases. The cURL examples export equivalent uppercase environment variables, such as ACCOUNT_ID for account_id, while the Python examples retain snake_case. Store secrets passed between phases, such as service_api_token and enrollment_passcode, in an approved secret manager instead of a general-purpose environment file.
Every example reads and writes files by relative path, including client.crt, root-ca.pem, ca-inventory.json, and device-issuing-ca.pem. Create a dedicated directory for the validation run. Run all five phases from this directory, and keep it until you finish the workflow:
WORK_DIR="private-trust-validation-$(date +%Y%m%d-%H%M%S)"
mkdir -m 700 "${WORK_DIR}"
cd "${WORK_DIR}"
umask 077
Run each cURL block as one unit, in order, from the same shell. Selected Python tabs illustrate the corresponding API operation. When a step contains more than one Python block, keep the earlier variables in the same Python session. Replace example values and placeholders before running a block, and review its output before continuing. The umask 077 setting remains active in the current shell and restricts new files to the current user. It protects response files that can contain tokens, passcodes, and private keys.
If you resume after a pause, return to that directory before running any command.
Key concepts
| Term | Definition |
|---|---|
| Root CA and trust anchor | The root certificate installed in a relying party’s trust store. It terminates certificate-path validation. |
| Issuing CA (ICA) | The intermediate CA that signs end-entity certificates. It is an issuer, not the trust anchor. |
| Certificate template | The purpose-bound constraints for issued certificates, including allowed key types, subject fields, validity, key usage, and extended key usage. |
| Certificate profile | A product-specific configuration that refines an end-entity template for a workload. |
| Certificate policy | The Device Trust Manager object that binds a profile, issuing CA, division, and enrollment methods. |
| Authentication policy | A Device Trust Manager collection of enrollment credentials, such as passcodes. |
| Division | An isolated environment inside a Device Trust Manager account that scopes device groups, certificate profiles, certificate policies, and software updates. Every account has a default division, and you create additional divisions to separate business units or customer segments. |
| Rendezvous zone | A regional Device Trust Manager service that handles communication between the product and devices running a TrustEdge agent. DigiCert operates the zones and assigns them to your account; accounts and divisions share a common set. Each division names one zone for primary usage and can name a second as a backup. You select an existing zone rather than creating one. |
| Device group | The organizational unit that a device must belong to before Device Trust Manager can manage it. A device group carries the policy assignments the devices in it inherit, and a device cannot exist outside one. |
| Service user | A non-interactive Account Manager identity represented by an API token and, where required, a client authentication certificate. |
Implementation roadmap
Establish the account foundation, then prepare the private trust domain. The complete validation includes both device identity and code signing. After the shared foundation is ready, complete the workstreams concurrently or in either order.
Shared foundation
- Phase 1 Account Manager
Establish the account foundation
Create a service user with limited roles, capture its API token, and create its client authentication certificate.
25 minutes Open phase - Phase 2 DigiCert Private CA
Prepare the private trust domain
Identify the root and workload-specific issuing CAs, assign each issuer to the account, and download the CA certificates.
25 minutes Prerequisite: Establish the account foundation Open phase
Next, complete both required workstreams. You may work in any order or in parallel.
Device identity
- Phase 3 Device Trust Manager
Configure device certificate infrastructure
Select a device template, create a profile limited to one division, and bind the device issuing CA in a REST certificate policy.
20 minutes Prerequisite: Prepare the private trust domain Open phase - Phase 4 Device Trust Manager
Enroll and verify a device
Attach a passcode authentication policy to a device group, register a managed device, and validate its bootstrap key and certificate path.
25 minutes Prerequisite: Configure device certificate infrastructure Open phase
Code signing
Planning time
| Work | Focused execution time |
|---|---|
| Shared foundation | 50 minutes |
| Device identity | 45 minutes |
| Code signing | 30 minutes |
| Full workflow | Approximately 125 minutes |
Plan for 3–5 hours in a prepared demo tenant. In addition to focused execution, this estimate includes review, environment setup, resource availability checks, wait or approval time, and validation. It excludes the lead time to establish the CA hierarchy, obtain product entitlements, provision support-managed templates, or complete production approvals.
Resume after a pause
- Return to the working directory you used for the earlier phases.
- Consult the implementation status and saved values table.
- Verify the saved values and the last phase checkpoint you satisfied.
- Re-export the environment variables the next phase needs. A new shell has none of them.
- Resume at the first unmet checkpoint.
- Search for existing resources before repeating any request that creates or changes a resource. A timed-out create request might have succeeded even when its response was lost.
Restore the shell environment
Each phase writes its responses to the working directory, so you can re-export the identifiers without repeating any request. Run only the blocks for phases you already completed, and retrieve the two secrets from your approved secret manager rather than from a local file.
# Secrets: retrieve from your approved secret manager.
read -rsp "Service API token: " SERVICE_API_TOKEN; echo
umask 077
export SERVICE_API_TOKEN
# Establish the account foundation.
ACCOUNT_ID="$(<account-id.txt)"
ORGANIZATION_ID="$(<organization-id.txt)"
SERVICE_USER_ID="$(<service-user-id.txt)"
API_TOKEN_ID="$(<api-token-id.txt)"
CLIENT_AUTH_CERTIFICATE_ID="$(<client-auth-certificate-id.txt)"
export ACCOUNT_ID ORGANIZATION_ID SERVICE_USER_ID API_TOKEN_ID CLIENT_AUTH_CERTIFICATE_ID
# Prepare the private trust domain.
ROOT_CA_ID="$(<root-ca-id.txt)"
DEVICE_ICA_ID="$(<device-ica-id.txt)"
SIGNING_ICA_ID="$(<signing-ica-id.txt)"
export ROOT_CA_ID DEVICE_ICA_ID SIGNING_ICA_ID
# Configure the device certificate infrastructure.
DEVICE_CERTIFICATE_TEMPLATE_ID="$(jq -er '.id' device-template.json)"
PRIMARY_RENDEZVOUS_ZONE_ID="$(<primary-rendezvous-zone-id.txt)"
DIVISION_ID="$(jq -er '.id' division.json)"
DEVICE_CERTIFICATE_PROFILE_ID="$(jq -er '.id' device-profile-response.json)"
CERTIFICATE_POLICY_ID="$(jq -er '.certificate_policy.id' certificate-policy-response.json)"
export DEVICE_CERTIFICATE_TEMPLATE_ID PRIMARY_RENDEZVOUS_ZONE_ID DIVISION_ID \
DEVICE_CERTIFICATE_PROFILE_ID CERTIFICATE_POLICY_ID
# Enroll and verify a device.
AUTHENTICATION_POLICY_ID="$(jq -er '.id' authentication-policy-response.json)"
PASSCODE_ID="$(jq -er '.id' passcode-response.json)"
DEVICE_GROUP_ID="$(jq -er '.id' device-group.json)"
DEVICE_NAME="$(<device-name.txt)"
CERTIFICATE_REQUEST_ID="$(jq -er '.certificate_request_id' device-certificate.json)"
DEVICE_CERTIFICATE_ID="$(jq -er '.id' device-certificate.json)"
DEVICE_ID="$(<device-id.txt)"
read -rsp "Enrollment passcode: " ENROLLMENT_PASSCODE; echo
export AUTHENTICATION_POLICY_ID PASSCODE_ID DEVICE_GROUP_ID \
DEVICE_NAME CERTIFICATE_REQUEST_ID DEVICE_CERTIFICATE_ID DEVICE_ID ENROLLMENT_PASSCODE
# Configure and test private code signing.
CODE_SIGNING_CERTIFICATE_TEMPLATE_ID="$(jq -er '.id' signing-template.json)"
SIGNING_PROFILE_ID="$(jq -er '.id' signing-profile-response.json)"
KEYPAIR_ALIAS="$(<keypair-alias.txt)"
KEYPAIR_ID="$(jq -er '.id' keypair-response.json)"
SIGNING_CERTIFICATE_ID="$(jq -er '.id' signing-certificate-response.json)"
SIGNATURE_ID="$(jq -er '.id' signing-response.json)"
export CODE_SIGNING_CERTIFICATE_TEMPLATE_ID SIGNING_PROFILE_ID KEYPAIR_ALIAS KEYPAIR_ID \
SIGNING_CERTIFICATE_ID SIGNATURE_ID
The enrollment passcode is not recoverable from passcode-response.json. Retrieve the original value from your secret manager, or create a replacement passcode on the existing authentication policy.