Skip to main content
Version: v1.1

Certificate Handler

Introduction

The Certificate Handler (CertHandler) is the core module within IAM responsible for managing cryptographic keys and X.509 certificates. It provides a unified interface for creating key pairs, generating Certificate Signing Requests (CSRs), applying signed certificates, and tracking certificate validity — regardless of the underlying storage technology.

CertHandler uses a pluggable module architecture to support different secure storage backends. Each module implements the same HSM interface, allowing the system to work with hardware security modules (via PKCS#11), TPM devices, or filesystem-based storage without changing the certificate management logic.

Architecture

CertHandler is implemented in the aos_core_lib_cpp library and used by the IAM application. It consists of three layers:

CertHandler (certhandler.hpp)
├── CertModule (certmodule.hpp) # Per-type certificate management
│ ├── HSMItf # Hardware security module interface
│ ├── StorageItf # Certificate metadata storage interface
│ └── x509::ProviderItf # X.509/CSR operations
└── Module implementations
├── PKCS11Module # PKCS#11 cryptographic token
├── TPM Module # TPM 2.0 device
└── Software Module # Filesystem-based storage

CertHandler

The top-level CertHandler class manages a collection of CertModule instances — one per configured certificate type. It routes operations to the appropriate module based on the certType parameter and notifies registered listeners when certificates change.

Key responsibilities:

  • Module registration and lookup by certificate type
  • Thread-safe access to certificate operations (mutex-protected)
  • Certificate change notification to subscribed listeners (CM, SM)
  • Self-signed certificate creation for initial bootstrap

CertModule

Each CertModule handles certificates of a single type (e.g., "iam", "sm", "cm"). It coordinates between the HSM interface (for key/certificate storage), the metadata storage interface (for tracking certificate information in the database), and the X.509 provider (for CSR generation and certificate parsing).

Key responsibilities:

  • Key generation via the HSM backend
  • CSR creation with configured extensions (extended key usage, alternative DNS names)
  • Certificate chain validation
  • Certificate application (storing in HSM + recording metadata)
  • Certificate trimming (removing oldest certificates when maxCertificates is exceeded)
  • Database synchronization on initialization (reconciling HSM state with stored metadata)

Supported Key Algorithms

CertHandler supports two key generation algorithms, configured per certificate module:

AlgorithmDescriptionPKCS#11 Parameters
RSARSA 2048-bit key pairs2048-bit modulus length
ECDSAElliptic Curve Digital Signature AlgorithmP-384 curve (secp384r1)

The key algorithm is specified in the module configuration via the algorithm field and applies to all keys generated by that module.

Certificate Lifecycle

Key Creation and CSR Generation

Certificate deployment follows a two-step process:

  1. CreateKey — the client requests a new key pair. CertHandler generates the key in the configured storage backend and returns a PEM-encoded CSR.
  2. ApplyCertificate — the client provides the signed certificate (obtained from a CA using the CSR). CertHandler stores the certificate and updates its metadata database.

The CSR includes:

  • Subject — the common name provided by the caller (e.g., the Node ID)
  • Extended Key Usage — configured per module: clientAuth, serverAuth, or both
  • Subject Alternative Names — DNS names configured for server certificates

Certificate Application

When a signed certificate is applied:

  1. The PEM certificate chain is parsed into X.509 certificate objects
  2. The certificate chain is validated (each certificate's issuer matches a parent in the chain)
  3. If the module has reached its maxCertificates limit, the oldest certificate (by expiration date) is removed to make room
  4. The certificate is stored in the HSM backend (matched to its pending private key)
  5. Certificate metadata (type, issuer, serial, URLs, expiration) is recorded in the database

Certificate Retrieval

Certificates are retrieved by specifying:

  • Certificate type — identifies which module to query
  • Issuer and serial number — identifies a specific certificate

If issuer and serial are empty, CertHandler returns the newest certificate (latest notAfter date) from the specified module. This is the common case for components requesting their current active certificate.

Certificate locations are expressed as URLs with scheme-specific formats:

  • pkcs11://... — certificate stored in a PKCS#11 token
  • tpm://0x80000001 — certificate key stored in TPM at the specified handle
  • file:///var/crypto/cert.pem — certificate stored on the filesystem

Certificate Renewal

Certificate renewal uses the same CreateKey → ApplyCertificate flow as initial deployment. The process is triggered externally (typically by the cloud during scheduled renewal):

  1. The cloud sends a CreateKey request via the IAM protected API
  2. IAM generates a new key pair and returns the CSR
  3. The cloud signs the CSR with the appropriate CA and sends back the certificate via ApplyCert
  4. IAM applies the new certificate, which becomes the active certificate
  5. If the certificate count exceeds maxCertificates, the oldest certificate is automatically removed

The maxCertificates configuration (minimum 2 for non-self-signed modules) ensures that a valid certificate always exists during renewal — the new certificate is applied before the old one is removed.

Self-Signed Certificates

CertHandler can create self-signed certificates for bootstrap scenarios (before a CA-signed certificate is available). Self-signed certificates:

  • Use CN=Aos Core as both subject and issuer
  • Have a validity period of 100 years
  • Use the current Unix timestamp (nanoseconds) as the serial number
  • Are created through the same key generation and application pipeline

Self-signed modules require maxCertificates of at least 1 (vs. 2 for CA-signed modules).

Certificate Change Notifications

Other components (CM, SM) subscribe to certificate change notifications for specific certificate types. When a certificate is applied or renewed, CertHandler compares the new certificate info against the last known state for each subscriber. If the certificate has changed, the subscriber's OnCertChanged callback is invoked with the updated certificate information.

This mechanism allows components to automatically reload their TLS credentials when certificates are renewed.

Storage Modules

PKCS#11 Module

The PKCS#11 module stores keys and certificates in any hardware or software token that implements the PKCS#11 Cryptographic Token Interface. This provides a unified interface to TPM devices, TEE secure storage, and software HSMs.

Token identification — the module identifies its token by one of:

  • Slot ID (unique hardware identifier)
  • Slot index (position in the slot list)
  • Token label (assigned during initialization)

If configured by label and no initialized token with that label exists, the module initializes the first available uninitialized slot with the configured label.

Object management — PKCS#11 objects (keys, certificates) are identified by:

  • CKA_ID — links a private key, public key, and certificate together
  • CKA_LABEL — set to the storage type, used to distinguish objects when multiple certificate types share a slot

Authentication — token access requires a user PIN, provided via:

  • A PIN file (path configured in userPINPath)
  • TEE identity (OP-TEE PKCS#11 TA) — uses Linux user/group authentication instead of a PIN

Certificate URLs — follow the PKCS#11 URI scheme (RFC 7512), optionally including the module library path.

Configuration parameters:

ParameterDescription
libraryPath to the PKCS#11 shared library
slotIdSlot ID (mutually exclusive with slotIndex and tokenLabel)
slotIndexSlot index (mutually exclusive with slotId and tokenLabel)
tokenLabelToken label (mutually exclusive with slotId and slotIndex)
userPinPathPath to the file containing the user PIN
teeLoginTypeTEE login type: public, user, or group
uidUser ID for TEE user login type
gidGroup ID for TEE group login type
modulePathInURLInclude library path in PKCS#11 URIs

TPM Module

The TPM module uses a TPM 2.0 device for key storage while storing certificates on the filesystem.

Key storage — keys are generated in the TPM and stored in persistent TPM handles. During key creation, keys are held in a temporary pending storage (up to 16 keys). When a certificate is applied, the matching pending key is moved to a persistent TPM handle.

Ownership — the TPM module supports device ownership. The owner password is set during provisioning and required for key creation and removal. Clearing the module removes the owner password and all stored keys and certificates.

Configuration parameters:

ParameterDescription
devicePath to the TPM device
storagePathDirectory for certificate file storage
lockoutMaxTryMaximum authentication failures before lockout
recoveryTimeTime between authentication failure counter decrements
lockoutRecoveryTimeTime to recover from lockout

Software Module

The software module stores both keys and certificates on the filesystem. It is suitable for development and testing environments or systems without hardware security.

Key storage — generated keys are held in RAM (pending key storage, up to 16 keys). When a certificate is applied, the matching key is written to the configured storage directory alongside the certificate.

Certificate hooks — the software module supports a post-apply hook (applyCertHookCmdArgs) — a shell command executed after each certificate is successfully applied. This enables custom integration (e.g., restarting services that use the certificate).

Ownership — not supported by the software module.

Configuration parameters:

ParameterDescription
storagePathDirectory for key and certificate file storage
applyCertHookCmdArgsShell command executed after certificate application

Initialization and Validation

On startup, each certificate module performs database synchronization:

  1. The HSM backend reports all valid certificates, invalid certificates, and invalid keys
  2. Valid certificates are synchronized with the metadata database:
    • Certificates present in the HSM but missing from the database are added
    • Certificates present in the database but missing from the HSM are removed
  3. Invalid certificates and keys are tracked for cleanup during the next key creation

This synchronization ensures the database accurately reflects the actual state of the storage backend, even if certificates were modified outside of IAM (e.g., by external provisioning tools).

Modules with skipValidation enabled bypass this synchronization step (used when the storage backend does not support validation queries).

Module Configuration

Each certificate module is configured in the IAM configuration file with the following common parameters:

ParameterDescription
idCertificate type identifier (e.g., "iam", "sm", "cm")
pluginModule implementation: "pkcs11module", "tpmmodule", or "swmodule"
algorithmKey algorithm: "RSA" or "ECDSA"
maxItemsMaximum number of certificates to retain (minimum 2 for CA-signed, 1 for self-signed)
extendedKeyUsageArray of extended key usages: ["clientAuth"], ["serverAuth"], or both
alternativeNamesDNS alternative names for server certificates
disabledWhether the module is disabled
skipValidationSkip certificate validation on initialization
isSelfSignedModule uses self-signed certificates
paramsModule-specific parameters (PKCS#11, TPM, or software module config)

gRPC API Integration

CertHandler operations are exposed through the IAM gRPC API:

gRPC ServiceRPCCertHandler Operation
IAMCertificateServiceCreateKeyCertHandler::CreateKey → generates key + CSR
IAMCertificateServiceApplyCertCertHandler::ApplyCertificate → stores certificate
IAMPublicCertServiceGetCertCertHandler::GetCert → retrieves certificate info
IAMPublicCertServiceSubscribeCertChangedCertHandler::SubscribeListener → certificate change stream
IAMProvisioningServiceStartProvisioningCertHandler::SetOwner → takes ownership of storage
IAMProvisioningServiceDeprovisionCertHandler::Clear → removes all certificates and keys