By default, ITMS macOS MDM servers use file-based private keys to sign macOS MDM (Modern Device Management) profiles. As of June 1, 2023, the CA/Browser Forum—the industry body that sets global standards for digital certificates—mandated that all publicly trusted code signing certificates must have their private keys stored on hardware that meets specific security standards. So, the CA must verify that private key is generated and stored in a "Hardware Crypto Module." . This article provides a comprehensive guide on reconfiguring an MDM server to use a pre-configured, password-protected USB token for profile signing, taking SafeNet eToken 5110+ FIPS and RHEL 9 as example.
IT Management Suite / MDM (Modern Device Management)
Operating System: RHEL 9
Hardware: SafeNet eToken 5110+ FIPS from DigiCert
Dependencies: OpenSSL, OpenSC, PKCS#11 Engine
PREREQUISITES:
To proceed, you must have the following:
By default, macOS MDM profile signing relies on local certificate files. This procedure replaces the file-based signing method with a hardware-security-module (HSM) flow using OpenSSL and the PKCS#11 engine. This ensures that the private key never leaves the physical token.
The default macOS MDM Profile signing script, sign-profile.sh, is configured for file-based keys. To use a hardware token, the script must be modified.
|
Component |
Purpose |
|
OpenSSL |
Base cryptography library. installed by default in RHEL 9 |
|
PKCS#11 Engine |
Lets OpenSSL use keys and certs on a hardware token (EPEL). |
|
SafeNet Driver |
Hardware-specific driver for the eToken 5110. |
The signing process employs OpenSSL, utilizing a PKCS#11 engine and configuration file, to guarantee that the private key remains secure on the token.
Enable the EPEL 9 repository and install the necessary cryptographic libraries:
Install the vendor-provided driver for the eToken 5110.
EXAMPLE:
The SafeNet tool provided by DigiCert can be installed by following these steps:
On legacy Linux setups, OpenSSL needs an explicit configuration file to load the PKCS#11 engine and point it at the SafeNet module. This configuration file's purpose is to load the PKCS#11 engine and specify the location of the SafeNet module.
vi ~/pkcs11.cnf
and add the following content:
openssl_conf = openssl_init
[openssl_init]
engines = engine_section
[engine_section]
pkcs11 = pkcs11_section
[pkcs11_section]
engine_id = pkcs11
dynamic_path = /usr/lib64/engines-3/pkcs11.so
MODULE_PATH = /usr/lib64/libeTPkcs11.so
init = 0
Where:
dynamic_path: Specifies the path for OpenSSL's PKCS#11 engine, provided by openssl-pkcs11.
MODULE_PATH: The path to the SafeNet library that facilitates communication with the eToken.
init = 0: Ensures the token is not initialized in a manner that would require additional PIN prompts upon the engine's loading; the PIN is supplied during the signing process.
You must export the public certificates from the hardware token. During extract use the exact labels your token uses.
pkcs11-tool --module /usr/lib64/libeTPkcs11.so --login --read-object --type cert --label "DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1" --out token_signing_intermediate.pem
Enter Token PIN when prompted.
Download the root certificate to build a full chain for the signature (In this example DigiCert root certificate is downloaded)
Place the certificates in the MDM service directory.
sudo cp signing.pem /opt/altiris/notification/mdmagent/services/micromdm/certificates/
sudo cp token_intermediate_bundle.pem /opt/altiris/notification/mdmagent/services/micromdm/certificates/
cd /opt/altiris/notification/mdmagent/services/micromdm/certificates/
sudo chmod 644 signing.pem
sudo chmod 644 token_intermediate_bundle.pem
sign_profile() {
openssl cms -sign -binary \
-engine pkcs11 \
-keyform engine \
-in "${PROFILE_TO_SIGN}" \
-signer "${SIGN_CERT}" \
-certfile "${INTERMEDIATE_CERT}" \
-inkey "pkcs11:object=Broadcom Inc.;pin-value=123456" \
-md sha256 \
-outform DER \
-nodetach
}
Where:
|
- pkcs11:object=Broadcom Inc. |
Value must match the key/cert label stored on the token. |
|
- pin-value=123456 |
Value must match your Token PIN, you may provide PIN here via environment variable or any other approach. |
if [ -z ${OUTPUT} ]; then
if [ ${OUTPUT_AS_BASE64} = 1 ]; then
sign_profile | base64 -w0
else
sign_profile
fi
else
if [ ${OUTPUT_AS_BASE64} = 1 ]; then
sign_profile | base64 -w0 > ${OUTPUT}
else
sign_profile > ${OUTPUT}
fi
fi
pkcs11-tool --module /usr/lib64/libeTPkcs11.so --list-slots
pkcs11-tool --module /usr/lib64/libeTPkcs11.so --list-objects –login
When prompted, enter your Token PIN. You should then observe the token's slots and objects without any fatal errors.
export OPENSSL_CONF=~/pkcs11.cnf && openssl engine pkcs11 -t
The expected outcome is the visibility of the pkcs11 engine and the absence of any fatal errors.
|
Symptom |
Check |
|
"Engine not found"
|
Verify OPENSSL_CONF is set and the paths in pkcs11.cnf are correct:
|
|
"Could not find object" |
Ensure the token is plugged in and the -inkey label matches pkcs11-tool output: |
|
PIN Errors |
Verify the pin-value in the script; ensure the token is not locked. |