MPC vs HSM: Which Key Management Approach Secures Your Enterprise?
Feb 25, 2026
ArticleCompare HSM, MPC and software-defined HSM (SD-HSM) for cloud programmes: single points of failure, TCO and when each custody model fits.
Read article
Move the Oracle TDE master key off the database host with an HSM-type PKCS#11 keystore: setup, rekey, auto-login, CDB/PDB notes and ORA- error fixes.
Oracle Transparent Data Encryption (TDE) protects data files and backups well, but only as well as it protects the one key that unlocks everything else: the TDE master encryption key. By default that key sits in a wallet file on the database server, next to the data it protects. Anyone who gets that server, or a backup that includes the wallet, gets the key along with it.
This guide covers how TDE's two-tier key model works, what changes when the master key moves into an external, HSM-type keystore reached over PKCS#11, and how to set up DuoKey's PKCS#11 library as that keystore step by step. It also covers rekeying, auto-login trade-offs, multitenant (CDB/PDB) details and the ORA- errors you're most likely to hit along the way.
TDE column encryption and TDE tablespace encryption both use a two-tier key architecture (Oracle: Introduction to TDE):
| Tier | What it is | What it does |
|---|---|---|
| TDE master encryption key | One active key per keystore, stored in a security module outside the data files | Encrypts (wraps) the table and tablespace keys |
| Tablespace key / table key | One per encrypted tablespace, and one per table with encrypted columns | Encrypts and decrypts the actual data |
Oracle is explicit about what this buys you: unauthorized users "cannot read the data from storage and back up media unless they have the TDE master encryption key to decrypt it." For column encryption, TDE uses a single table key per table, however many columns are encrypted, and each table key is individually encrypted with the master key (Oracle: Introduction to TDE).
Two properties of this model drive everything else in this guide:
The first property is why an external keystore doesn't slow down queries. DuoKey sits only on the master-key path. Oracle keeps doing bulk table and tablespace encryption itself, locally, with AES-NI (DuoKey docs: Oracle TDE overview).
Oracle selects where the master key lives with the KEYSTORE_CONFIGURATION attribute of the TDE_CONFIGURATION parameter. FILE configures a wallet keystore and HSM configures a hardware security module (Oracle: TDE_CONFIGURATION).
Software wallet (FILE) | External keystore (HSM) | |
|---|---|---|
| Where the master key lives | A PKCS#12 wallet file on the database server, encrypted with a key derived from the wallet password (Oracle) | Outside the database, in a separate server or device (Oracle) |
| Who controls how the key is stored | Oracle, through SQL | The external keystore. Oracle "can request the external keystore to create a key but it cannot define how this key is stored" (Oracle) |
| Keystore backups | WITH BACKUP is mandatory for password-protected software keystores (Oracle) | Optional; Oracle Database cannot back up external keystores (Oracle) |
| Keystore open | Wallet password, or an auto-login wallet file | Keystore credential, or an auto-login secret (see Auto-Login Considerations) |
With DuoKey, Oracle sees an ordinary HSM keystore: WRL_TYPE = HSM in V$ENCRYPTION_WALLET. It loads the DuoKey PKCS#11 provider, which turns each master-key operation into an HTTPS call to DuoKey Cockpit. Cockpit performs the operation against the tenant vault or HSM. For hardware key custody, DuoKey partners with Securosys (DuoKey docs: Oracle TDE overview). The library itself holds no keys and performs no cryptography locally, and master-key bytes are never returned to Oracle (DuoKey docs: Oracle TDE integration).
Host or DBA compromise. With a local wallet, privileged access to the server exposes the wallet, and with it the master key (DuoKey docs: Oracle TDE overview). With an external keystore, the key material is never on the host to copy. An attacker who controls a live host can still ask the keystore to unwrap keys while access is granted. What changes is that the key can't be taken away and used elsewhere, every operation is logged centrally, and access can be cut off centrally.
Backups. TDE's promise is that stolen data files and backup media are unreadable without the master key (Oracle). That promise weakens if the wallet travels with the backups. A default auto-login wallet is especially exposed, because it "can be opened from computers other than the computer on which the keystore resides" unless it was created with LOCAL (Oracle: ADMINISTER KEY MANAGEMENT).
Separation of duties. Oracle notes that an external security module lets you assign distinct duties to database administrators and security administrators, and that the keystore password can be unknown to the DBA (Oracle). You can grant ADMINISTER KEY MANAGEMENT or SYSKM only to the people who manage keys. With DuoKey, key lifecycle (create, rotate, deactivate, destroy) is managed in Cockpit under role-based access control, so DBAs run the database and security administrators run the keys (DuoKey docs: Oracle TDE overview).
Regulation and audit. DuoKey's documentation positions an external HSM keystore with a full audit trail as support for PCI DSS, HIPAA and GDPR requirements (DuoKey docs). For how key custody maps to DORA's ICT risk articles, see our DORA encryption checklist.
Read this before you plan a deployment. Oracle's current reference for TDE_CONFIGURATION describes the HSM value and then states: "Oracle does not support the use of HSMs for TDE key management." It points to My Oracle Support note KB593570, "Oracle TDE Support With 3rd Party HSM Vendors" (Oracle: TDE_CONFIGURATION). The current Advanced Security Guide lists Oracle Key Vault and OCI Vault as the external keystores Oracle Database supports (Oracle: Configuring TDE).
What this means in practice:
HSM keystore type is still a valid KEYSTORE_CONFIGURATION value, and ADMINISTER KEY MANAGEMENT still documents hardware-keystore syntax (Oracle). The setup below uses exactly those mechanisms.ADMINISTER KEY MANAGEMENT or SYSKM for keystore and key operations (Oracle), plus ALTER SYSTEM for the parametersWALLET_ROOT and TDE_CONFIGURATION. From 18c, TDE configuration in sqlnet.ora is deprecated (Oracle: united mode). Older releases, including the 12.2.0.1 base release, need the sqlnet.ora method instead (DuoKey docs: Troubleshooting)libdke_pkcs11.so on Linux, dke_pkcs11.dll on WindowsThe Linux library must link against a glibc no newer than the one on the database host. DuoKey's standard Linux build targets Oracle Linux 8 (glibc 2.28). A build the host can't load fails silently from Oracle's point of view: ORA-28353: failed to open wallet, with no provider log at all. Don't infer the OS from the Oracle version: Oracle's own 19.3.0.0 Enterprise Edition container image runs Oracle Linux 7.9 with glibc 2.17 (DuoKey docs: Troubleshooting). Check first, as the oracle user:
ldd --version | head -1
If it reports a glibc older than 2.28, ask DuoKey for the build that matches your host.
This follows DuoKey's Getting Started guide. The Cockpit deployment bundle gives you every value used below.
In Cockpit, open Apps, create a new app of type Oracle TDE, and export its deployment bundle. Creating the app provisions an initial active AES-256 master key. The bundle contains the pkcs11.toml file, the library install commands, the environment exports and the Oracle SQL scripts in the right run order. Treat the whole bundle as sensitive and keep it out of version control (DuoKey docs: Getting Started).
Oracle scans a fixed vendor directory for PKCS#11 HSM libraries and loads the first shared object it finds there. Keep the library's shipped name. Don't rename it to libpkcs11.so:
sudo mkdir -p /opt/oracle/extapi/64/hsm/DuoKey/1.0
sudo cp libdke_pkcs11.so /opt/oracle/extapi/64/hsm/DuoKey/1.0/
sudo chown -R oracle:oinstall /opt/oracle/extapi/64/hsm/DuoKey
sudo chmod -R 755 /opt/oracle/extapi/64/hsm/DuoKey
Two details catch people out (DuoKey docs: Getting Started):
/opt/oracle/extapi/64/hsm/... is used even if your ORACLE_BASE is somewhere else, such as /u01/app/oracle.On Windows the library is dke_pkcs11.dll, placed at the fixed system-drive path C:\oracle\extapi\64\hsm\DuoKey\1.0\. The Oracle service account (NT SERVICE\OracleService<SID>) must be able to read pkcs11.toml (DuoKey docs: Getting Started on Windows).
The library reads its configuration from the file named in DKE_PKCS11_CONF. It holds the Cockpit proxy URL for this app and a single bearer credential. There are no OAuth2 client IDs or secrets, no username or password, and no tenant or vault settings. The tenant is resolved server-side (DuoKey docs: pkcs11.toml).
[http_config]
server_url = "<proxy-url-from-your-bundle>" # embeds your app id and <access-guid>
access_token = "<access-token>" # the bearer credential
timeout_secs = 30
verify_tls = true
[pkcs11]
slot_id = 0
logging_level = "info"
logging_folder = "/var/log/dke-pkcs11"
Copy the file from the bundle as is, restrict it to the oracle user, and export the variable in that user's profile:
sudo chown oracle:oinstall <config-dir>/pkcs11.toml
sudo chmod 600 <config-dir>/pkcs11.toml
export DKE_PKCS11_CONF=<config-dir>/pkcs11.toml
The instance itself must inherit DKE_PKCS11_CONF, not just your SQL*Plus session. Start the database from a login shell that sources the profile. Otherwise Oracle's background HSM heartbeat check can fail later, even though a manual keystore open worked (DuoKey docs: Troubleshooting).
Optionally, sanity-check the library outside Oracle with OpenSC's pkcs11-tool:
pkcs11-tool --module /opt/oracle/extapi/64/hsm/DuoKey/1.0/libdke_pkcs11.so --list-slots
WALLET_ROOT is a static parameter, so it takes a restart (Oracle: WALLET_ROOT). TDE_CONFIGURATION only takes effect once WALLET_ROOT is set (Oracle: TDE_CONFIGURATION). Create the directory first, then:
ALTER SYSTEM SET WALLET_ROOT='<wallet-root>' SCOPE=SPFILE;
-- RAC: add SID='*'
SHUTDOWN IMMEDIATE;
STARTUP;
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM' SCOPE=BOTH;
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN
IDENTIFIED BY "<pin>"
CONTAINER = ALL;
ADMINISTER KEY MANAGEMENT SET KEY
IDENTIFIED BY "<pin>"
WITH BACKUP
CONTAINER = ALL;
Keep three things in mind:
access_token in pkcs11.toml. It must still be a literal quoted string (DuoKey docs: Getting Started).IDENTIFIED BY EXTERNAL STORE. With this provider it raises ORA-00988 (DuoKey docs).ORA-28365 right after a successful open (DuoKey docs).SELECT con_id, wrl_type, status, wallet_type FROM v$encryption_wallet;
-- expect WRL_TYPE = HSM, STATUS = OPEN
CREATE TABLESPACE encrypted_ts
DATAFILE '<oradata-path>/encrypted_ts01.dbf' SIZE 128M
ENCRYPTION USING 'AES256' DEFAULT STORAGE(ENCRYPT);
SELECT tablespace_name, encrypted FROM dba_tablespaces WHERE encrypted = 'YES';
SELECT key_id, activation_time FROM v$encryption_keys;
Then confirm that the key operations show up in the Cockpit audit log for this app (DuoKey docs: Getting Started). If the database is only mounted, an external keystore can report OPEN_UNKNOWN_MASTER_KEY_STATUS, because the data dictionary isn't available yet (Oracle: Configuring TDE).
SET KEY creates a new master key and activates it. Any key that was active is deactivated first (Oracle: ADMINISTER KEY MANAGEMENT):
-- Keystore opened manually
ADMINISTER KEY MANAGEMENT SET KEY
IDENTIFIED BY "<pin>" WITH BACKUP CONTAINER = ALL;
-- Auto-login keystore in use
ADMINISTER KEY MANAGEMENT SET KEY FORCE KEYSTORE
IDENTIFIED BY "<pin>" WITH BACKUP CONTAINER = ALL;
FORCE KEYSTORE lets the operation run even if the keystore is closed (Oracle).
You can also rotate from Cockpit. Rotation makes a new key active and deactivates but keeps the previous one, so tablespace keys wrapped under older master keys stay decryptable. Cockpit returns the matching Oracle rotation SQL (DuoKey docs: Getting Started). DuoKey's documentation recommends rotating production master keys every 6 to 12 months (DuoKey docs: Key Management).
Deactivate, don't destroy. Destroying a master key in the Oracle TDE app is permanent. Anything encrypted under it becomes unreadable the next time Oracle has to unwrap a key through it, and there is no restore path (DuoKey docs: Key Management). Only destroy a key when nothing still depends on it.
On the TDE path, table and tablespace keys are wrapped and unwrapped under the master key with length-preserving AES-CBC with padding. Oracle expects the unwrapped key to be exactly the size it wrapped (DuoKey docs: Oracle TDE integration).
By default, an HSM keystore has to be opened by hand after every restart. For unattended restarts, Oracle's pattern is to store the external keystore's credential as a secret under the Oracle-defined client name HSM_PASSWORD in an auto-login software wallet (Oracle 18c: Managing the Keystore). With DuoKey, run this once at the CDB root:
ADMINISTER KEY MANAGEMENT SET KEYSTORE CLOSE IDENTIFIED BY "<pin>" CONTAINER = ALL;
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=FILE' SCOPE=BOTH;
ADMINISTER KEY MANAGEMENT CREATE KEYSTORE '<wallet-root>/tde' IDENTIFIED BY "<pin>";
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY "<pin>" CONTAINER = ALL;
ADMINISTER KEY MANAGEMENT ADD SECRET '<pin>' FOR CLIENT 'HSM_PASSWORD'
IDENTIFIED BY "<pin>" WITH BACKUP;
ADMINISTER KEY MANAGEMENT SET KEYSTORE CLOSE IDENTIFIED BY "<pin>";
ADMINISTER KEY MANAGEMENT CREATE AUTO_LOGIN KEYSTORE
FROM KEYSTORE '<wallet-root>/tde' IDENTIFIED BY "<pin>";
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM|FILE' SCOPE=BOTH;
After a restart the keystore is already OPEN. Use FORCE KEYSTORE when rotating.
Before you turn this on, weigh the trade-offs:
access_token in pkcs11.toml, so protecting that file is what matters. If the credential is ever exposed, rotate the app's access token from Cockpit (DuoKey docs: pkcs11.toml).LOCAL carefully. LOCAL ties an auto-login wallet to the host that created it, so omit it on RAC, where every node needs to open the same credential (Oracle 18c).CONTAINER = ALL opens the keystore in the root and in all PDBs. CONTAINER = CURRENT opens it in the root only (Oracle: ADMINISTER KEY MANAGEMENT).OPEN READ WRITE during a CONTAINER = ALL rekey causes ORA-46664 ("master keys not created for any PDBs during REKEY"). Open the PDB, or key the root first and then each PDB in its own session (DuoKey docs: Troubleshooting):SELECT con_id, name, open_mode FROM v$pdbs ORDER BY con_id;
ALTER SESSION SET CONTAINER = <pdb_name>;
ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY "<pin>" WITH BACKUP;
ALTER PLUGGABLE DATABASE ALL OPEN, which also targets the read-only PDB$SEED and can fail with ORA-65054.pkcs11.toml. If two instances share one app, they share one master key, and destroying it breaks both (DuoKey docs: Key Management).If a database already uses a local TDE wallet, MIGRATE USING decrypts the existing table and tablespace keys with the software-keystore master key and re-encrypts them under a new master key in the hardware keystore (Oracle: ADMINISTER KEY MANAGEMENT). HSM|FILE is the KEYSTORE_CONFIGURATION value for migrating from a wallet to an HSM (Oracle: TDE_CONFIGURATION).
With the library and pkcs11.toml in place:
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM|FILE' SCOPE=BOTH;
ADMINISTER KEY MANAGEMENT SET ENCRYPTION KEY IDENTIFIED BY "<pin>"
MIGRATE USING "<software-wallet-password>" WITH BACKUP;
Both keystores must show OPEN during the migration. Once it completes, you don't need to restart or reopen the external keystore, because the migration reloads the keys in memory (Oracle 18c). Keep the old wallet: RMAN backups and Data Pump exports taken under earlier keys may still need it (Oracle 18c).
To move off a third-party HSM, first reverse-migrate its key into a local wallet with REVERSE MIGRATE USING. Then remove the old vendor library from /opt/oracle/extapi/64/hsm/, install DuoKey's, and migrate forward as shown above (DuoKey docs: Key Management).
Check the provider log (logging_folder, /var/log/dke-pkcs11/ by default) first. An empty log after a failure means the library never loaded (DuoKey docs: Troubleshooting).
Most often a glibc mismatch: the library was built for a newer glibc than the host has. Other causes are a library in the wrong directory, a renamed library, or the oracle user being unable to read the library or pkcs11.toml. Compare ldd --version with the build you deployed, and run ldd against the library to look for not found (DuoKey docs).
You used IDENTIFIED BY EXTERNAL STORE. Use a literal quoted PIN instead (DuoKey docs).
Either the HSM heartbeat closed the keystore between two separate sessions, or, after a restart, auto-login isn't configured. Run the open and the dependent statement in one script, or complete Auto-Login Considerations (DuoKey docs).
A target PDB wasn't OPEN READ WRITE. See Multitenant Notes.
TDE_CONFIGURATION was set before the WALLET_ROOT restart took effect. Restart first, then set it.
SET KEY ran before the database, or the PDB, finished opening read-write. This is common right after a restart. Wait until v$database.open_mode shows READ WRITE.
The provider reached Cockpit, but the request failed or was rejected. Check that server_url points at the Cockpit API hostname, not the browser UI. A wrong host can still return HTTP 200, but with an HTML page instead of JSON. Also check that access_token matches the app's current credential, that the app is enabled, and that no proxy in between strips the Authorization header. Re-download the bundle rather than editing the token by hand (DuoKey docs: Troubleshooting).
The key wrap on the TDE path wasn't length-preserving. Oracle TDE needs AES-CBC with padding here, not an expanding AES-GCM envelope. Contact DuoKey support, re-download the bundle, and rekey once it's corrected (DuoKey docs).
The instance was started without DKE_PKCS11_CONF in its environment, so the background heartbeat check fails. Persist the variable in the oracle user's profile and always start the database from a login shell (DuoKey docs).
Q: Does an external keystore slow down queries?
No. Bulk table and tablespace encryption stays local on the database host. DuoKey is only involved in keystore open, SET KEY and wrapping or unwrapping table and tablespace keys (DuoKey docs).
Q: What keystore type do I configure in Oracle?
HSM, through TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM', or HSM|FILE for auto-login and migration. V$ENCRYPTION_WALLET then reports WRL_TYPE = HSM.
Q: Does Oracle support HSMs for TDE key management?
Oracle's current TDE_CONFIGURATION reference says it does not, and points to My Oracle Support note KB593570 (Oracle). The HSM keystore type is still documented and still works. Review the note and agree the support model with DuoKey before production; see Oracle Support Position.
Q: Should I rename the library to libpkcs11.so?
No. Install libdke_pkcs11.so unchanged under /opt/oracle/extapi/64/hsm/DuoKey/1.0/. Oracle loads the first shared object in that directory whatever its name.
Q: What does the PIN in IDENTIFIED BY actually protect?
Nothing on the DuoKey side. Oracle's grammar requires it, but the credential that authorizes master-key operations is access_token in pkcs11.toml. Protect that file (chmod 600, owned by oracle).
Q: Can I still read old backups after rotating the master key?
Yes. Rotation deactivates the previous master key but keeps it, so data wrapped under it remains decryptable. Only destroying a key removes it.
Q: What credentials does pkcs11.toml hold?
One bearer credential, access_token, plus the Cockpit proxy URL, which embeds the app's non-secret access_guid. There is no OAuth2 client ID or secret, no username or password, and no tenant or vault field (DuoKey docs).
Q: Do I need a separate DuoKey app per database?
Yes, one per database instance. Sharing an app means sharing a master key, and with it the blast radius of any destructive key operation.
Moving the TDE master key into an external keystore changes who can use it and how you'd know. The key no longer sits in a file next to the data. Every use goes through an audited, centrally controlled path, and bulk encryption performance is unchanged.
ldd --version on the host matches the library build you deployedlibdke_pkcs11.so is installed unchanged and alone in /opt/oracle/extapi/64/hsm/DuoKey/1.0/pkcs11.toml is 600, owned by oracle, and DKE_PKCS11_CONF is inherited by the instanceWALLET_ROOT is set and the instance restarted before TDE_CONFIGURATION=HSMSET KEY ran in one session, with a literal quoted PINV$ENCRYPTION_WALLET shows HSM / OPEN in every container, and a test tablespace round-tripsFor the product view, see DuoKey for Oracle TDE. For other databases and platforms, see integrations.
Written by
Nagib Aouini
Related Resources
Tell us where control is difficult today. We will help you identify a practical next step.