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.

The single cross-product service user in this guide simplifies initial setup. For production, use separate identities for administrative setup, device enrollment, and software signing. Give each identity only the roles it needs, and do not use the broadly privileged setup credential in a production pipeline.

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" .-> TRUST

Products and APIs

ProductAPI specificationRole in this solution
Account ManagerAPI referenceIdentify the account and organization, find the required roles, and create the setup identity and credentials.
DigiCert Private CAAPI referenceIdentify the root and issuing CAs, assign each issuer to the account, and download the CA certificates.
Device Trust ManagerAPI referenceSelect the device template, then create the division, certificate profile, policy, authentication configuration, and device group. Issue a device certificate.
Software Trust ManagerAPI referenceSelect the code-signing template, create a private trust certificate profile, keypair, and signing certificate, and sign a hash.

Data flow overview

FromToDataPurpose
Establish the account foundationPrepare the private trust domain, configure device identity, and configure code signingaccount_id, organization_id, service_api_tokenIdentify the target account and organization and authenticate setup calls.
Establish the account foundationConfigure and test private code signingclient.crt, client.keyProvide the second authentication factor for protected Software Trust Manager operations.
Prepare the private trust domainTrust storesroot-ca.pemEstablish the private trust anchor.
Prepare the private trust domainConfigure the device certificate infrastructuredevice_ica_id, device-issuing-ca.pemConfigure and verify device-certificate issuance.
Prepare the private trust domainConfigure and test private code signingsigning_ica_id, signing-issuing-ca.pemConfigure and verify private code-signing certificate issuance.
Configure the device certificate infrastructureDevice certificate profiledevice_certificate_template_idApply the device certificate constraints defined in Device Trust Manager.
Configure and test private code signingSoftware Trust Manager certificate profilecode_signing_certificate_template_idApply the code-signing constraints defined in Software Trust Manager.
Configure the device certificate infrastructureEnroll and verify a devicedivision_id, device_certificate_profile_id, certificate_policy_idConfigure 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:

A DigiCert® ONE account with Account Manager, DigiCert Private CA, Device Trust Manager, and Software Trust Manager entitlements.
An active Software Trust Manager license on the target account that permits 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.
A Device Trust Manager Advanced plan. The device identity workstream registers a device and issues a certificate against a device group, which requires managed device records.
An API token for a bootstrap user authorized to list accounts, organizations, and roles and to create the setup service user. If you do not have one, see Create and authenticate a service user for how an account administrator creates an identity and its token.
An existing private root CA and an active issuing CA for each workload. Prefer separate issuing CAs with purpose-appropriate constraints. If your PKI policy permits a shared issuer or an issuer without an extended key usage (EKU) constraint, document the compensating control. Creating or importing the CA hierarchy is a governed PKI activity outside this workflow.
An active organization record for the private code-signing certificate subject.
An enabled Device Trust Manager rendezvous zone assigned to the account for primary usage. DigiCert operates the rendezvous zones and assigns them to your account, so you select an existing zone rather than creating one. Confirm that at least one zone is available before you start.
An existing custom Device Trust Manager template that passes the eligibility checks in Select the device certificate template. This workflow selects the template; it does not change one.
An existing Software Trust Manager template that passes the eligibility checks in Select the code-signing certificate template. In hosted accounts, ask DigiCert Support to create it before you start if needed.
Tenant roles that grant only the operations used in this guide. Find their exact names with 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.
A demo tenant for validation before production use.

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.

ProductRole response keyRequired capabilityHow to verify it
Account Manageraccount_managerManage 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 CAca_managerView CA and Manage CA accountsEffective permissions include VIEW_CM_CA and MANAGE_CM_CA_ACCOUNTS.
Device Trust Managerdevice_trust_managerSolution AdministratorThe exact selected role name appears in applications[].roles; its effective permissions provide edit access to the resources this workflow creates.
Software Trust Managersecure_software_managerManage certificate profiles, View certificate template, View keypair, Generate keypair, Generate certificate, and SignEffective 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.

Solution Administrator is the Device Trust Manager role with full access to every Device Trust Manager permission. Its API role name can vary by tenant, so select the exact active role returned under 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.
The examples use the US demo host 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

TermDefinition
Root CA and trust anchorThe 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 templateThe purpose-bound constraints for issued certificates, including allowed key types, subject fields, validity, key usage, and extended key usage.
Certificate profileA product-specific configuration that refines an end-entity template for a workload.
Certificate policyThe Device Trust Manager object that binds a profile, issuing CA, division, and enrollment methods.
Authentication policyA Device Trust Manager collection of enrollment credentials, such as passcodes.
DivisionAn 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 zoneA 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 groupThe 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 userA 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.

Next, complete both required workstreams. You may work in any order or in parallel.

Implementation complete Both required workstreams are finished.
View operational guidance

Planning time

WorkFocused execution time
Shared foundation50 minutes
Device identity45 minutes
Code signing30 minutes
Full workflowApproximately 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

  1. Return to the working directory you used for the earlier phases.
  2. Consult the implementation status and saved values table.
  3. Verify the saved values and the last phase checkpoint you satisfied.
  4. Re-export the environment variables the next phase needs. A new shell has none of them.
  5. Resume at the first unmet checkpoint.
  6. 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.

Start the implementation

Establish the account foundation