Cosmian provides readily available, easy to use software components, based on next-generation cryptography to secure data and applications in all environments, from the cloud to the edge.
This is the technical documentation
This site provides the technical documentation of the components. It provides information for technical users, architects to developers.
The documentation is divided by security use cases and then by products.
Security use cases
-
Architecture security of data and applications with a mapping of threats to solutions and a review of common architecture uses cases.
-
Use modern encryption schemes such as:
-
Advanced encryption schemes on client-side encryption (or application level encryption) and server-side encryption:
-
Cosmian Covercrypt: Protect data with the latest post-quantum encryption, access control, and traceable keys.
-
Cosmian KMS: Central point of security for managing encryption keys and enabling server-side encryption.
-
-
Alternative encryption schemes
-
Cosmian FPE: Selectively encrypt data while preserving the data format with format-preserving encryption.
-
Anonymizing clear-text data with Cosmian Anonymization
-
-
-
Compute over encrypted data with Cosmian's Verifiable Confidential Computing solutions:
-
Solutions based on Confidential Virtual Machine:
-
Cosmian VM: quickly secure data in any running application in the cloud.
-
Cosmian AI: Benefit of Cosmian VM and leverage advanced AI models with built-in privacy and security features.
-
-
Solutions based on Intel SGX enclave:
- Cosmian Enclave (formerly MSE): protects algorithms and data in the cloud and on 3rd party premises with maximum security.
-
-
Searching encrypted data with Cosmian Findex and Findex server: run encrypted queries on an encrypted index.
Cosmian products
- Cosmian KMS: A modern, open-source, highly-scalable key management system that is KMIP 1.x/2.x compliant.
- Cosmian VM Secure data in any running application in the cloud.
- Cosmian AI: Leverage advanced AI models with built-in privacy and security features.
- Cosmian Enclave: Protect algorithms and data in the cloud and on third-party premises with maximum security.
- Cosmian Findex Server: Run encrypted queries on an encrypted index with server-side capabilities.
- Cosmian CLI: Command-line interface for managing and interacting with Cosmian's suite of tools.
If you want to see our technology in action and "play" with it, please visit our Interactive Tutorial

For pricing, check the website
For pricing information, general information on Cosmian and its products, please visit our website
All our code is open-sourced on GitHub
All our code is available on GitHub
Chat with us
To chat with our technical team, please join our Discord server
Legal
End User License Agreements
Terms and Conditions
- For Packs
The first step in understanding how to secure data and applications in a zero-trust environment is to look at potential attackers and their threat model. We assume the application code is safe and that we do not need to protect against the software developer.
| Attacker | Access | Threats |
|---|---|---|
| Passive 3rd party | insider | may get a copy of the disks content |
| Man in the middle | external network | may intercept the data in transit |
| Infrastructure admin. | physical access + network | may externally look at memory, disk contents and network traffic may change hardware or spoof server names, redirect traffic |
| System admin. | OS level access | may access and change memory, disks content and network traffic. may modify the code or run malicious code |
| Application admin. | authorization stack | may escalate privileges to access the data |
Protection against all attackers
Client-side encryption is the only ubiquitous solution that protects against all attackers because data is encrypted by the data owner under its own key before it reaches any of these attackers. Enabling client-side encryption without loss of functionality usually requires a modification to the application and the use of a few Cosmian products: Cosmian Covercrypt, Cosmian KMS, and possibly Cosmian VM and Cosmian Findex.
See the last use case on this page for details.
Protection against a reduced list of attackers
When the threat model is limited to a reduced list of attackers, other solutions may be used. The following table summarizes the solutions that Cosmian provides to protect against each attacker.
| Attacker | Solution Name | Cosmian Products |
|---|---|---|
| Passive 3rd party | Encryption at rest | Cosmian Covercrypt: post-quantum encryption with access policies Protects against the "Harvest now, decrypt later" risk + limits key leakage |
| Man in the middle | Encryption in transit | TLS |
| Infrastructure admin. | Memory Encryption | Cosmian Enclave or Cosmian VM: verifiable encrypted memory at runtime |
| System admin. | Sealed Encrypted Memory | Cosmian Enclave: verifiable enclaved encrypted memory at runtime that is immutable from the outside (the underlying OS) |
| Application admin. | Covercrypt encryption | Client-side encryption with Cosmian Covercrypt: access policies in user decryption keys prevent the user from decrypting data not authorized by its key |
Use case: move to the cloud
When moving an application for its own users to the cloud, the main threat is the cloud provider itself. It is assumed that the system administrators and the application administrators are trusted.
In that particular case the use of TLS connections to applications running in Cosmian VMs with a simple at-rest encryption scheme is sufficient to protect the data and the application from the cloud provider. The Cosmian VM integrity is remotely verifiable by the user, preventing the infrastructure administrator from tampering with the VM hardware or software.
Use case: protect code at client's premises (or client's cloud)
When the application code is to be deployed at a client premises (or cloud), and needs to remain secret (such as an AI model), the main threat is the client's system administrator.
Cosmian Enclave is the solution that lets the code provider encrypt its code under its own key, deliver it encrypted to the client's system administrator. The encrypted code is then loaded in an enclave with encrypted memory, and before securely provisioning the code encryption key to the enclave, the code provider can then verify that the code is correctly deployed inside the enclave. Check this section for more details.
Use case: a 3rd party SaaS platform running in the cloud
From a user's perspective this is the use case where its data is exposed to all potential attackers: client side encryption will be the answer to protecting its data.
Enabling client-side encryption
From the SaaS provider perspective, this means making a client-side encryption API available to its users. If the application offers a web interface, the web application will need to be modified to encrypt the data before sending it to the servers. Encryption will require the ability to connect to a KMS from the web application. Performing encryption client-side will require
- either Cosmian javascript (or Dart, or Java, etc.) encryption libraries running client-side with calls to the Cosmian KMS server to fetch keys
- or direct encryption/decryption calls to the Cosmian KMS which can perform encryption on the fly in a scalable manner.

An example: Google Workspace
Google Workspace is a good example of a SaaS application that offers client-side encryption out of the box. Google made an API available that allows connecting compatible Key Management Systems such as Cosmian KMS to encrypting data in the browser.

Thanks to Cosmian VM, the user does not even have to install its KMS on premise. The KMS can be deployed in a Cosmian VM on GCP, which will protect it from Google and its browser can connect to it over a TLS connection.
Likewise, other services, such as document summarization using a language model, can be deployed in a Cosmian VM and made available to the user through a web interface. The user's data will be encrypted by the TLS connection to the AI service and will only be available to service in encrypted memory which is protected from Google.
Cosmian VM and Cosmian KMS are now offered as IaaS services on the marketplaces of all major hyperscalers Azure, AWS and GCP.
- Cosmian VM and KMS on AWS Marketplace
- Cosmian VM and KMS on Azure Marketplace
- Cosmian VM and KMS on GCP Marketplace
SaaS platform: distributing keys between clients
When using client-side encryption in a SaaS platform setting, some users may need to be able to decrypt data from another user that was encrypted with a key that they do not have. This is the case, for example, when a user shares a document with another user. The document is encrypted with the key of the user that created it.
The Cosmian KMS offers a key sharing mechanism that allows users to share keys with other users. The key sharing mechanism is based on a standard Public Key Infrastructure (PKI) available in the KMS which offers the ability to wrap a decryption key under the public key of another user. The receiving user can then unwrap the key using its own private key.
The users can safely use the Cosmian KMS PKI deployed in the cloud because the KMS does not have access to the private keys of the users.

Say Client 1 wants to provide Client 2 with a decryption key sk_a to decrypt data previously encrypted with Covercrypt with Client 1's public key pk_1.
This decryption key is sensitive and should be wrapped under Client 2's public key to be transferred from Client 1's KMS to Client 2's KMS. Since their KMS cannot communicate, the clients are using the Public Key Infrastructure (PKI) built in Cosmian KMS to exchange keys.
The typical flow for the distribution of a decryption key is illustrated in the following diagram.
Say Client 1 wants to provide Client 2 with a decryption key sk_a to decrypt data previously encrypted under Client 1's key.
Client 2(the recipient) generates a key pairsk_2/pk_2and publishes its public keypk_2wrapped in a certificate to the SaaS PKI.Client 1recoversClient 2's certificate containingpk_2.Client 1wraps (i.e., encrypts) the decryption keysk_aunder the public keypk_2and publishes the wrapped key in the SaaS PKI.Client 2recovers the wrapped keysk_afrom the SaaS PKI and unwraps it (i.e. decrypts it) using its private keysk_2.
Covercrypt is a post-quantum public key encryption scheme that allows encrypting data for a set of attributes in order to provide fine-grained partitioning.
Covercrypt is being developed in partnership with the ENS cryptographic Lab , has been published at the ESORICS 2023 conference and is being standardized at ETSI. Covercrypt is coded in Rust and the source is available on GitHub.
Unique Decryption Keys with Access Policies
Consider the following 2 policy axes, Department and Country which data are partitioned by the following
attributes:
Department,Finance,Marketing,Human Res.andSalesCountry,France,UK,SpainandGermany
Each pair (Department, Country) constitutes one of the $4^2=16$ data partitions.
When defining the Policy for these partitions, Covercrypt offers the ability to selectively choose which partition is protected by post-quantum cryptography.
With Covercrypt, the encryption key is public. Encrypting systems (A browser, a mobile phone, a Spark process, data engineering applications, ETLs, etc...) do not have to be secured and can directly hold the key, relaxing constraints on the infrastructure. The public key can encrypt for any partition defined by the policy.
Decryption keys can decrypt a subset of the partitions defined by the policy.

Key 1 can decrypt all the France data with the following access policy:
Country::France
Key 2 can decrypt all the Sales data with the following access policy:
Department::Sales
Key 3 can decrypt the Marketing and Sales data from Spain and Germany with the following access policy:
(Department::Marketing || Department::Sales) && (Country::Spain || Country::Germany )
User keys are truly unique: even though two users have the same access policy, their key fingerprints will be different. This makes it much easier for forensic cyber teams to trace a key leak.
Policy axes can be hierarchical. Suppose three levels on a Confidentiality axis: Medium, Secret,
and Top Secret. This hierarchical axis will let users with a Top Secret attribute in their key access policy
decrypt Medium, Secret, and Top Secret data – whereas users with a Medium attribute will only be able to
decrypt Medium data.
Finally, attributes can be rotated providing forward secrecy on selected partitions only.
The libraries are available in multiple languages to facilitate encryption close to the data source and decryption close to the decryption target, including mobile devices and browsers.
This section describes the Application Level Encryption API, the Encrypted Search API is on this page.
Supported Languages
The application-level encryption scheme is called Covercrypt. It is open-source and written in Rust. For the cryptographic documentation and implementation details, please check its GitHub repository.
Unless low-level programming in Rust, implementers should use Covercrypt through the various cloudproof_xxx user
libraries:
- cloudproof_java: the Cloudproof Java Library,
- cloudproof_js: the Cloudproof Javascript Library,
- cloudproof_python: the Cloudproof Python Library,
- cloudproof_flutter: the Cloudproof Flutter Library.
- cloudproof_spark: the Cloudproof Spark Library.
All these libraries are open-source and available on GitHub
The user libraries all contain extensive tests, and it is highly recommended to start by hacking those tests.
Installing the Libraries
It is possible to create keys using the libraries; however, it is more likely that you will want to store them in a KMS. Please go to the KMS documentation to fetch and run a local KMS.
The library is published on npm: simply install the library in your package.json
npm install cloudproof_js
The library contains web assembly for cryptographic speed
You need Java 8+ and Maven version 3+
The cloudproof_java library is deployed on Maven central.
Add the library to your POM:
<dependency>
<groupId>com.cosmian</groupId>
<artifactId>cloudproof_java</artifactId>
<version>8.0.1</version>
<type>jar</type>
</dependency>
Encryption and decryption can be accomplished in the KMS, however, you will likely want to perform them locally using the native library, compiled from Rust.
The cloudproof_java library leverages Java Native Access to call the native library.
Builds of the native libraries are already provided on package.cosmian.com and can be fetched and copied via the Python script ./scripts/get_native_libraries.py to:
src/main/resources/linux-x86-64(with support of GLIBC 2.17+)src/main/resources/darwin-x86-64src/main/resources/win32-x86-64
python3 scripts/get_native_libraries.py
To build the library yourself, please see the Covercrypt project. In your java project, the library build needs to be placed inside in
src/main/resources/linux-x86-64folder for a Linux Intel machinesrc/main/resources/linux-amd64folder for a Linux AMD machinesrc/main/resources/darwinfolder for a Mac running MacOSsrc/main/resources/win32-x86folder for a Windows machine
To run tests only, place the library inside the corresponding folder above replacing main with test
Check the JNA documentation for alternative locations for the native library.
To use the native library, use statically the class Covercrypt object.
byte[] ciphertext = CoverCrypt.encrypt(...);
The instance is thread-safe and can be used for all subsequent calls.
The version 5.0.0 is available on PyPI:
pip install cloudproof_py
Import classes:
from cloudproof_py.cover_crypt import Policy, PolicyAxis, Attribute, CoverCrypt
# needed if you use Cosmian KMS
from cloudproof_py.kms import KmsClient
The library is published on pub.dev as a Dart library: https://pub.dev/packages/cloudproof. To install it:
flutter pub add cloudproof
The published package contains cryptographic native libraries called through FFI functions.
Download the prebuilt libraries and header for released versions at https://github.com/Cosmian/cloudproof_cpp/releases.
Include header file:
#include "cloudproof.h"
- Compile and run on Linux
g++ main.cpp -o main -I include/ -L lib/ -lcloudproof
LD_LIBRARY_PATH=lib ./main
- Compile and run on MacOS
g++ main.cpp -o main -I include/ -L lib/ -lcloudproof
DYLD_FALLBACK_LIBRARY_PATH=lib ./main
- Compile and run on Windows
cl main.cpp /I "include" /link "lib/libcloudproof.dll.a" /OUT:main.exe
main.exe
cloudproof.dll should be in the same directory as main.exe
Creating a Policy
A policy defines the space of rights that are used for encryption. It is composed by a set of axes that contain attributes.
For example, the following two axes are divided into four attributes and define a policy:
Department:Finance,Marketing,Human Res.,SalesCountry:France,UK,Spain,Germany
A combination of axis attributes is associated to a partition. For example
Department::Finance && Country France points to a valid partition under the above
policy.
An access policy is defined by a set of partitions. It can be written as a boolean expression of axis attributes:
(Department::Marketing || Department::Sales) && Country::France
In the following demo, we will create a policy that combines two axes, a
security level, and a department. A user will be able to decrypt data only
if it possesses a key with a sufficient security level and the correct
department.
Policy Axes
Security Level Axis:
The first policy axis is the Security Level. It is hierarchical and is
composed of 3 levels: Protected, Confidential, and Top Secret. Since this
axis is hierarchical, when a user is granted access to a given level, it is
granted access to all lower levels. The attributes must be provided in
ascending order.
Department Security Axis:
The second policy axis is the Department axis. It is composed of 3 values:
HR, MKG, and FIN. This axis is not hierarchical: granting access to an
attribute of this axis to a user does not give access to any other attribute.
Hybridization
Covercrypt offers the possibility to hybridize the classic asymmetric scheme with the winner of the NIST post-quantum algorithm selection process: Kyber. Hybridization can be applied with granularity since it is specified at the attribute level. A partition corresponding to a combination of attributes with at least one hybridized attribute is hybridized. Any data encrypted for a hybridized partition will result in a hybridized ciphertext.
Rotations
Rotations allow to refresh the value of a given partition. The maximum number of creations of partition values is set in the policy.
Generating the Master Keys
The master authority possesses the master key pair:
- a master secret key which is used to generate user keys;
- and a public key which is used for encryption. Since it cannot decrypt, the public key can be freely distributed to encrypting systems.
Keys can be generated locally using the WASM code
To generate keys you can use a Cosmian KMS server and, unless you run in dev mode, an API Key to authenticate to the server.
To generate keys from a Cosmian KMS server, instantiate a KmsClient with its URL
and, unless you run in dev mode, an API Key to authenticate to the server.
And create master keys
The master keys can be exported from the KMS and their bytes recovered to use with the native library
To use the native library, simply instantiate a CoverCrypt object.
To generate keys from a Cosmian KMS server, instantiate a KmsClient with its URL
and, unless you run in dev mode, an API Key to authenticate to the server.
The Python methods calling the server are asynchronous.
Encrypting Data
Data is encrypted using the Public Key and an encryption policy that determines the target partitions of the ciphertext.
Anyone who has access to the Public Key can encrypt data, however, only users possessing user keys with the right access policy can decrypt the ciphertext.
A Covercrypt ciphertext is the concatenation of an encrypted header and an encrypted content.
- The encrypted content is a plaintext symmetrically encrypted using an ephemeral secret key (i.e. a random key generated on the fly).
- The header is the encapsulation of the ephemeral key for a given encryption policy, concatenated with some optional metadata. The metadata, if present, is symmetrically encrypted using the same ephemeral key.
Header and encrypted content can be generated separately using the various APIs. Check the inline documentation of the various languages and the test suites for details.
The code below shows the encryption of 3 messages with 3 different encryption policies targeting 3 different partitions.
Encrypting data is done using the encrypt() function which calls the WASM function.
Encrypting data is done using the coverCryptEncrypt() function which calls the KMS to encrypt
Encrypting using the native library is fast and provides many options.
a protected marketing message
a top-secret marketing message
a protected finance message
Encrypting using the KMS is possible (and compatible with the native library) but is inefficient compared to using the native library, due to the added I/O and stress on the KMS server.
The only reason to encrypt using the KMS is to enable a "pure" java solution without native code (which is, for instance, a requirement for a plugin in an Oracle database )
a protected marketing message
a top-secret marketing message
a protected finance message
Encrypting data is done using the encrypt() function that concatenates the
header (encapsulation of the ephemeral symmetric key) and the symmetrically
encrypted data.
These can be done separately; see CoverCrypt.encrypt_header
a protected marketing message
a top secret marketing message
a protected finance message
Encrypting using the KMS is possible with the Python library but is inefficient compared to using the native library, due to the added I/O and stress on the KMS server.
a protected marketing message
a top secret marketing message
a protected finance message
Generating User Decryption Keys
User Decryption Keys are generated from the Master Private Key using access policies.
Let us create 2 users with different access policies to illustrate their effect.
User Decryption Keys can be generated by calling the local WASM
User keys can be locally generated using the native library
the confidential marketing user
This user can decrypt messages from the marketing department only, with a security level of Confidential or below:
the top secret marketing financial user
This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:
the confidential marketing user
This user can decrypt messages from the marketing department only, with a security level of Confidential or below:
the top secret marketing financial user
This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:
exporting the keys
As with the master keys, the user keys can be exported to be used with the native library
the confidential marketing user
This user can decrypt messages from the marketing department only, with a security level of Confidential or below:
the top secret marketing financial user
This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:
the confidential marketing user
This user can decrypt messages from the marketing department only, with a security level of Confidential or below:
the top secret marketing financial user
This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:
the confidential marketing user
This user can decrypt messages from the marketing department only, with a security level of Confidential or below:
the top secret marketing financial user
This user can decrypt messages from the marketing department OR the financial department, with a security level of Top Secret or below:
the confidential marketing user
This user can decrypt messages from the marketing department only, with a security level of Confidential or below:
Decrypting Ciphertexts
The confidential marketing user can successfully decrypt a protected marketing message:
.. however, it can neither decrypt a marketing message with higher security:
... nor decrypt a message from another department even with lower security:
As expected, the top-secret marketing financial user can successfully decrypt all messages
Rekeying keys
At any time the Master Authority can generate new keys for any access policy.
When that happens future encryption of data for a given access policy cannot be decrypted with keys that have not been "refreshed".
It is best to perform rekeying using the KMS to automatically refresh each user key if it is active in the KMS (the key has not been revoked).
rekeying all keys having access to "Department::MKG"
This operation will rekey all keys with access to Department::MKG.
It is also possible to rekey all keys with a precise access policy like Department::MKG && Security Level::Protected.
You successfully rekeyed the master keys and all active user keys with access to marketing data.
See more
See more
creating a new confidential marketing message
decrypting the messages with the re-keyed key
The automatically re-keyed confidential marketing user key can still decrypt the "old" protected marketing message, as well as the new confidential marketing message.
Pruning keys
After a rekey operation, the affected keys will store both the old and the newly generated subkeys to be able to decrypt old and new ciphertexts. If you only need access to the new ciphertexts, you can save space by pruning these keys.
By performing the pruning operation using a KMS, the active user keys will be automatically synced with the master keys.
WARNING: This operation will permanently remove access to old ciphertexts for the pruned access policy.
pruning all keys having access to "Department::MKG"
The master and user keys will only keep the latest subkeys associated to the access policy Department::MKG.
Pruned keys will only be able to decrypt ciphertexts generated after the last rekey operation for the corresponding access policy.
Policy editing
The Policy in use by a KMS can be modified on the fly through various operations:
-
Rename attributes: purely visual modification of the Policy.
-
Add new attributes to an existing Policy dimension. ONLY supported by unordered dimension.
-
Disable attributes: soft removal of an attribute, prevents the encryption of new messages for this attribute while keeping the ability to decrypt existing ciphertexts.
-
Remove attributes: will permanently remove the ability to use this attribute in both encryptions and decryptions. ONLY supported by unordered dimension.
The masters keys and users keys will automatically be updated accordingly by the KMS.
Rename attributes
Specify the existing attribute Dimension::Name and the desired name for the attribute NewName.
The resulting attribute will be Dimension::NewName.
rename attribute "MKG" to "Marketing"
The rename operation is purely visual and will not impact the existing user keys and ciphertexts.
From now on, be sure to use the new attribute name when encrypting data or issuing new user keys. New messages can still be decrypted by marketing user keys created before the renaming and vice versa.
Add attributes
Add a new attribute to an unordered dimension, specify the attribute to create with Dimension::Name and whether to use hybridized keys.
add new attribute "Department::R&D"
Create a non-hybridized attribute R&D in the existing dimension Department.
The newly added attribute can be used to encrypt and generate keys as seen previously.
See more
See more
encrypt a message for the newly created attribute
This message will be readable by users with access to the R&D department and the security level protected or above.
generate a user key with access rights for this attribute
This user can decrypt messages from the R&D department OR the financial department, with a security level of confidential or below:
the new user key can decrypt the R&D message
Disable attributes
Remove the ability to encrypt new message for an existing attribute using the KMS. Existing messages associated to the disabled attribute will remain readable.
disable attribute "Department::R&D"
Prevent the generation of new R&D messages while keeping access to existing ones.
Encryption of new R&D messages is no longer possible.
Remove attributes
Completely removes an attribute from the policy and from all associated keys in the KMS.
WARNING: Encryption and decryption for this attribute will no longer be possible after this operation. We strongly recommend to make a local copy of the master secret key beforehand, otherwise messages whose encryption policy does not contain any other attributes belonging to the dimension of the deleted attribute will be lost.
remove "Department::R&D"
All user keys in the KMS associated with this attribute will automatically loose the ability to decrypt for this attribute.
Ciphertexts for which the only Department access was R&D are now unreadable by all KMS keys.
The Whole Code
The code used in this documentation as well as more examples can be found for each library:
If you want to see full code of usage of cloudproof_js, please check the examples directory in Github.
If you want to see full code of usage of cloudproof_java, please check the examples directory in Github.
The full code is available in the examples directory of the Github repo.
The full code is available in the examples directory of the Github repo.
Format Preserving Encryption
Format Preserving Encryption (FPE) is a cryptographic technique standardized in NIST SP 800-38G specification that allows the encryption of data while preserving its original format or structure. Unlike traditional encryption methods that transform data into ciphertext with a different format, FPE ensures that the encrypted output maintains the same format as the original input, such as preserving the length, character set, and other specific formatting requirements.
The purpose of Format Preserving Encryption is to provide confidentiality for sensitive data while minimizing the impact on applications or systems that rely on the original data format. This technique finds applications in scenarios where data format constraints are critical, such as databases, legacy systems, or data interchange processes.
FPE-FF1, the underlying cryptographic primitive, is a normalized algorithm that uses symmetric encryption, but it's not as fast or secure as standardized symmetric (or public key) encryption methods like AES or ChaCha. It should only be used where the format of the ciphertext container is constrained (e.g., a fixed database schema that cannot be changed).
Features
Cosmian FPE implementation supports the encryption of strings, floats and big integers.
In order to keep the format of the input plaintext, the alphabet used for plaintext must be specified.
There are multiple pre-defined alphabets available:
alpha-> abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZalpha_lower-> abcdefghijklmnopqrstuvwxyzalpha_upper-> ABCDEFGHIJKLMNOPQRSTUVWXYZnumeric-> 0123456789hexa_decimal-> 0123456789abcdefalpha_numeric-> 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZchineselatin1suplatin1sup_alphanum
These alphabets can easily be extended with any character.
Implementations and quick start
The FPE techniques are open-source and written in Rust. For the cryptographic documentation and implementation details, please check its GitHub repository.
Unless low-level programming in Rust, implementers should use those techniques through the various Cloudproof user libraries:
- cloudproof_js: the Cloudproof Javascript Library,
- cloudproof_python: the Cloudproof Python Library,
All these libraries are open-source and available on GitHub
The user libraries all contain extensive tests, and it is highly recommended to start by hacking those tests.
Setup
The library is published on npm: simply install the library in your package.json
npm install cloudproof_js
The library contains web assembly for cryptographic speed
The version 4.0.0 is available on PyPI:
pip install cloudproof_py
Import classes:
from cloudproof_py.cover_crypt import Policy, PolicyAxis, Attribute, CoverCrypt
# needed if you use Cosmian KMS
from cloudproof_py.kms import KmsClient
Encrypting integers
The most common example when using FPE is the encryption of credit card numbers. Here the alphabet numeric is used (characters of this alphabet being 0123456789) as follows:
When encrypting integers, the important parameters are radix and digits.
radixis the base of the number representation (must be between 2 and 16 inclusive)digitsis the maximum number of digits in the representation. A value of 10 will limit the ciphertext output size to 10.
Also, integers must be passed as string
Here are various examples for integers encryption:
Encrypting chinese plaintexts
Using the chinese alphabet can be done as follows:
Encrypting using a custom alphabet
Data Anonymization
Data anonymization is the process of transforming data in such a way that it can no longer be used to identify individuals without the use of additional information. This is often done to protect the privacy of individuals whose data is being collected or processed.
Anonymization techniques can include removing identifying information such as names and addresses, replacing identifying information with pseudonyms, and aggregating data so that individual data points cannot be distinguished. It's important to note that while anonymization can reduce the risk of re-identification, it is not foolproof and must be used in conjunction with other security measures to fully protect personal data.
Features
Cosmian anonymization provides multiple methods:
-
Hashing: transforms data into a fixed-length representation that is difficult to reverse and provides a high level of anonymity.
-
Noise Addition: adds random noise to data in order to preserve privacy. Support various types of noise distributions to
float,integer, anddate. -
Word Masking: hides sensitive words in a text.
-
Word Pattern Masking: replaces a sensitive pattern in text with specific characters or strings. Supports Regex.
-
Word Tokenization: removes sensitive words from text by replacing them with tokens.
-
Number Aggregation: rounds numbers to a desired power of ten. This method is used to reduce the granularity of data and prevent re-identification of individuals.
-
Date Aggregation: rounds dates based on the specified time unit. This helps to preserve the general time frame of the original data while removing specific details that could potentially identify individuals.
-
Number Scaling: scales numerical data by a specified factor. This can be useful for anonymizing data while preserving its relative proportions.
-
Format preserving encryption: encrypts data preserving its format.
Implementations and quick start
The data anonymization techniques are open-source and written in Rust. For the cryptographic documentation and implementation details, please check its GitHub repository.
Unless low-level programming in Rust, implementers should use those techniques through the various Cloudproof user libraries:
- cloudproof_java: the Cloudproof Java Library,
- cloudproof_js: the Cloudproof Javascript Library,
- cloudproof_python: the Cloudproof Python Library,
- cloudproof_flutter: the Cloudproof Flutter Library.
All these libraries are open-source and available on GitHub
The user libraries all contain extensive tests, and it is highly recommended to start by hacking those tests.
Setup
The library is published on npm: simply install the library in your package.json
npm install cloudproof_js
The library contains web assembly for cryptographic speed
The version 4.0.0 is available on PyPI:
pip install cloudproof_py
Import classes:
from cloudproof_py.anonymization import (
DateAggregator,
Hasher,
NoiseGenerator,
NumberAggregator,
NumberScaler,
WordMasker,
WordPatternMasker,
WordTokenizer,
)
Hashing
The goal of hashing techniques for data anonymization is to transform sensitive or personally identifiable information (PII) into a fixed-length string of characters, called a hash value, while preserving the privacy and confidentiality of the original data. Hashing is a one-way process, meaning that it is computationally infeasible to reverse-engineer the original data from the hash value.
The supported hashing algorithms are SHA2, SHA3 and Argon2:
- SHA-2: SHA-2 consists of multiple hash functions, including SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, and SHA-512/256. These functions use the Merkle-Damgård construction and operate on a block size of 512 bits. They employ different combinations of logical functions, such as bitwise logical operations, modular addition, and logical rotation.
- SHA-3: SHA-3 is a cryptographic hash function primarily designed for data integrity, digital signatures, and message authentication codes. It takes an input of any length and produces a fixed-length hash value.
- Argon2: Argon2 is a password hashing function that is specifically designed for secure password storage. It aims to protect against password cracking attacks, such as brute-force and dictionary attacks, by incorporating memory-hardness and resistance to parallel computation.
In JavaScript, the hasher object needs to be instantiated with a specified algorithm and then call the method apply.
Noise addition
The goal of the Noise Addition technique for data anonymization is to introduce random noise or perturbation to sensitive data to preserve privacy while still allowing for meaningful analysis or processing. Noise addition helps protect the confidentiality of individual records by obscuring specific details while preserving the statistical properties and patterns of the dataset.
Three noise distributions are supported:
- Laplace: The Laplace distribution, also known as the double-exponential distribution, is characterized by its peakiness around the mean and its exponential decay in the tails. It is often used to model data with heavy-tailed or skewed distributions.
- Gaussian (Normal): The Gaussian distribution, also known as the normal distribution, is a symmetric bell-shaped distribution. It is one of the most widely used distributions in statistics and probability theory, often employed to model data that is normally distributed or approximately so.
- Uniform: The uniform distribution is a probability distribution where all values within a specified range are equally likely. It forms a rectangle-shaped distribution with a constant probability density function (PDF) over the range.
The noiser object needs to be instantiated with a specified distribution and then call the method apply.
Either mean and standard deviation can be specified:
Or minimum or maximum bounds can be specified:
Noise can be added with correlated information and apply_correlated function as follows:
Word Masking
The purpose of the Word Masking technique in data anonymization is to protect sensitive information by replacing specific words or terms with more generic or generalized placeholders. This technique is commonly applied to text data, such as documents, emails, or chat logs, where preserving privacy is crucial while maintaining the overall meaning and context of the text.
Word Pattern Masking
Word Pattern Masking technique is similar to Word Masking but using a Regular Expression (RegEx).
Word Tokenization
Word tokenization involves splitting a given text or document into its constituent words, and then replace specific sensitive words.
Number Aggregation
The purpose of the Number Aggregation technique in data anonymization is to group or summarize numerical data to protect individual privacy while preserving the overall statistical properties and trends of the dataset. This technique is commonly applied to datasets containing sensitive numerical information, such as income, age, or medical measurements.
Date Aggregation
The purpose of the Date Aggregation technique is similar to the Number Aggregation technique.
Number Scaling
Data Scaling, also known as feature scaling or normalization, is a preprocessing technique used to standardize or transform numerical data to a common scale. The purpose of Data Scaling is not specifically related to data anonymization but rather to ensure that features or variables have similar ranges or distributions, which can benefit various data analysis and machine learning tasks. It aims to address issues that may arise when variables have different scales or units, which can impact the performance and accuracy of algorithms.
Format Preserving Encryption
Format Preserving Encryption (FPE) aims to encrypt plaintext while retaining its format (alphabet). FPE-FF1 is a normalized algorithm that uses symmetric encryption, but it's not as fast or secure as standardized symmetric (or public key) encryption methods like AES or ChaCha. It should only be used where the format of the ciphertext container is constrained (e.g., a fixed database schema that cannot be changed).
FPE can be applied to string, specifying an alphabet. Characters of the plaintext that belong to the alphabet are encrypted while the others are left unchanged at their original location in the ciphertext.
FPE can be applied to int or float, specifying radix and digits parameters:
Anonymization application flow
To facilitate the usage of these anonymization techniques, we offer advanced tools that simplify the process of anonymizing datasets.
Python package
Utilizing the cosmian-anonymization Python package, anonymize a dataframe based on a specified configuration stored in a JSON file. This file defines the techniques to be applied to each column along with specific parameters. The JSON configuration file adheres to a specific format and can be generated through the provided user interface (UI).
The library is available on PyPI:
pip install cosmian-anonymization
UI generating configuration
This user interface (UI) is crafted for constructing JSON configuration files, subsequently parsed by the Python cosmian-anonymization package. Choose the appropriate technique and parameters for each column in a given data sample, and easily download the configured JSON file.
The UI is available on GitHub, and can be run locally.
Verifiable Confidential Computing
Cosmian Enclave and Cosmian VM are solutions to compute over data
- that keeps data encrypted at all times, even when in use
- and that can be remotely verified at any time, i.e., that a correct non-tampered application is currently running in encrypted memory.
In other words, these solutions ensure that you know what processes your data, and that the data is always encrypted.
Both of these solutions
- have low performance overhead compared to processing in clear text,
- do not require modifications to existing software,
- provide real-time remote verifiability of the hardware environment and the running software
- can run either on the cloud or on-premise.
- are remotely administered and verified using simple CLI tools provided by Cosmian
- do not require external key management while in use
Security Models and Use Cases
The two solutions protect applications and data against malicious infrastructure providers (cloud administrators, third-party premises administrators, etc...) that can have physical access to the machine.
- Cosmian Enclave is a solution that provides additional protection against the system administrator of the machine, i.e. someone with operating system level access. Cosmian Enclave is a sealed secured environment best-suited for scenarios where the provider of the application code - or its parameters such as a neural network - wants to protect its intellectual property from the system administrator. This is typically the case of collaborative confidential computing scenarios where the code provider wants to deploy its code (or its parameters) on a system administered by a third party, such as the data provider.
- Cosmian VM provides additional flexibility and performance and is appropriate for scenarios where the running code does not have to be protected against the system administrator. This is typically the migration of an on-premise application to the cloud, or the security upgrade of an on-premise application to allow it to process data with increased confidentiality.
| Solution | Infra. Admins (physical access) | Sys. Admins (OS access) | Use Cases |
|---|---|---|---|
| Cosmian Enclave | No access to data or code | No access to data or code | Collaborative confidential computing, code protection |
| Cosmian VM | No access to data or code | Access | Move to cloud, security upgrade of on-premise apps |
Note: it is possible to "seal" a Cosmian VM by shutting down all operating system level access to the VM (such as the SSH daemon)
Cosmian Enclave
Please check the dedicated documentation at Cosmian Enclave
Cosmian VM
Please check the dedicated documentation at Cosmian VM
Summary Comparison of Cosmian Enclave and Cosmian VM
| Feature | Cosmian Enclave | Cosmian VM |
|---|---|---|
| Memory encryption | Yes | Yes |
| Remote verifiability | Yes | Yes |
| Remote code deployment | Yes (Python ASGI) | No |
| Offline encrypted code deployment | Yes | No |
| Protection against | Infra. Admins + Sys. Admins | Infra. Admins |
| Required hardware | Intel SGX | Intel TDX or AMD-SEV-SNP |
| Cloud providers availability | Azure, OVH | AWS, Azure, GCP, OVH |
| Applications type | Python, Singularity containers | Any application |
| Code modification | None | None |
| Performance overhead | ~+20% | ~+10% |
| Re-usability of OS images | No | Yes |
| Attack Surface | Small | Large |
These solutions are now available as IaaS on all the major cloud providers.
Search encrypted data
Building an index is required to search an encrypted database without having to decrypt it entirely. However, this index can also contain sensitive data and thus need to be encrypted before it can be outsourced to a Zero-Trust such as a public cloud.
Cosmian Findex is a Searchable Encryption scheme that allows building and securely retrieving information from an encrypted index.
A detailed functional description of Findex is available in its functional documentation.
Implementations
The Findex library provides a Rust implementation of the Findex algorithm. This implementation is storage-technology agnostic. This means that in order for Findex to use a given storage (e.g. a database), all it needs is a Rust implementation of the Findex DB interface on top of this storage.
Two implementations of Findex are available:
- using Cloudproof Rust library which exposes binding for other languages
- using Findex server that provides a HTTP server offering REST API.
The current documentation focuses on the Cloudproof Rust library.
The Cloudproof Rust library provides:
- implementations of the Findex DB interface for some popular databases;
- a wrapper that allows easily instantiating Findex using a selected DB interface;
- bindings to other languages (FFI/WASM/Python).
The other Cloudproof libraries build easy-to-use abstractions on top of these bindings to allow users to use the Findex API and to implement a custom Findex DB interface from languages such as JavaScript, Python or Java. See the section on DB interface implementation to know more about how to code, select and instantiate Findex with a given DB interface.
All those libraries are open-source and contain extensive tests. It is highly recommended to start by hacking some of those tests.
Using Findex using the REST DB interface
The REST DB interface relies on a DB server implementing the Findex REST API.
Setup
The library is published on NPM: simply install the library in your package.json.
npm install cloudproof_js
The library is based on WASM for speed.
TODO: update version after release
You need Java 8+ and Maven version 3+. The Cloudproof Java library is deployed on Maven central. Add the library to your POM:
<dependency>
<groupId>com.cosmian</groupId>
<artifactId>cloudproof_java</artifactId>
<version>7.0.0</version>
<type>jar</type>
</dependency>
Cloudproof Python is available on PyPI:
pip install cloudproof_py
The library is published on pub.dev as a Dart library: https://pub.dev/packages/cloudproof. To install it:
flutter pub add cloudproof
The library contains cryptographic native libraries called through FFI functions.
Instantiating Findex
Findex relies on the user to provide it with:
- the private key;
- the public label.
These are used to encrypt the index before it is sent to the DB for storage. See the security documentation to know more about the cryptographic algorithms used.
The REST DB interface requires an additional parameter: the server URL. A different server can be used for the two Findex tables. If only one URL is provided, it is used for both tables.
The complete example can be found in the JavaScript tests.
import { Findex, } from "cloudproof_js"
const key = randomBytes(16)
const label = 'hello, world!'
const url = 'http://localhost:8080'
const findex = new Findex(key, label)
// Instantiating an interface is performed in a dedicated step in JS since
// it is an asynchronous one.
await findex.instantiateRestInterface(serverUrl)
The complete example can be found in the Java tests.
// Dependencies:
//
// import java.security.SecureRandom;
// import com.cosmian.jna.findex.Findex;
byte[] key = new byte[16];
SecureRandom rng = new SecureRandom();
rng.nextBytes(key);
String label = "hello, world!";
String url = "http://localhost:8080";
Findex findex = new Findex(key, label, url);
The complete example can be found in the Python tests.
from cloudproof_findex import (Findex, Key)
key = Key.random()
label = 'hello, world!'
url = 'http://localhost:8080'
findex = Findex.new_with_rest_interface(key, label, url)
The REST DB interface is not (yet) available in Flutter. Therefore the SQLite is used here (see the complete test).
const dbPath = "./build/sqlite2.db";
await initDb(dbPath);
final key = base64Decode("6hb1TznoNQFvCWisGWajkA==");
SqliteFindex.init(dbPath, key, "Some Label");
Adding and deleting associations to and from the index
Adding associations to the index
Populating the index is done using the add API. It takes as argument a list
of associations that map values to sets of keywords. Each value passed as input
can then be retrieved by searching for any associated keyword.
This API returns the keywords that have been added to the index (meaning that no value where associated to these before).
The following snippet indexes the data 1337 under the keywords "John" and
"Doe".
await findex.add([
{
indexedValue: Location.fromNumber(1337),
keywords: ["John", "Doe"],
}
])
HashMap<IndexedValue, Set<Keyword>> indexedValuesAndWords =
new HashMap<>();
indexedValuesAndWords.put(
new Location(1337).toIndexedValue(),
new HashSet<>(Arrays.asList(new Keyword("John"),
new Keyword("Doe")))
);
KeywordSet res = findex.add(indexedValuesAndWords);
res = findex.add({ Location.from_int(1337): ['John', 'Doe'] })
It is also possible to index keywords under other keywords. Indexing keywords under other keywords can be seen as building a graph where nodes represent keywords and contain the data associated to them and a directed vertex from a node "A" to a node "B" represents "B" being indexed under "A".
In the following example the ID "0xA43C" represents John Doe. It is indexed under both "John" and "Doe" such that a search for either "John" or "Dow" would find the results indexed under this ID.
await findex.add([
{
indexedValue: Keyword.fromString("0xA43C"),
keywords: ["John", "Doe"],
}
])
HashMap<IndexedValue, Set<Keyword>> indexedValuesAndWords =
new HashMap<>();
indexedValuesAndWords.put(
new Keyword("0xA43C").toIndexedValue(),
new HashSet<>(Arrays.asList(new Keyword("John"), new Keyword("Doe")))
);
KeywordSet res = findex.add(indexedValuesAndWords);
res = findex.add({ Keyword.from_string('0xA43C'): ['John', 'Doe'] })
Deleting associations from the index
Similarly to the add operation, the delete operation takes associations as
argument. Instead of removing these associations from the index, it adds their
negation. No association added before its negation was indexed can be found
during a search.
The consequence is that the index size increases during this operation. The compact operation collapses negated associations, which allows deflating the index size.
Searching the index
The input of the search API is a set of keywords to search for, and an
optional interrupt function.
It searches the index for all values indexed under the given keywords. If new
keywords are found, the interrupt is called with all found values (both data
and keywords). If it returns true, the search process is interrupted and the
function returns with the data found so far, otherwise the index is searched
for the keywords found in the previous search operation.
The result of the search is a map of the searched keywords to a set containing the data directly associated to them, the data associated to a keyword that is associated to them etc.
In the following example, the index is searched for "Mar". When provided, the
interrupt stops the search after more than 10 results have been found.
// Search without interruption.
const results = await findex.search(["Mar"])
// Search with interruption.
let searchCounter = 0
const filteredResults = await findex.search(
["Mar"],
async (results: IntermediateSearchResults) => {
searchCounter += results.total()
return 10 <= searchCounter
}
)
// Search without interruption.
SearchResults results = findex.search(new String[] {"Mar"});
// Search with interruption.
SearchResults filteredResults = findex.search(new String[] {"Mar"},
new Interrupt() {
int counter = 0;
@Override
public boolean interrupt(Map<Keyword, Set<IndexedValue>> results)
throws CloudproofException {
for (Set<IndexedValue> values: results.values()) {
counter += values.size();
}
return (10 <= counter);
}
});
# Search without interruption.
results = instance.search(['Mar'])
counter = 0
def interrupt(res: ProgressResults, counter: int) -> bool:
for _, values in res.items():
counter += len(values)
return 10 <= counter
# Search with interruption.
filtered_results = instance.search(['Mar'],
lambda res: interrupt(res, counter))
Compacting the Index
The compact operation allows to:
- collapse negated associations;
- increase the index density;
- remove obsolete data;
- remove keywords not associated to any value (which can happen if all of them where negated values or obsolete data);
- reset any knowledge gained by an attacker watching index requests. This gives a lower bound on the frequency of the compact operation allowing to maintain the safety of index (see the Findex security documentation).
The compact operation takes as argument:
- The new key and a new label used to encrypt the index. At least one of them needs to be different from the old key and old label.
- The compacting rate, which is a float between 0 and 1 and determines how many
compact operations (
1/compacting_rate) would allow to compact the index entirely. - An optional filter that it is called on all the data found during the compact operation and allows to filter out data that does not need to be indexed back (only the data that is returned from the filter is present in the compacted version of the index).
In the following example, the index is entirely compacted in one operation
using the old key and a new label, and the data Location(1337) is removed
from the index.
The JavaScript binding for the compact operation is not available yet.
Set<Location> filteredLocations = new HashSet<Location>(Arrays.asList(new Location(1337)));
findex.compact(key, "new label", 1, new FilterLocations() {
@Override
public List<Location> filter(List<Location> locations)
throws CloudproofException {
return locations.stream()
.filter((Location l) -> filteredLocations.contains(l))
.collect(Collectors.toList());
}
});
filtered_locations = { Location.from_int(1337) }
def filter(dataset: Set[Location]):
res = set()
for data in dataset:
if data not in filtered_locations:
res.add(data)
return res
instance.compact(key, "new label", 1, filter)
The Flutter for the compact operation is not available yet.
Using Findex with other DB interfaces
The following figure describes the relationship between the user code, Cloudproof Rust, Findex and the DB interface.
+-----------------------------------------------------------------+
| +-----------------------------------------+ |
| | +-------+ +------+ +-----+ | // |
| | | Redis | | HTTP | ... | FFI | | // DB interfaces |
| | +-------+ +------+ +-----+ | // |
| +-----------------------------------------+ |
| | Findex instance | |
| +-----------------------------------------+ |
| ^ ^ |
| | | |
| +---------------+ Findex |
| | Configuration | API |
| +---------------+ | |
| | v |
| ------------------------ |
| / | \ |
| +-----+ +------+ +--------+ // |
| | FFI | | WASM | | Python | // User interface |
| +-----+ +------+ +--------+ // |
| |
+-----------------------------------------------------------------+
| Cloudproof Rust |
+-----------------------------------------------------------------+
^
|
v
+-----------------------------------------------------------------+
| Cloudproof Js/Python/Java/Flutter (optional) |
+-----------------------------------------------------------------+
^
|
v
+-----------------------------------------------------------------+
| User Code |
+-----------------------------------------------------------------+
The user code calls Cloudproof Rust (directly or using a binding from one of the other Cloudproof libraries) to instantiate a Findex. It provides the configuration with the required information (which depends on the targeted DB interface). Cloudproof Rust instantiates the selected DB interface and a Findex object on top of it, which can then be used by the client code through the Findex API.
Available Rust implementations of the Findex DB interface
The following Findex DB interfaces are implemented in Cloudproof Rust:
- REST: interface relying on a server implementing the Findex REST API. It is called by passing the URL of the server to the configuration. It can be identical for the Entry Table and the Chain Table.
- SQLite: called passing a path for the Entry Table and Chain Table. The
path can be identical since a dedicated SQL table (
entry_tableresp.chain_table) is created in the SQLite DB at the given path. - Redis: called passing a Redis URL for the Entry Table and the Chain table in the configuration. The URL can be identical since the tokens are prefixed with an identifier allowing to determine which DB they belong to.
- Custom: each language that exports the Findex API offers the possibility to provide an custom DB interface implementation. It is called by passing the implementation of the Findex DB interface for the Entry Table and for the Chain Table. The following section describes in details how to implement this interface in different languages.
Implementing the Findex DB interface
The DB interface needs to be implemented for:
- the Entry Table;
- the Chain Table.
To understand why two tables are used, see the functional documentation. What is important to know here is that these two tables are simple key/value stores, and that the Entry Table keys and the Chain Table keys are collision free. This means that a single key/value store can be used for both of them, as long as the Entry Table keys can be retrieved for the compact operation.
The following section describes the requirement of each function from the Findex DB interface and the following table describes which function from the Findex DB interface (the columns) needs to be implemented in order to use a function from the Findex API (the rows).
+-----------+-----------+-----------+-----------+---------------+
| `fetch` | `upsert` | `insert` | `delete` | `dump_tokens` |
+---------+-----------+-----------+-----------+-----------+---------------+
| search | ET + CT | | | | |
+---------+-----------+-----------+-----------+-----------+---------------+
| add | ET + CT | ET | CT | | |
+---------+-----------+-----------+-----------+-----------+---------------+
| delete | ET + CT | ET | CT | | |
+---------+-----------+-----------+-----------+-----------+---------------+
| compact | ET + CT | | ET + CT | ET + CT | ET |
+---------+-----------+-----------+-----------+-----------+---------------+
Fetch
The fetch function takes as argument a list of keys. It returns the list of key/value pairs of each key for which a value was found. The keys that didn't match any value should not be returned.
It is needs to be implemented for the both tables, for each Findex operation.
Implementation of the fetch function for an in-memory DB. The complete implementation can be found in the Cloudproof Js library.
const fetch= async (
uids: Uint8Array[],
table: Map<string, Uint8Array>,
): Promise<Index[]> => {
const results = []
for (const k of uids) {
const v = table.get(k.toString())
if (v !== undefined) {
results.push(new Index(k, v))
}
}
return results
}
See one of the Redis Entry Table and Redis Chain Table or the SQLite Entry Table SQLite Chain Table implementation in the Cloudproof Java library.
Implementation of the fetch function for an in-memory DB. The complete implementation can be found in the Cloudproof Rust library.
def fetch(uids, table):
res = {}
for k in uids:
if k in table:
res[k] = table[k]
return res
Upsert
This is the most difficult function to implement since it is in charge of ensuring the concurrence safety of the index.
It takes as argument a list of old key/value pairs and a list of new key/value pairs. For each new key, it performs the following operation atomically:
If the current value stored under this key equals the old value given for this key, replace the current value with the new value. Otherwise, if the current value is not defined, return an error. Otherwise stack the current key/value pair for return.
The returned value is therefore the map of current key/value pairs for which the corresponding old key/value pair was different. If no conflict happened nothing should be returned.
It needs to be implemented for the add and delete Findex operations for the
Entry Table only.
Implementation of the upsert function for an in-memory DB. The complete implementation can be found in the Cloudproof Js library.
const upsert = async (
oldValues: UidsAndValues,
newValues: UidsAndValues,
table: Map<string, Uint8Array>,
): Promise<UidsAndValues> => {
const rejected = [] as UidsAndValues
// Add old values in a map to efficiently search for matching UIDs.
const mapOfOldValues = new Map()
for (const { uid, value } of oldValues) {
mapOfOldValues.set(uid.toString(), value)
}
for (const { uid, value: newValue } of newValues) {
const currentValue = table.get(uid.toString())
if (currentValue?.toString() === mapOfOldValues.get(uid.toString())?.toString()) {
table.set(uid.toString(), newValue)
} else if (currentValue === undefined) {
throw new Error(
"Rust shouldn't send us an oldValue if the table never contained a value… (except if there is a compact between)",
)
} else {
rejected.push({ uid, value: currentValue })
}
}
return rejected
}
See one of the Redis Entry Table and Redis Chain Table or the SQLite Entry Table SQLite Chain Table implementation in the Cloudproof Java library.
Implementation of the upsert function for an in-memory DB. The complete implementation can be found in the Cloudproof Rust library.
def upsert(old_values: dict, new_values: dict, table: dict):
res = {}
for uid, new_value in new_values.items():
current_value = entry_table.get(uid)
old_value = old_values.get(uid)
if old_value == current_value:
entry_table[uid] = new_value
elif not current_value:
raise ValueError('current value for uid ' + uid
+ ' needs to be defined as long as the old value is defined')
else:
res[uid] = current_value
return res
Insert
It takes as input a list of key/value pairs. It stores each pair and returns. An error should be returned if there already was a value for any given key.
It needs to be implemented for the add, delete and compact Findex
operations for the Chain Table and for the compact operation only for the
Entry Table.
Implementation of the insert function for an in-memory DB. The complete implementation can be found in the Cloudproof Js library.
const insert = async (
links: UidsAndValues,
table: Map<string, Uint8Array>,
): Promise<void> => {
for (const { uid: newUid, value: newValue } of links) {
table.set(newUid.toString(), newValue)
}
}
See one of the Redis Entry Table and Redis Chain Table or the SQLite Entry Table SQLite Chain Table implementation in the Cloudproof Java library.
Implementation of the insert function for an in-memory DB. The complete implementation can be found in the Cloudproof Rust library.
def insert(items: dict, table):
for uid, value in items.items():
if uid in table:
raise ValueError('collision on insert for UID: ' + uid)
table[uid] = value
Delete
It takes as argument a list of keys. It removes all values stored for those keys from the DB.
It needs to be implemented for both tables for the compact Findex operation
only.
The JavaScript binding for the compact operation is not available yet.
See one of the Redis Entry Table and Redis Chain Table or the SQLite Entry Table SQLite Chain Table implementation in the Cloudproof Java library.
def delete(uids, table):
for uid in uids:
table.pop(uid)
Dump tokens
It returns all keys stored in the Entry Table.
The JavaScript binding for the compact operation is not available yet.
See one of the Redis Entry Table and Redis Chain Table or the SQLite Entry Table SQLite Chain Table implementation in the Cloudproof Java library.
def dump_entry_tokens(table: dict):
return table.keys()
Instantiating Findex with a custom DB interface
Given that the required functions have been implemented, Findex can then be instantiated with a custom DB interface.
await loadWasm()
const entryTable: Map<string, Uint8Array> = new Map()
const chainTable: Map<string, Uint8Array> = new Map()
const entryInterface = new DbInterface()
entryInterface.fetch = async (uids: Uint8Array[]) => {
await fetch(uids, entryTable)
}
entryInterface.upsert = async (oldEntries: UidsAndValues,
newEntries: UidsAndValues) => {
await upsert(oldEntries, newEntries, entryTable)
}
const chainInterface = new DbInterface()
chainInterface.fetch = async (uids: Uint8Array[]) => {
await fetch(uids, chainTable)
}
chainInterface.insert = async (links: UidsAndValues) => {
await insert(links, chainTable)
}
const findex = new Findex(key, label)
findex.instantiateCustomInterface(entryInterface, chainInterface)
Findex findex = new Findex(key,
label,
new SqliteEntryTable("/tmp/sqlite.db"),
new SqliteChainTable("/tmp/sqlite.db"));
entry_interface = PythonCallbacks.new()
entry_interface.set_fetch(lambda uids: fetch(uids, entry_table))
entry_interface.set_insert(lambda entries: insert(entries, entry_table))
entry_interface.set_delete(lambda entries: delete(entries, entry_table))
entry_interface.set_dump_tokens(lambda : dump_tokens(entry_table))
entry_interface.set_upsert(
lambda old_entries, new_entries: upsert(old_entries, new_entries, entry_table))
chain_interface = PythonCallbacks.new()
chain_interface.set_fetch(lambda uids: fetch(uids, chain_table))
chain_interface.set_insert(lambda links: insert(links, chain_table))
chain_interface.set_delete(lambda links: delete(links, chain_table))
findex = Findex.new_with_custom_interface(key,
label,
entry_interface,
chain_interface)
Eviden KMS
Note: Cosmian has become part of Eviden. The Cosmian KMS is now the Eviden KMS.
The Eviden KMS is a high-performance, source available, FIPS 140-3 compliant server application written in Rust with unique capabilities.
High-scale, secure encryption, anywhere
- High-performance: Delivers encryption and decryption services at up to millions of operations per second, with master keys held in a secure HSM-backed environment.
- Flexible pricing: Per-CPU pricing with no hidden costs, all connectors are included; deploying any number of servers.
- Runs securely in public clouds: or zero-trust environments using Eviden VMs available on Azure, GCP, and AWS marketplaces. See our deployment guide.
Standards' compliance
- FIPS 140-3 mode
- KMIP support (versions 1.0-1.4, 2.0-2.1) in both binary and JSON formats - see KMIP documentation.
- HSM support for Trustway Proteccio & Crypt2Pay, Utimaco general purpose, Nitrokey HSM 2, Smartcard HSMs, etc. with KMS keys wrapped by the HSM.
- Developed in Rust, a memory safe language, with the source code available on GitHub.
- 100% developed in the European Union.
Modern technology
- Source Available server application written in Rust
- Full-featured Web UI with client command line and graphical interface
- Advanced authentication mechanisms
- High-availability mode with simple horizontal scaling
- Multi-language client support: Python, JavaScript, Dart, Rust, C/C++, and Java (see the
cloudprooflibraries on Cosmian GitHub) - Advanced logging with OpenTelemetry
Integrations
- Cloud integrations:
- Azure BYOK
- GCP CSEK and Google CMEK
- AWS BYOK and AWS Fargate
- ...
- Workplace security:
- Transparent data encryption:
- Disk encryption:
- Storage encryption:
- Big Data:
- Other integrations:
- HSM integrations:
Three-in-one: Key lifecycle management + Encryption oracle + Public key infrastructure
The Eviden KMS combines the functions of a Key Management System, an Encryption Oracle, and a Public Key Infrastructure:
- Key Management System: Manages the full key lifecycle, including on-the-fly generation and revocation, including for connected HSMs.
- Encryption Oracle: Provides high-availability, high-scalability encryption and decryption operations at millions of operations per second with HSM-backed security.
- PKI: Manages root and intermediate certificates, signs and verifies certificates, and uses public keys for encryption/decryption. Certificates can be exported in various formats (including PKCS#12) for applications like S/MIME encrypted emails.
The Eviden KMS supports all standard NIST cryptographic algorithms as well as advanced post-quantum cryptography algorithms like Covercrypt. See the complete supported algorithms list.
Deployment options
The Eviden KMS is available as:
- Linux packages: Debian or RPM
- Windows installer: Windows
- macOS installer: macOS
- Docker: Standard image and FIPS image
User Interface
The Eviden KMS includes an intuitive graphical user interface (GUI) with support for client certificate and OIDC token authentication.

The UI can be fully customized to match your organization's branding.
Client CLI
The KMS CLI provides a powerful command-line interface for managing the server, handling keys, and performing encryption/decryption operations. It features integrated help and is available for multiple operating systems.
The KMS CLI is packaged as:
- Debian or RPM package
- Pre-built binaries for Linux, Windows, and macOS
Quick start
To quick-start a Eviden KMS server on http://localhost:9998 that stores its data
inside the container, run the following command:
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest
# Minimal default configuration
[http]
port = 9998
hostname = "0.0.0.0"
To run a KMS where the database will survive restarts, run:
docker run -p 9998:9998 --name kms --volume cosmian-kms:/cosmian-kms ghcr.io/cosmian/kms:latest
# Same default configuration; persistence is handled by Docker volume
[http]
port = 9998
hostname = "0.0.0.0"
Please note that if you want to use the KMIP wire protocol, you need to configure TLS and the socket server using the server configuration file first.
If you do not have Docker available, install a Eviden KMS server as described in installation guide:
Using the Web UI
Open your web browser and navigate to http://localhost:9998/ui to access the GUI.

Using the CLI
Get the KMS CLI from Cosmian packages. You can then easily manage the server:
-
Create a 256-bit symmetric key
ckms sym keys create --number-of-bits 256 --algorithm aes --tag my-file-key The symmetric key was successfully generated. Unique identifier: 87e9e2a8-4538-4701-aa8c-e3af94e44a9e -
Encrypt the
image.pngfile with AES GCM using the keyckms sym encrypt --tag my-file-key --output-file image.enc image.png The encrypted file is available at "image.enc" -
Decrypt the
image.encfile using the keyckms sym decrypt --tag my-file-key --output-file image2.png image.enc The decrypted file is available at "image2.png"
Encrypting and Decrypting at Scale
The Eviden KMS is architected specifically to deliver high-performance cryptography at scale for enterprise applications.
Scalability Design
The KMS scales efficiently through:
- Vertical scaling: Adding CPUs on the same machine
- Horizontal scaling: Deploying across multiple machines with load balancing
- High availability: Support for high-availability configuration
Performance Considerations
Cryptographic operations themselves are rarely the bottleneck. The key factors affecting overall performance are:
- Network latency: Minimizing the distance between the KMS and client applications
- CPU resources: Allocating sufficient processing power for concurrent operations
- Database performance: Using optimized database configurations
Deployment Architecture
The optimal architecture places KMS instances as close as possible to the applications they serve. Thanks to Eviden KMS's:
- Stateless design
- Per-CPU pricing model
- Containerized an OS packaged deployment option
This makes it practical to deploy KMS instances in multiple locations, including:
- Private data centers
- Edge locations
- Public cloud environments:

Security Considerations
Placing KMS instances closer to applications can introduce security challenges by potentially exposing key material in less trusted environments.
HSM Integration
To maintain strong security while preserving performance, Eviden KMS can be backed by Hardware Security Modules (HSMs):
- HSM integration details are explained in the HSM support section
- HSM master keys wrap all application keys handled by the KMS
- This protects keys at rest while only exposing the cleartext application keys in memory cache; the cache expiration delay is configurable
- Supported HSMs include Trustway Proteccio and Utimaco
For additional security details, see the FIPS 140-3 compliance and zeroization documentation.
Additional Protection in Public Clouds
For deployments in public clouds, consider using the Eviden VM to run the KMS. The Eviden VM provides memory and disk encryption and verifiability of the KMS's integrity.
Pre-packaged KMS in Eviden VMs is available on the Azure, GCP, and AWS marketplaces.
Integration Examples
For practical examples of integrating the KMS for high-volume operations, see:
- Client-side and application-level encryption
- Google Workspace Client-Side Encryption
- Microsoft Double Key Encryption
The Eviden KMS is particularly suited for application-level and client-side encryption scenarios, which may require high-performance encryption and decryption.
The KMS offers two mechanisms for encrypting and decrypting data:
- by calling the
EncryptandDecryptoperations on the KMS KMIP API and benefiting from its parallelization, concurrency, and optimized batching capabilities. - by using the
cosmianCLI client to encrypt and decrypt data locally, including large files.
Calling the KMS API
The KMS provides a high-performance encryption and decryption API for encrypting and decrypting data at scale.
Parallelization, concurrency, and batching
Due to its stateless user session model, the Eviden KMS is designed to use modern multi-core processors and can parallelize encryption and decryption operations across multiple cores. Parallelization can be achieved by scaling vertically (increasing the number of cores on a single machine) or horizontally (increasing the number of machines in a cluster).
The Eviden KMS can also handle multiple concurrent encryption and decryption requests on a single core using (async) concurrency primitives. The asynchronous model optimizes the use of CPU resources by allowing the CPU to perform other tasks while waiting for I/O operations to complete.
Finally, batching can further optimize the performance of encryption and decryption operations. Batching allows multiple encryption or decryption operations to be performed in a single request, reducing the overhead of making multiple requests to the KMS.
Efficient batching
The KMIP way
Batching in KMIP is achieved by sending multiple Operations in a single KMIP RequestMessage operation.
The protocol is highly flexible and allows various operations to be batched together.
The Eviden KMS supports batching using the KMIP protocol.
Optimized batching
However, the overhead of the KMIP protocol can be significant, especially for small data sizes.
Each Operation in a KMIP message carries significant metadata, which can be
prohibitively expensive for small data sizes.
When batching encryption or decryption requests, the metadata is likely identical for each request, and the overhead of unnecessarily sending the metadata multiple times can be significant.
To address this issue, the Eviden KMS provides an optimized batching API that allows multiple encryption or decryption requests to be batched together in a single request, without the overhead of the KMIP protocol. The optimized batching API is designed to be lightweight and efficient, allowing multiple encryption or decryption requests to be batched together with minimal overhead.
The method is to use a single Encrypt or Decrypt operation with multiple data items encoded in
the data field of the request.
Encoding scheme
The encoding scheme is called BulkData and encodes an array of items, each item being an array of
bytes. It works as follows.
- The encoded data starts with the 2-byte fixed sequence
0x87 0x87 - followed by the unsigned leb128 encoded number of items in the array
- followed, for each item, by
- the unsigned leb128 encoded byte length of the item
- the item itself
BulkData = 0x87 0x87 <number of items> <item 1 length> <item 1> ... <item n length> <item n>
number of items = leb128 encoded number of items
item 1 length = leb128 encoded length of item 1
When the server receives an Encrypt or Decrypt operation and detects the header 0x87 0x87, it
attempts to decode the data as a BulkData array. If the decoding is unsuccessful, the server
returns to the standard KMIP protocol (i.e., single item encryption or decryption).
If the decoding is successful, the server processes each item in the array as a separate encryption or decryption request and re-encodes the results.
When processing symmetric encryption results, the server will first, for each encrypted item,
concatenate the IV, the ciphertext, and the MAC, and then encode the result as a single item in the
BulkData array.
For AES-GCM encryption, the concatenation is as follows:
- the IV (12 bytes)
- the ciphertext (same size as the plaintext)
- the MAC (16 bytes)
Performance heuristics
The Eviden KMS uses heuristics to determine the optimal batch size for encryption and decryption requests. The heuristics consider the size of the data, the number of cores available, and the expected latency of the KMS.
Typically, for 64-byte data items, the optimal batch size is around 100,000. With these kinds of batch sizes, each CPU core should be sent an average of five batches to maximize concurrency.
Hence, to encrypt 5 million messages on 10 core machines, 50 requests of 100,000 items each should be sent in parallel. On a standard server CPU, the total processing time should be around 8 seconds, excluding network latency.
Using the KMS CLI client
The KMS CLI client can be used to encrypt and decrypt data locally, including large files.
Encryption can be performed in two modes:
- server side: the file data is sent server-side and encrypted there. This mode is well suited for small or medium files, and where a direct encryption scheme is required.
- client side: the file data is encrypted locally using a hybrid encryption scheme with key wrapping. This mode is well-suited for any type of file, including large ones, requiring high performance.
Server-side encryption and decryption
The file content is sent to the server when using server-side encryption or decryption. To use
This method uses the encrypt or decrypt command of the KMS CLI client WITHOUT
specifying a
--key-encryption-algorithm option.
Say, the KMS holds a 256-bit AES key with the ID 43d28ec7-7438-4d2c-a1a0-00379fa4fe5d, and you want to encrypt a file
image.png with AES 256-bit GCM encryption:
ckms sym encrypt \
--data-encryption-algorithm aes-gcm \
--key-id 43d28ec7-7438-4d2c-a1a0-00379fa4fe5d \
--output-file image.enc \
image.png
To decrypt the file, use the decrypt command:
ckms sym decrypt \
--data-encryption-algorithm aes-gcm \
--key-id 43d28ec7-7438-4d2c-a1a0-00379fa4fe5d \
--output-file decrypted-image.png \
image.enc
Available ciphers
The following ciphers are available for server-side encryption and decryption:
| Cipher | Description | NIST Certified? |
|---|---|---|
| aes-gcm | AES in Galois Counter Mode | yes |
| aes-xts | AES XTS | yes |
| aes-gcm-siv | AES GCM SIV | no |
| chacha20-poly1305 | ChaCha20 Poly1305 | no |
When in doubt, use AES GCM with a 256-bit key. AES GCM is NIST-certified (as NIST SP 800–38D) and well suited for arbitrary data encryption with a length of up to 2^39–256 bits ~ 64 GB.
Please note that for AES XTS, that.
- The key size must be doubled to achieve the same security level: 256 bits for AES 128 and 512 bits for AES 256.
- There is no authentication
Format of the encrypted file
The encrypted file is the concatenation of the IV (or Tweak for XTS), the ciphertext, and the MAC (None for XTS).
IV || Ciphertext || MAC
With these symmetric block ciphers, the size of the ciphertext is equal to the size of the plaintext.
The table below shows the size of the IV (tweak for XTS) and the MAC in bytes.
| Cipher | IV size | MAC size |
|---|---|---|
| aes-gcm | 12 | 16 |
| aes-xts | 16 | 0 |
| aes-gcm-siv | 12 | 16 |
| chacha20-poly1305 | 12 | 16 |
Client-side encryption and decryption
When using client-side encryption or decryption, the file content is encrypted locally using a hybrid encryption scheme with key wrapping:
- A random data encryption key (DEK) is generated. The key size is 256 bits for all schemes except for AES, which is 512 bits to provide 256 bits of classic security, and 128 bits post-quantum security.
- The DEK is used to encrypt the file content using the specified locally
--data-encryption-algorithmfor the data encryption mechanism (DEM). - The DEK is server-side encrypted (i.e., wrapped) using the specified
--key-encryption-algorithmfor the key encryption mechanism (KEM) and the KMS key encryption key (KEK) identified by--key-id.
To use this method, use the encrypt or decrypt command and specify BOTH the
--key-encryption-algorithm and --data-encryption-algorithm.
Say, the KMS holds a 256-bit AES KEK (key encryption key) with the ID
43d28ec7-7438-4d2c-a1a0-00379fa4fe5d and you want to client-side encrypt a file image.png with AES-GCM encryption,
the ephemeral KEK key is wrapped with RFC5649 (a.k.a. NIST key wrap):
ckms sym encrypt \
--data-encryption-algorithm aes-gcm \
--key-encryption-algorithm rfc5649 \
--key-id 43d28ec7-7438-4d2c-a1a0-00379fa4fe5d \
--output-file image.enc \
image.png
To decrypt the file, use the decrypt command:
ckms sym decrypt \
--data-encryption-algorithm aes-gcm \
--key-encryption-algorithm rfc5649 \
--key-id 43d28ec7-7438-4d2c-a1a0-00379fa4fe5d \
--output-file decrypted-image.png \
image.enc
Available ciphers
The following ciphers are available for client-side encryption and decryption:
- Data Encryption
| Cipher | Description | NIST Certified? |
|---|---|---|
| aes-gcm | AES in Galois Counter Mode | yes |
| aes-xts | AES XTS | yes |
| chacha20-poly1305 | ChaCha20 Poly1305 | no |
- Key Wrapping (Encryption)
| Cipher | Description | NIST Certified? |
|---|---|---|
| rfc5649 | NIST Key Wrap | yes |
| aes-gcm | AES in Galois Counter Mode | yes |
| aes-xts | AES XTS | yes |
| aes-gcm-siv | AES GCM SIV | no |
| chacha20-poly1305 | ChaCha20 Poly1305 | no |
When in doubt, use the AES GCM data encryption scheme with the AES GCM key encryption scheme (or RFC5649) with a 256-bit key. These are the most widely used schemes, and they are NIST-certified.
Format of the encrypted file
The encrypted file is the concatenation of
- the length of the key wrapping (a.k.a. encapsulation) in unsigned LEB 128 format
- the key encapsulation
- the data encryption mechanism (DEM) IV (or tweak for XTS)
- the ciphertext (same size as the plaintext)
- the data encryption mechanism (DEM) MAC
encapsulation length || encapsulation || DEM IV || Ciphertext || DEM MAC
The key encapsulation is the concatenation of
- the key encryption mechanism (KEM) IV (or tweak for XTS, none for RFC5649)
- the encrypted DEK (same length as the DEK, +8 bytes for RFC5649)
- the key encryption mechanism (KEM) MAC (none for XTS and RFC5649)
KEM IV || Encrypted DEK || KEM MAC
Using AES GCM as a KEM and a DEM, the details will be as follows:
- 1 unsigned LEB 128 byte holding the length of the encapsulation (60)
- 60 bytes of encapsulation decomposed in :
- 12 byte KEM IV
- 32 bytes encrypted DEK
- 16 byte KEM MAC
- 12 bytes of DEM IV
- x bytes of ciphertext (same size as plaintext)
- 16 bytes of DEM MAC
Public Key Infrastructure (PKI)
The Eviden KMS is a full-featured X.509 certificate authority capable of issuing, storing, validating, and revoking certificates for both classical and post-quantum algorithms.
Supported standards
| Standard | Description | Scope |
|---|---|---|
| RFC 5280 | X.509 PKI Certificate and CRL Profile | All certificate operations |
| RFC 8017 | PKCS #1 v2.2 — RSA Cryptography | RSA key pairs & certificates |
| RFC 5480 | ECC Subject Public Key Information | EC/ECDSA key pairs & certificates |
| RFC 8032 | Edwards-Curve Digital Signature Algorithm (EdDSA) | Ed25519/Ed448 certificates |
| RFC 9881 | ML-DSA in X.509 (FIPS 204) | Post-quantum signing certificates |
| RFC 9909 | SLH-DSA in X.509 (FIPS 205) | Post-quantum signing certificates |
| RFC 9935 | ML-KEM in X.509 (FIPS 203) | Post-quantum KEM certificates |
| RFC 9608 | No Revocation Available extension | All self-signed end-entity certs |
Not supported
The following specifications are not currently implemented:
- Merkle Tree Certificates (IETF draft) — transparency-based certificate format.
- Composite Certificates (draft-ietf-lamps-pq-composite-sigs / draft-ietf-lamps-pq-composite-kem) — hybrid classical+PQC keys in a single certificate.
- OCSP responder — the KMS does not act as an OCSP responder.
- CRL generation — the KMS does not generate CRLs; it can include
crlDistributionPointspointing to an external CRL.
Certificate export formats
Certificates and their associated private keys can be exported in:
- PEM (
.pem) — Base64-encoded, human-readable. - DER (
.der) — Binary ASN.1 encoding. - PKCS#12 (
.p12/.pfx) — Bundled certificate + private key, password-protected.
Post-quantum algorithms
PQC algorithms (ML-DSA, SLH-DSA, ML-KEM) are only available in the non-FIPS build
(--features non-fips). The FIPS build restricts algorithms to those approved under
the FIPS 140-3 boundary.
Algorithm identifiers (OIDs)
ML-DSA — signing (RFC 9881, FIPS 204)
| Variant | OID |
|---|---|
| ML-DSA-44 | 2.16.840.1.101.3.4.3.17 |
| ML-DSA-65 | 2.16.840.1.101.3.4.3.18 |
| ML-DSA-87 | 2.16.840.1.101.3.4.3.19 |
SLH-DSA — signing (RFC 9909, FIPS 205)
| Variant | OID |
|---|---|
| SLH-DSA-SHA2-128s | 2.16.840.1.101.3.4.20 |
| SLH-DSA-SHA2-128f | 2.16.840.1.101.3.4.21 |
| SLH-DSA-SHA2-192s | 2.16.840.1.101.3.4.22 |
| SLH-DSA-SHA2-192f | 2.16.840.1.101.3.4.23 |
| SLH-DSA-SHA2-256s | 2.16.840.1.101.3.4.24 |
| SLH-DSA-SHA2-256f | 2.16.840.1.101.3.4.25 |
| SLH-DSA-SHAKE-128s | 2.16.840.1.101.3.4.26 |
| SLH-DSA-SHAKE-128f | 2.16.840.1.101.3.4.27 |
| SLH-DSA-SHAKE-192s | 2.16.840.1.101.3.4.28 |
| SLH-DSA-SHAKE-192f | 2.16.840.1.101.3.4.29 |
| SLH-DSA-SHAKE-256s | 2.16.840.1.101.3.4.30 |
| SLH-DSA-SHAKE-256f | 2.16.840.1.101.3.4.31 |
ML-KEM — key encapsulation (RFC 9935, FIPS 203)
| Variant | OID |
|---|---|
| ML-KEM-512 | 2.16.840.1.101.3.4.4.1 |
| ML-KEM-768 | 2.16.840.1.101.3.4.4.2 |
| ML-KEM-1024 | 2.16.840.1.101.3.4.4.3 |
Key usage requirements
The Eviden KMS automatically adds the correct critical keyUsage extension
to every PQC certificate it generates, per the applicable IETF standard.
ML-DSA and SLH-DSA (signing algorithms)
Per RFC 9881 §5 and RFC 9909 §6:
- The
keyUsageextension MUST be present and MUST be critical. - It MUST include
digitalSignature. - For CA certificates:
keyCertSignandcRLSignare added.
X509v3 Key Usage: critical
Digital Signature
ML-KEM (key encapsulation algorithm)
Per RFC 9935 §5:
- The
keyUsageextension MUST be present and MUST be critical. - It MUST contain
keyEnciphermentand MUST NOT contain any other bit.
X509v3 Key Usage: critical
Key Encipherment
ML-KEM is a key encapsulation mechanism (KEM), not a signature scheme.
An ML-KEM key cannot be used to sign its own certificate.
ML-KEM certificates must always be CA-issued: supply
--issuer-private-key-id and --issuer-certificate-id pointing to
a signing key (RSA, EC, ML-DSA, or SLH-DSA).
Generating certificates with the CLI
Self-signed ML-DSA-44 certificate
ckms certificates certify \
--generate-key-pair \
--algorithm ml-dsa-44 \
--subject-name "CN=My ML-DSA CA,O=Acme,C=FR" \
--days 365
The server will:
- Generate an ML-DSA-44 key pair.
- Issue a self-signed X.509 v3 certificate.
- Automatically add a critical
keyUsageextension withdigitalSignature(per RFC 9881). - Return the certificate identifier.
CA-issued ML-KEM-512 certificate (RFC 9935)
First create an ML-DSA-44 CA:
# Step 1: create the CA certificate (self-signed ML-DSA-44)
CA_CERT_ID=$(ckms certificates certify \
--generate-key-pair \
--algorithm ml-dsa-44 \
--subject-name "CN=PQC Root CA,O=Acme,C=FR" \
--days 3650 \
| grep "Certificate ID" | awk '{print $NF}')
# Retrieve the CA private key ID from the certificate attributes
CA_SK_ID=$(ckms certificates export \
--certificate-id "$CA_CERT_ID" \
--output-format json-ttlv \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(next(l['LinkedObjectIdentifier'] for l in d.get('Link',[]) if l['LinkType']=='PrivateKeyLink'))")
Then issue an ML-KEM-512 leaf certificate signed by the CA:
# Step 2: create an ML-KEM-512 leaf certificate signed by the CA
ckms certificates certify \
--generate-key-pair \
--algorithm ml-kem-512 \
--subject-name "CN=ML-KEM-512 Leaf,O=Acme,C=FR" \
--issuer-private-key-id "$CA_SK_ID" \
--issuer-certificate-id "$CA_CERT_ID" \
--days 365
The server will:
- Generate an ML-KEM-512 key pair.
- Issue an X.509 certificate signed by the ML-DSA-44 CA.
- Automatically add a critical
keyUsageextension withkeyEnciphermentonly (per RFC 9935).
SLH-DSA-SHA2-128s self-signed certificate
ckms certificates certify \
--generate-key-pair \
--algorithm slh-dsa-sha2-128s \
--subject-name "CN=SLH-DSA Test,O=Acme,C=FR" \
--days 365
RSA or EC self-signed certificate
# RSA 4096
ckms certificates certify \
--generate-key-pair \
--algorithm rsa4096 \
--subject-name "CN=RSA CA,O=Acme,C=FR" \
--days 365
# NIST P-256
ckms certificates certify \
--generate-key-pair \
--algorithm nist-p256 \
--subject-name "CN=EC CA,O=Acme,C=FR" \
--days 365
Verifying certificates with OpenSSL 3.5+
OpenSSL 3.5+ supports all NIST PQC algorithms. Use the following commands to inspect and verify PQC certificates:
# Inspect the certificate
openssl x509 -text -noout -in ml-dsa-cert.pem
# Verify a leaf certificate against a CA certificate
openssl verify -CAfile ca-cert.pem leaf-cert.pem
Using the Web UI
The Eviden KMS Web UI exposes certificate generation through the
Certificate Issuance and Renewal page at /ui/certificates/certs/certify.
- Select "4. Generate New Keypair".
- Choose an algorithm from the Key Algorithm dropdown
(e.g.
ML-DSA-44 (PQC),ML-KEM-512 (KEM),RSA-4096,NIST-P256). - Enter a subject name.
- Optionally provide issuer key and certificate IDs for CA-signed certificates.
ML-KEM algorithms appear under (KEM) in the dropdown to signal that they require a CA issuer. Attempting to create a self-signed ML-KEM certificate will return an error.
Cross-algorithm PKI
RFC 9881 and RFC 9935 explicitly support cross-algorithm PKI: the CA signing key does not need to match the subject key algorithm.
Examples of supported combinations:
| CA algorithm | Leaf/subject algorithm | Use case |
|---|---|---|
| ML-DSA-44 | ML-KEM-512 | PQC-only PKI (RFC 9935) |
| ML-DSA-44 | ML-DSA-65 | Hierarchical PQC signing chain |
| SLH-DSA-SHA2-128s | ML-DSA-44 | Cross-family PQC PKI |
| ML-DSA-44 | RSA 4096 | PQC CA, classical leaf (transition) |
| RSA 4096 | ML-DSA-44 | Classical CA, PQC leaf (transition) |
Certificate lifecycle
All standard KMIP certificate lifecycle operations work with certificates:
| Operation | Description |
|---|---|
Certify | Generate a new certificate (self-signed or CA-issued) |
Export | Export in PEM, DER, or PKCS#12 format |
Import | Import an externally generated certificate |
Validate | Validate a certificate chain |
Revoke | Revoke a certificate |
Destroy | Permanently delete a certificate and its keys |
Revocation handling
CRL distribution points
To include a CRL distribution point in a certificate, add a
crlDistributionPoints entry in the extension config file passed via
--certificate-extensions:
[ v3_ext ]
crlDistributionPoints=URI:http://ca.example.com/crl.pem
Authority Information Access (AIA)
The AIA extension (authorityInfoAccess, OID 1.3.6.1.5.5.7.1.1) can be added
via the extension config file to point to an OCSP responder or CA issuer:
[ v3_ext ]
authorityInfoAccess=OCSP;URI:http://ocsp.example.com/,caIssuers;URI:http://ca.example.com/ca.crt
No Revocation Available (id-ce-noRevAvail, RFC 9608)
For self-signed certificates (no issuer key provided) that do not carry a
CRL distribution point, the KMS automatically adds the
id-ce-noRevAvail extension (OID 2.5.29.56, RFC 9608 §2). This signals
to relying parties that no revocation information is available for this
certificate, and that they should not reject it for lack of a CRL or OCSP
response.
This behavior applies to all algorithms (RSA, EC, ML-DSA, SLH-DSA, …), not only PQC.
When validating a chain, the KMS skips CRL fetching for any certificate that carries this extension.
Anonymization
Cosmian KMS exposes a set of data anonymization methods through a dedicated REST endpoint. These methods are stateless, require no cryptographic key, and are available under /tokenize/{method} on any KMS instance built with the non-fips feature.
All endpoints accept a JSON body and return a JSON object with a single result field. Errors come back as HTTP 422 with { "code": 422, "message": "..." }.
The ckms tokenize CLI command wraps each of these endpoints if you prefer working from the command line.
Endpoints
Hash
POST /tokenize/hash
Produces an irreversible, base64-encoded hash of a string. Three algorithms are available: SHA2 (SHA-256), SHA3 (SHA3-256), and Argon2. A salt can be passed as a base64-encoded byte string; for Argon2 it is required.
{
"data": "test sha2",
"method": "SHA2"
}
Response:
{ "result": "Px0txVYqBePXWF5K4xFn0Pa2mhnYA/jfsLtpIF70vJ8=" }
Use Argon2 when the input has low entropy (passwords, short identifiers) and you need resistance to brute-force lookup. Use SHA2 or SHA3 for high-entropy values or when throughput matters.
Noise
POST /tokenize/noise
Adds random noise to a numeric or date value. Three distributions are supported: Gaussian, Laplace, and Uniform. You can parameterize the distribution either by mean and standard deviation, or by lower and upper bounds.
The data_type field controls what kind of input to expect: float, integer, or date. Dates must be in RFC 3339 format (2023-04-07T12:34:56Z); the timezone is preserved in the output.
{
"data": 42000.0,
"data_type": "float",
"method": "Laplace",
"mean": 0.0,
"std_dev": 500.0
}
{
"data": "2023-04-07T12:34:56+02:00",
"data_type": "date",
"method": "Uniform",
"min_bound": -3600.0,
"max_bound": 3600.0
}
Laplace noise is the standard choice for differential privacy budgets. Uniform noise is appropriate when you need a hard bound on the perturbation. Gaussian is a reasonable default for datasets where outliers are acceptable.
Word Mask
POST /tokenize/word-mask
Replaces every occurrence of a listed word with XXXX, case-insensitively, matching only on word boundaries.
{
"data": "Confidential: contains -secret- documents",
"words": ["confidential", "secret"]
}
{ "result": "XXXX: contains -XXXX- documents" }
Non-word characters surrounding a target word (dashes, punctuation, spaces) are preserved.
Word Tokenize
POST /tokenize/word-tokenize
Replaces listed words with random 16-byte hex tokens. All occurrences of the same word receive the same token within a single request, so joins across a single document remain consistent. Across separate requests, the tokens are different.
{
"data": "confidential meeting with confidential sources",
"words": ["confidential"]
}
The output might be:
{ "result": "3A9F1C8B2E7D4A60 meeting with 3A9F1C8B2E7D4A60 sources" }
Word Pattern Mask
POST /tokenize/word-pattern-mask
Replaces all substrings matching a regular expression with a fixed replacement string. The pattern is limited to 1024 characters.
{
"data": "Call me at +33 6 12 34 56 78 or +1-555-123-4567",
"pattern": "\\+[\\d\\s\\-]+",
"replace": "[PHONE]"
}
{ "result": "Call me at [PHONE] or [PHONE]" }
Aggregate Number
POST /tokenize/aggregate-number
Rounds a number to the nearest power of ten. power_of_ten: 2 rounds to the nearest hundred; power_of_ten: -1 keeps one decimal place.
{
"data": 1234567,
"data_type": "integer",
"power_of_ten": 3
}
{ "result": "1235000" }
data_type is either float or integer.
Aggregate Date
POST /tokenize/aggregate-date
Truncates a date to the specified precision. The time_unit field accepts Second, Minute, Hour, Day, Month, or Year. The timezone offset is preserved.
{
"data": "2023-04-07T12:34:56+02:00",
"time_unit": "Month"
}
{ "result": "2023-04-01T00:00:00+02:00" }
Scale Number
POST /tokenize/scale-number
Applies a z-score normalization followed by a linear transformation. Given the mean and standard deviation of the original distribution, each value is standardized to zero mean and unit variance, then multiplied by scale and shifted by translate.
{
"data": 75.0,
"data_type": "float",
"mean": 50.0,
"std_deviation": 15.0,
"scale": 10.0,
"translate": 100.0
}
{ "result": 116.6666666666667 }
data_type is either float or integer. For integers the result is rounded to the nearest integer.
Relation to Format-Preserving Encryption
The methods above are one-way or statistically approximate transformations. They do not require a key and cannot be reversed to recover the original value.
For reversible, key-based field-level encryption that preserves the format of the original value (digit strings stay digit strings, alphanumeric stays alphanumeric), see Format-Preserving Encryption (FPE FF1). FPE is accessed through the KMIP Encrypt and Decrypt operations, not through the /tokenize endpoint.
| Property | Anonymization (/tokenize) | FPE (KMIP) |
|---|---|---|
| Reversible | No | Yes |
| Requires a key | No | Yes (256-bit AES) |
| Format-preserving | Partial (noise, rounding) | Exact |
| FIPS mode | No | No |
| Use case | Analytics, data sharing | Tokenized storage, round-trip |
HSM Support
The Eviden KMS can be configured to use HSMs to store and manage keys and create KMS keys wrapped by the HSM keys. This provides the best of both worlds: the security of an HSM at rest and the scalability of a KMS at runtime.
Eviden KMS natively integrates with the Proteccio, the Utimaco general purpose, the Smartcard HSM, and any HSM that has a standard PKCS#11 interface such as SoftHSMv2.
Integration Workflow
Main use case and benefits
Aside from providing a single interface to manage both KMS and HSM keys, the main use case for HSM support is to host keys in the KMS that are wrapped by keys stored in the HSM.
This combination provides the best of both worlds:
- the scalability and performance of the KMS at runtime to answer a large number of requests concurrently,
- and the hardware security of the HSM at rest, which may be a compliance requirement in some industries.
Typical use cases include:
- securing workplace applications such as MS 365 or Google Workspace, where concurrent requests from potentially a large number of users need to be processed quickly,
- securing big data applications such as Hadoop/Spark, Snowflake, Databricks, where a large number of encryption and decryption requests need to be processed on the fly for each request.
At Rest
KMS keys are stored in the KMS database in a wrapped form, and the wrapping key is stored in the HSM. This provides an additional layer of security for the keys stored in the KMS, since the keys stored in the HSM are protected by the HSM's hardware security mechanisms, and benefit from the HSM certifications.
At Runtime
Encryption and decryption requests from applications are processed by the KMS, which first unwraps the keys stored in the KMS database using the keys stored in the HSM. Contrary to the HSM, the KMS is a highly scalable and performant system that can handle a large number of requests concurrently.
In addition to managing its keys, Eviden KMS can act as a proxy to an HSM, storing and managing keys within the HSM.
HSM keys
HSM keys are prefixed keys. They are created with a unique identifier that is prefixed by the hsm keyword and the
slot number in the form:
hsm::<slot_number>::<key_identifier>
For instance, the key hsm::1::mykey is stored in the HSM slot 1 with the identifier mykey. Technically, the identifier
is stored in the LABEL field of the key object in the HSM.
!!! warning Labels must be unique within a slot
The PKCS#11 standard does not enforce label uniqueness: multiple key objects can share the same LABEL
in the same slot. Eviden KMS however uses the label as the sole key identifier within a slot, so it requires
labels to be unique per slot per key type. If two objects of the same type share a label in the same slot,
Eviden KMS will return an error when that label is referenced. Always verify that no existing object already
uses a label before creating a new key with pkcs11-tool --list-objects.
!!! info CKA_ID is automatically set by Eviden KMS
Eviden KMS sets both CKA_LABEL and CKA_ID (to the same bytes as the label) on every key it creates in
the HSM. This conforms to PKCS#11 v2.40 and prevents spurious warnings from tools such as
pkcs11-tool --list-objects. Keys provisioned externally (via pkcs11-tool or the HSM vendor software)
should also have CKA_ID set to match the label bytes if they are intended to be used with Eviden KMS.
Non-prefixed keys are considered KMS keys and are stored in the KMS database.
HSM admin
The KMS server maintains a list of HSM admin users that are allowed to create and destroy
objects directly in the HSM. This is configured with the hsm_admin key in kms.toml:
# One or more KMS usernames with HSM admin privileges
hsm_admin = ["alice@example.com", "bob@example.com"]
# Wildcard: any authenticated user becomes an HSM admin
hsm_admin = ["*"]
From the command line, pass one --hsm-admin flag per username (or a single comma-separated value):
# Two explicit admins
cosmian_kms --hsm-admin alice@example.com --hsm-admin bob@example.com ...
# Or via environment variable
KMS_HSM_ADMIN=alice@example.com,bob@example.com cosmian_kms ...
!!! note Authorization of HSM keys is still managed by the KMS
Although key material is stored in the HSM, the KMS continues to enforce the standard
ownership and access-rights model for all other operations (Encrypt, Decrypt, Get, etc.).
An HSM admin can therefore grant these operations to ordinary users, who can then use the
HSM key without themselves being HSM admins.
See HSM keys and authorization for details.
HSM key authorization model
HSM keys follow a stricter permission model than regular KMS keys. The key principles are:
- HSM admins are the only users who can create and destroy HSM keys.
- All HSM admins share ownership of all HSM keys (any admin can grant, revoke, or destroy any HSM key).
- Non-admin users can only use HSM keys they have been explicitly granted operations on.
- The
Getpermission does not act as a wildcard for HSM keys — each operation must be granted individually. - Locate only returns HSM keys the user is authorized to see (all keys for admins, granted keys for non-admins).
- The server KEK (Key Encryption Key) is a shared wrapping resource accessible to all users for wrapping/unwrapping, but direct cryptographic operations on the KEK itself require explicit grants.
Operations by role
| Operation | HSM Admin | Non-admin (granted) | Non-admin (no grant) |
|---|---|---|---|
| Create / CreateKeyPair | ✅ | ❌ | ❌ |
| Destroy | ✅ | ❌ (cannot be granted) | ❌ |
| Locate | All HSM keys | Granted keys only | None |
| Grant / Revoke (access rights) | ✅ (any HSM key) | ❌ | ❌ |
| Encrypt | ✅ | ✅ | ❌ |
| Decrypt | ✅ | ✅ | ❌ |
| Sign | ✅ | ✅ | ❌ |
| SignatureVerify | ✅ | ✅ | ❌ |
| MAC | ✅ | ✅ | ❌ |
| Get / Export | ✅ | ✅ (metadata if sensitive) | ❌ |
| GetAttributes | ✅ | ✅ | ❌ |
| SetAttribute / ModifyAttribute / AddAttribute / DeleteAttribute | ✅ | ✅ | ❌ |
| Revoke (lifecycle state) | ❌ (not supported) | ❌ | ❌ |
Grantable operations on HSM keys
| Operation | Can be granted? | Notes |
|---|---|---|
encrypt | ✅ | Symmetric (AES) and asymmetric (RSA) |
decrypt | ✅ | Symmetric (AES) and asymmetric (RSA) |
sign | ✅ | RSA private keys only |
signature_verify | ✅ | RSA public keys only |
mac | ✅ | Compute a Message Authentication Code using the HSM key |
get | ✅ | Retrieve key material or metadata; also implies export |
export | ✅ | Export key; also implies get |
get_attributes | ✅ | Read KMS metadata |
locate | ✅ | Search visibility for this key |
set_attribute | ✅ | Modify KMS metadata — does not access HSM hardware |
modify_attribute | ✅ | Modify KMS metadata — does not access HSM hardware |
add_attribute | ✅ | Modify KMS metadata — does not access HSM hardware |
delete_attribute | ✅ | Modify KMS metadata — does not access HSM hardware |
destroy | ❌ | Admin-only — irreversible hardware operation |
revoke | ❌ | HSM keys do not support KMIP lifecycle state changes |
create | ❌ | Admin-only — not a per-key grant |
!!! warning Get is not a wildcard for HSM keys
Unlike regular KMS keys, granting Get on an HSM key does not implicitly grant all other operations.
Each operation (Encrypt, Decrypt, Sign, etc.) must be granted individually.
Creating a KMS key wrapped by an HSM key
KMS Keys can be created wrapped by an HSM key, either manually or automatically.
Manually using the CLI
To create a KMS key wrapped by an HSM key, the --wrapping-key-id argument must be used to specify the unique
identifier of the HSM key.
The user creating the key must be the HSM admin (see above) or have been granted the Encrypt operation on the HSM key.
!!! note Server-level key_encryption_key is accessible to all users
When the server is configured with a key_encryption_key (see Automatically using the server configuration),
that KEK is a shared server resource and can be used as a wrapping key by any authenticated user, not just
the HSM admin. This allows non-admin users to create their own KMS keys wrapped by the server KEK.
For instance, the following command creates a 256-bit AES key wrapped by the HSM RSA (public) key
hsm::4::my_rsa_key_pk:
> ckms sym keys create --algorithm aes --number-of-bits 256 --sensitive \
--wrapping-key-id hsm::4::my_rsa_key_pk my_sym_key
The symmetric key was successfully generated.
Unique identifier: my_sym_key
The symmetric key is now stored in the database encrypted (wrapped) by the HSM key. The encryption happened in the HSM.
Manually using the Web UI
In the web UI, fill in the Wrapping Key ID field with the unique identifier of the HSM key.

Automatically using the server configuration
The KMS server can automatically wrap all KMS keys with a specific HSM key.
This is done by setting the key_encryption_key property in the TOML server configuration file
or using the corresponding command line switch.
When key_encryption_key is configured, all newly created and imported keys will be automatically wrapped
by the specified Key Encryption Key (KEK), typically an HSM key. Keys are stored wrapped in the KMS database,
ensuring no clear-text key material is persisted.
The server provides selective automatic unwrapping through the default_unwrap_type configuration parameter.
This controls which KMIP object types are automatically unwrapped when retrieved via Get or Export operations:
- Valid values:
["PrivateKey", "PublicKey", "SymmetricKey", "SecretData"] - Default:
[](no automatic unwrapping) - When a
key_encryption_keyis set, it's common to configuredefault_unwrap_type = ["SymmetricKey", "SecretData"]
Example configuration:
# Force all keys to be wrapped by an HSM key
key_encryption_key = "hsm::4::master_kek"
# Automatically unwrap symmetric keys and secret data when retrieved
default_unwrap_type = ["SymmetricKey", "SecretData"]
When an object matching the configured types is retrieved, it is automatically unwrapped and cached in the server's memory cache (see The Unwrapped Objects Cache). This enables transparent encryption/decryption operations without storing clear-text keys in the database while minimizing HSM calls through expiring caching.
Using the wrapped KMS key
The symmetric key created above can now be used to encrypt and decrypt data, and the KMS will transparently unwrap the key using the HSM key.
This unwrapping will happen once, and the unwrapped symmetric key will be cached in memory for later operations; no clear-text symmetric key will be stored in the KMS database.
Small data: encrypting server-side
For example, to encrypt a message with the key my_sym_key server-side, the following command can be used:
> ckms sym encrypt --key-id my_sym_key /tmp/secret.txt
The encrypted file is available at "/tmp/secret.enc"
To decrypt a message with the key my_sym_key, the following command can be used:
> ckms sym decrypt --key-id my_sym_key --output-file /tmp/secret.recovered.txt /tmp/secret.enc
The decrypted file is available at "/tmp/secret.recovered.txt"
Large data: encrypting client side with key wrapping
To encrypt a large file with the key my_sym_key client side, the following command can be used:
>ckms sym encrypt --key-id my_sym_key_2 --data-encryption-algorithm aes-gcm \
--key-encryption-algorithm rfc5649 /tmp/large.bin
The encrypted file is available at "/tmp/large.enc"
In this case, an ephemeral symmetric key (the Data Encryption Key, DEK) is generated and used to encrypt the data.
The DEK is then encrypted/wrapped with RFC4659 (a.k.a NIST AES Key Wrap) with the key my_sym_key,
called the Key Encryption Key, KEK.
The wrapping of the DEK by the KEK is stored at the beginning of the encrypted file.
At rest, in the KMS database, my_sym_key is stored encrypted/wrapped with the HSM key hsm::4::my_rsa_key_pk.
To decrypt a large file with the KEK my_sym_key client side, the following command can be used:
> ckms sym decrypt --key-id my_sym_key_2 --data-encryption-algorithm aes-gcm \
--key-encryption-algorithm rfc5649 --output-file /tmp/large.recovered.bin /tmp/large.enc
The decrypted file is available at "/tmp/large.recovered.bin"
Unwrapping a KMS-wrapped key from a file
If a KMS key was exported in wrapped KMIP JSON TTLV format (for example, via ckms sym keys export without --unwrap),
it can later be unwrapped using ckms sym keys unwrap.
When the unwrapping key is an HSM key (identified by the hsm:: prefix), the KMS performs the unwrap
server-side using its crypto oracle: the wrapped file is imported to the KMS with key_wrap_type=NotWrapped,
the server decrypts it using the HSM key, and the result is exported back to the output file.
This is transparent to the caller and works even when the HSM key is marked sensitive (non-extractable).
# Export a wrapped DEK to disk
ckms sym keys export --key-id my_sym_key /tmp/my_sym_key_wrapped.json
# Unwrap it using the HSM KEK — the KMS handles the decryption server-side
ckms sym keys unwrap --unwrap-key-id hsm::4::master_kek \
/tmp/my_sym_key_wrapped.json /tmp/my_sym_key_unwrapped.json
The Unwrapped Objects Cache
The unwrapped cache is a memory cache, and it is not persistent. The unwrapped cache is used to store unwrapped objects that are fetched from the database.
When a wrapped object is fetched from the database, it is unwrapped and stored in the unwrapped cache. Further calls to the same object will use the unwrapped object from the cache until the cache expires.
The time in minutes after an unused object is evicted from the cache is configurable
using the unwrapped_cache_max_age setting. The default is 15 minutes.
When HSM keys wrap objects, a long expiration time reduces the number of calls made to the HSM to unwrap the object. However, increasing the cache time will increase the memory the KMS server uses and expose the key in clear text in the memory for a longer time.
HSM KMIP operations
Some KMIP operations can be performed directly via the KMS server API on the HSM keys.
Create
Create a new key in the HSM. The key unique must be provided on the request and must follow the
hsm::<slot_number>::<key_identifier> format described above.
Only HSM admin users can create keys directly in the HSM (see HSM admin above).
RSA and AES keys are supported.
When creating an RSA key, the key_identifier will be that of the private key. The corresponding public key will be
automatically created and stored in the HSM with the same key_identifier but with the _pk suffix, for example,
the public key of the hsm::1::mykey private key will be created with a unique identifier hsm::1::mykey_pk.
Create an RSA 4096-bit key on the HSM slot 4, with the KMS CLI:
❯ ckms rsa keys create --size_in_bits 4096 hsm::4::my_rsa_key
The RSA key pair has been created.
Public key unique identifier: hsm::4::my_rsa_key_pk
Private key unique identifier: hsm::4::my_rsa_key
Create an AES 256-bit key on HSM slot 4, with the KMS CLI:
❯ ckms sym keys create --algorithm aes --number-of-bits 256 hsm::4::my_aes_key
The symmetric key was successfully generated.
Unique identifier: hsm::4::my_aes_key
HSM keys are always created with CKA_SENSITIVE=true (private/symmetric key material cannot be
exported). Pass --sensitive false explicitly only if you intentionally need an extractable key.
Note: HSM keys do not support object tagging in this release.
Using pkcs11-tool directly
Keys can also be provisioned directly in the HSM with pkcs11-tool (part of OpenSC), bypassing the Eviden KMS
entirely. This is useful for pre-provisioning a master KEK before the KMS server starts, or for HSM models where
the Eviden PKCS#11 integration does not yet support key generation.
The LABEL set with --label becomes the <key_identifier> part of the Eviden KMS unique identifier
hsm::<slot_number>::<label>.
Step 1 — List available slots
pkcs11-tool --module /tw/oemDist/libnethsmpkcs11.so --list-slots
Step 2 — Create an AES key
--key-type AES:<bytes> — size in bytes (16 = 128-bit, 24 = 192-bit, 32 = 256-bit).
# AES-128 key on slot 1, label "master_kek"
pkcs11-tool --module /tw/oemDist/libnethsmpkcs11.so \
--slot 1 \
--key-type AES:16 \
--keygen \
--label master_kek
# AES-256 key on slot 1, label "data_kek"
pkcs11-tool --module /tw/oemDist/libnethsmpkcs11.so \
--slot 1 \
--key-type AES:32 \
--keygen \
--label data_kek
If the slot requires a PIN, add --login --pin <PIN> (or --login alone to be prompted interactively):
pkcs11-tool --module /tw/oemDist/libnethsmpkcs11.so \
--slot 1 \
--login --pin 1234 \
--key-type AES:32 \
--keygen \
--label data_kek
Step 3 — Create an RSA key pair
# RSA-4096 key pair on slot 4, label "my_rsa_key"
pkcs11-tool --module /tw/oemDist/libnethsmpkcs11.so \
--slot 4 \
--login --pin 1234 \
--key-type RSA:4096 \
--keypairgen \
--label my_rsa_key
The private key label becomes hsm::4::my_rsa_key in Eviden KMS. For RSA key pairs, Eviden KMS
appends _pk to the label to build the public key identifier: hsm::4::my_rsa_key_pk.
Step 4 — Verify the objects are visible
Always check for existing objects with the same label before creating a new key — Eviden KMS requires labels to be unique within a slot and key type:
pkcs11-tool --module /tw/oemDist/libnethsmpkcs11.so \
--slot 1 \
--list-objects
The AES key created above will then be addressable in Eviden KMS as hsm::1::master_kek
and can immediately be used as a KEK:
# kms.toml
key_encryption_key = "hsm::1::master_kek"
Destroy
Unlike KMS keys, HSM keys must not be revoked before being destroyed. The Destroy operation will remove the
key from the HSM.
Only HSM admin users can destroy keys in the HSM. The Destroy operation cannot be delegated to non-admin users.
To destroy the key hsm::4::my_rsa_key, the following command can be used:
❯ ckms rsa keys destroy --key-id hsm::4::my_rsa_key
Successfully destroyed the key.
Unique identifier: hsm::4::mykey
To destroy the corresponding public key hsm::4::my_rsa_key_pk, the following command can be used:
❯ ckms rsa keys destroy --key-id hsm::4::my_rsa_key_pk
Successfully destroyed the object.
Unique identifier: hsm::4::my_rsa_key_pk
Get - Export
The Get and Export operations are used to retrieve the key material from the HSM.
Only HSM admin users, or a user granted the Get operation by an HSM admin, can retrieve keys from the HSM.
Private or symmetric keys marked as sensitive cannot be retrieved from the HSM.
The public key of a key pair can always be retrieved.
To export the public key hsm::4::my_rsa_key_pk in PKCS#8 PEM format, the following command can be used:
❯ ckms rsa keys export --key-id hsm::4::my_rsa_key_pk --key-format pkcs8-pem /tmp/pubkey.pem
The key hsm::4::my_rsa_key_pk of type PublicKey was exported to "/tmp/pubkey.pem"
Unique identifier: hsm::4::my_rsa_key_pk
To export the private key hsm::4::mykey in PKCS#8 PEM format, the following command can be used:
❯ ckms rsa keys export --key-id hsm::4::my_rsa_key --key-format pkcs8-pem /tmp/privkey.pem
The key hsm::4::my_rsa_key of type PrivateKey was exported to "/tmp/privkey.pem"
Unique identifier: hsm::4::my_rsa_key
To export the symmetric key hsm::4::my_aes_key in raw format (i.e., raw bytes),
the following command can be used:
❯ ckms sym keys export --key-id hsm::4::my_aes_key --key-format raw /tmp/symkey.raw
The key hsm::4::my_aes_key of type SymmetricKey was exported to "/tmp/symkey.raw"
Unique identifier: hsm::4::my_aes_key
Encrypt
Symmetric keys and public keys can be used to encrypt data. Only HSM admin users, or a user granted the Encrypt
operation by an HSM admin, can encrypt data with keys stored in the HSM.
For symmetric keys, only AES GCM is supported. CKM_RSA_PKCS_OAEP and the now-deprecated, but still widely used, CKM_RSA_PKCS (v1.5) are supported for RSA keys. The hashing algorithm is fixed to SHA256.
When using RSA, the maximum message size in bytes is:
- PKCS#1 v1.5: (key size in bits / 8) - 11
- OAEP: (key size in bits / 8) - 66
To encrypt a message with the public key hsm::4::my_rsa_key_pk and the CKM RSA PKCS OAEP algorithm, the following
command can be used:
❯ ckms rsa encrypt --key-id hsm::4::my_rsa_key_pk --encryption-algorithm ckm-rsa-pkcs-oaep \
/tmp/secret.txt
The encrypted file is available at "/tmp/secret.enc"
To encrypt a message using AES GCM with the symmetric key hsm::4::my_aes_key, the following command can be used:
❯ ckms sym encrypt --key-id hsm::4::my_aes_key --data-encryption-algorithm aes-gcm /tmp/secret.txt
The encrypted file is available at "/tmp/secret.enc"
Decrypt
Symmetric keys and private keys can be used to decrypt data. Only HSM admin users, or a user granted the Decrypt
operation by an HSM admin, can decrypt data with keys stored in the HSM.
For symmetric keys, only AES GCM is supported. CKM_RSA_PKCS_OAEP and the now-deprecated, but still widely used, CKM_RSA_PKCS (v1.5) are supported for RSA keys. The hashing algorithm is fixed to SHA256.
To decrypt a message with the private key
key hsm::4::hsm::4::my_rsa_key and the CKM RSA PKCS OAEP algorithm, the following command can be used:
❯ ckms rsa decrypt --key-id hsm::4::my_rsa_key --encryption-algorithm ckm-rsa-pkcs-oaep \
--output-file /tmp/secret.recovered.txt /tmp/secret.enc
The decrypted file is available at "/tmp/secret.plain"
To decrypt a message using AES GCM with the symmetric key hsm::4::my_aes_key, the following command can be used:
> ckms sym decrypt --key-id hsm::4::my_aes_key --data-encryption-algorithm aes-gcm \
--output-file /tmp/secret.recovered.txt /tmp/secret.enc
The decrypted file is available at "/tmp/secret.recovered.txt"
Multi-HSM Support
Eviden KMS can connect to multiple Hardware Security Modules simultaneously. Each HSM instance is independently initialised via PKCS#11 and exposed to the rest of the server through a unique routing prefix derived from its model name.
Routing prefix scheme
Every KMS object stored inside an HSM has a UID of the form:
hsm::<model>::<slot_id>::<key_id>
The model name embedded in the prefix allows the server to route any KMIP operation to the correct HSM without additional configuration.
| Configuration | Prefix | Example UID |
|---|---|---|
Single softhsm2 instance | hsm::softhsm2 | hsm::softhsm2::0::my-aes-key |
Single utimaco instance | hsm::utimaco | hsm::utimaco::0::another-key |
First of two softhsm2 instances | hsm::softhsm2 | hsm::softhsm2::0::key-a |
Second of two softhsm2 instances | hsm::softhsm2_1 | hsm::softhsm2_1::1::key-b |
Third of two softhsm2 instances | hsm::softhsm2_2 | hsm::softhsm2_2::2::key-c |
When the same model appears more than once, the second instance gets the suffix
_1, the third _2, and so on (e.g. hsm::softhsm2, hsm::softhsm2_1,
hsm::softhsm2_2).
Configuration
Option A — flat single-HSM CLI flags (backward compatible)
The existing --hsm-model, --hsm-admin, --hsm-slot, and --hsm-password
flags continue to work exactly as before. They configure one HSM instance
whose prefix is "hsm::<model>".
Option B — TOML [[hsm_instances]] array (multi-HSM)
Add one [[hsm_instances]] section per HSM in kms.toml. When this section is
present it takes precedence over the flat CLI flags.
# First HSM — prefix "hsm::softhsm2"
[[hsm_instances]]
hsm_model = "softhsm2"
hsm_admin = ["tech@example.com"]
hsm_slot = [0]
hsm_password = ["changeme"]
# Second HSM — prefix "hsm::utimaco"
[[hsm_instances]]
hsm_model = "utimaco"
hsm_admin = ["tech@example.com"]
hsm_slot = [0, 1]
hsm_password = ["slot0pass", "slot1pass"]
# Third HSM — same model as first, disambiguated as "hsm::softhsm2_1"
[[hsm_instances]]
hsm_model = "softhsm2"
hsm_admin = ["tech@example.com"]
hsm_slot = [2]
hsm_password = ["anotherpass"]
| Field | Description |
|---|---|
hsm_model | HSM model: softhsm2, utimaco, proteccio, crypt2pay, smartcardhsm, other |
hsm_admin | List of KMS user identities that have admin rights on this HSM |
hsm_slot | PKCS#11 slot indices to open |
hsm_password | Login passwords for the corresponding slots (same order as hsm_slot) |
Checking HSM status at runtime
The GET /hsm/status endpoint returns a JSON array of all configured HSM
instances. Authentication is required (pass the usual credentials):
curl http://localhost:9998/hsm/status
Example response:
[
{
"prefix": "hsm::softhsm2",
"model": "softhsm2",
"slots": [
{ "slot_id": 0, "accessible": true }
]
},
{
"prefix": "hsm::utimaco",
"model": "utimaco",
"slots": [
{ "slot_id": 0, "accessible": true },
{ "slot_id": 1, "accessible": false }
]
}
]
The same information is available in the HSM Status page of the Web UI
(Objects → HSM Status).
Supported platforms
HSM support is available on:
- Linux x86_64 — all models (
softhsm2,utimaco,proteccio,crypt2pay,smartcardhsm,other) - macOS (arm64 / x86_64) —
softhsm2andsmartcardhsmonly
See also
The Smartcard HSM integration is supported on Linux (x86_64). It has been tested with the following devices: BULL PKCS11 C2P 5.0.7 (Release) Unix64
HSM files installation
Copy the Crypt2pay PKCS#11 library to /lib
Copy libpkcs11c2p.so to /lib.
Make sure it is readable by the user running the KMS.
Create the c2p directory
Create a c2p directory in, say, /etc/c2p (hereafter called [C2P_DIR])
In this directory copy the following files:
c2padmin<- The Crypt2pay admin toolc2p.xml<- The Crypt2pay configuration fileca.der<- The CA certificateinstallca<- The Crypt2pay CA installation toolp11tool<- The PKCS#11 tool used to test the connection- The two files with extensions
.kdkand.ksk<- The client key files
Install the CA certificate
This certificate is the one that signed the HSM certificate and will be used to authenticate the HSM.
In the [C2P_DIR], run the installca tool:
./installca -i ./ca.der ssl
This will create an ssl directory in the [C2P_DIR] and copy the CA certificate there.
To check that the CA certificate is installed correctly, run:
./installca -l ./ssl/
Edit the c2p.xml file and insert the full path to the CA certificate ssl directory in C2Pconfig/sslDefinition/Authorities:
<C2Pconfig>
...
<sslDefinition>
<Authorities>[C2P_DIR]/ssl</Authorities>
</sslDefinition>
...
</C2Pconfig>
replace [C2P_DIR] with the actual path.
Set logging and Verify the c2p.xml file
In the c2p.xml file, set the logging to
<C2Pconfig>
<TraceLevel>debug functions parameters pkcs hsm</TraceLevel>
<TraceFile>+logs\c2p.trc</TraceFile>
...
</C2Pconfig>
Check the Crypt2pay manual to make sure that other elements of the c2p.xml are correct, in particular,
- the name of the
. kskfile inC2Pconfig/KSKfile - the name of the
. kdkfile inC2Pconfig/C2pSlot/C2PBox/KDKfile - the IP address of the HSM in
C2Pconfig/C2pSlot/C2PBox/IP
.. and recover the configured Slot ID(s) in C2Pconfig/C2pSlot[Id]"
IMPORTANT NOTE: The configuration above authenticates the HSM only. To configure mutual authentication with mTLS, additional configuration is required. Check the Crypt2pay manual for details.
Set the C2P_CONF environment variable to [C2P_DIR]/c2p.xml
export C2P_CONF=[C2P_DIR]/c2p.xml
replace [C2P_DIR] with the actual path.
Test the configuration
Run the p11tool tool to create a new 256-bit AES key:
./p11tool -genkey -keyalg aes -keysize 256 -shared /lib/libpkcs11c2p.so -slot 1 -verbose
The creation should be successful and print the key alias and ID:
use slot #1
Alias 'mykey' selected
Secret key #1000004 created
The logs are available in [C2P_DIR]/logs/c2p.trc.
KMS Configuration
When using the TOML configuration file, enable HSM support by setting these parameters:
hsm_model = "crypt2pay"
hsm_admin = "<HSM_ADMIN_USERNAME>" # defaults to "admin"
hsm_slot = [0, 0, ] # example [0,4] for slots 0 and 4
hsm_password = ["<password>", "<password>", ] # example ["648219", "648219"] for slots 0 and 4
NOTE:
hsm_slotandhsm_passwordmust always be arrays, even if only one slot is used.The order of the passwords must match the order of the slots in the
hsm_slotarray.If you want to login with an empty (null) password, use an empty string.
If you do not want to login, use the special password value
<NO_LOGIN>
Configuration via command-line
HSM support can also be enabled with command-line arguments:
--hsm-model "crypt2pay" \
--hsm-admin "<HSM_ADMIN_USERNAME>" \
--hsm-slot <number_of_1st_slot> --hsm-password <password_of_1st_slot> \
--hsm-slot <number_of_2and_slot> --hsm-password <password_of_2and_slot>
The hsm-model parameter is the HSM model. Use crypt2pay.
The hsm-admin parameter is the username of the HSM administrator.
The HSM administrator is the only user who can create objects on the HSM via the KMIP Create operation
and delegate other operations to other users.
The hsm-slot and hsm-password parameters are the slot number and user password (PIN) of the HSM slots used by the KMS.
These options can be repeated to configure multiple slots.
NOTE: To list available slots and keys run from the
[C2P_DIR]directory:./p11tool -list -shared /lib/libpkcs11c2p.so -verbose
Eviden KMS natively integrates with the Trustway Proteccio HSM.
Proteccio library setup
This solution works on Linux (x86_64) and has been validated against the Proteccio nethsm library version 3.17.
The KMS expects:
- the Proteccio
nethsmlibrary to be installed in/lib/libnethsm.so - and the Proteccio configuration files in
/etc/proteccio.
/etc/proteccio configuration files
The Proteccio client library reads its configuration from /etc/proteccio. The directory must contain the
following files:
| File | Description |
|---|---|
proteccio.rc or proteccio.ini | Main INI configuration file (see below) |
proteccio.crt | Server TLS certificate (PEM) used to authenticate the HSM appliance |
proteccio_client.key | Client TLS private key (PEM) for mutual TLS authentication |
proteccio_client.crt | Client TLS certificate (PEM) for mutual TLS authentication |
secchannel_hsm.pem | HSM secure-channel public key (EC, PEM) |
secchl_clt_privkey.pem | Client secure-channel private key (PEM) |
secchl_clt_pubkey.pem | Client secure-channel public key (PEM) |
The proteccio.rc / proteccio.ini file contains two sections:
[PROTECCIO]
IPaddr=<HSM_IP_ADDRESS> ; IP address of the Proteccio appliance
SSL=1 ; Enable TLS (1) or plain TCP (0)
SrvCert=proteccio.crt ; Server certificate filename (relative to /etc/proteccio)
SEC_CHANNEL=1 ; Enable encrypted secure channel (1) or not (0)
SecChlSrvKey=secchannel_hsm.pem ; HSM secure-channel public key filename
[CLIENT]
Mode=0 ; 0 = synchronous
LoggingLevel=7 ; Verbosity (0–7, 7 = most verbose)
LogFile=proteccio_log_file.log ; Path to the library log file
ClntKey=proteccio_client.key ; Client TLS private key filename
ClntCert=proteccio_client.crt ; Client TLS certificate filename
SecChlClntPrivKey=secchl_clt_privkey.pem ; Client secure-channel private key
SecChlClntPubKey=secchl_clt_pubkey.pem ; Client secure-channel public key
NOTE: All filenames in the configuration file are relative to
/etc/protecciounless an absolute path is given.
A secondary status log (HSM_Status.log) is written to /etc/proteccio by the nethsmstatus
monitoring daemon and records HSM availability events. It is not read by the KMS.
Please run the nethsmstatus tool to check the status of the HSM before proceeding with the
rest of the installation.
KMS configuration
At least one slot and its corresponding password must be configured. Any slot and any number of slots may be used.
When using the TOML configuration file, the HSM support is enabled by configuring these 4 parameters:
hsm_model = "proteccio"
hsm_admin = "<HSM_ADMIN_USERNAME>" # defaults to "admin"
hsm_slot = [0, 0, ] # example [1,4] for slots 1 and 4
hsm_password = ["<password>", "<password>", ] # example ["pass1", "pass4"] for slots 1 and 4
NOTE:
hsm_slotandhsm_passwordmust always be arrays, even if only one slot is used.The order of the passwords must match the order of the slots in the
hsm_slotarray.If you want to login with an empty (null) password, use an empty string.
If you do not want to login, use the special password value
<NO_LOGIN>
When the KMS is started from the command line, the HSM support can be enabled by using the following arguments:
--hsm-model "proteccio" \
--hsm-admin "<HSM_ADMIN_USERNAME>" \
--hsm-slot <number_of_1st_slot> --hsm-password <password_of_1st_slot> \
--hsm-slot <number_of_2and_slot> --hsm-password <password_of_2and_slot>
The hsm-model parameter is the HSM model to be used; use proteccio
The hsm-admin parameter is the username of the HSM administrator. The HSM administrator is the only user that can create objects on the HSM via the KMIP Create operation the delegate other operations to other users. (see below)
The hsm-slot and hsm-password parameters are the slot number and password of the HSM slots to be used by the KMS. These arguments can be repeated multiple times to specify multiple slots.
This solution works on Linux (x86_64) and has been validated against the Utimaco client library version 6.0.
Utimaco library setup
This solution works on Linux (x64_86) and has been validated against the Utimaco libcs_pkcs11_R3.so library version 6.0.
The KMS expects:
- the Utimaco
cs_pkcs11_R3library to be installed in/lib/libcs_pkcs11_R3.so - the Utimaco configuration file
cs_pkcs11_R3.cfgto be in/etc/utimacoand - and the environment variable
CS_PKCS11_R3_CFto point to it, i.e.,
export CS_PKCS11_R3_CFG=/etc/utimaco/cs_pkcs11_R3.cfg
Please make sure the cs_pkcs11_R3.cfg is set with the correct parameter, and validate your
installation with the p11tool2 utility, by running, for instance,
./p11tool2 Slot=0 GetSlotInfo
KMS configuration
At least one slot and its corresponding password must be configured. Any slot and any number of slots may be used.
When using the TOML configuration file, the HSM support is enabled by configuring these 4 parameters:
hsm_model = "utimaco"
hsm_admin = "<HSM_ADMIN_USERNAME>" # defaults to "admin"
hsm_slot = [0, 0, ] # example [0,4] for slots 0 and 4
hsm_password = ["<password>", "<password>", ] # example ["pass0", "pass4"] for slots 0 and 4
NOTE:
hsm_slotandhsm_passwordmust always be arrays, even if only one slot is used.The order of the passwords must match the order of the slots in the
hsm_slotarray.If you want to login with an empty (null) password, use an empty string.
If you do not want to login, use the special password value
<NO_LOGIN>
When the KMS is started from the command line, the HSM support can be enabled by using the following arguments:
--hsm-model "utimaco" \
--hsm-admin "<HSM_ADMIN_USERNAME>" \
--hsm-slot <number_of_1st_slot> --hsm-password <password_of_1st_slot> \
--hsm-slot <number_of_2and_slot> --hsm-password <password_of_2and_slot>
The hsm-model parameter is the HSM model; use utimaco.
The hsm-admin parameter is the username of the HSM administrator.
The HSM administrator is the only user who can create objects on the HSM via the KMIP Create operation
and delegate other operations to other users.
(see below)
The hsm-slot and hsm-password parameters are the slot number and user password of the HSM slots used by the KMS.
These arguments can be repeated multiple times to specify various slots.
Using the simulator
Utimaco provides a simulator that can be used instead of a physical HSM to test your installation. The simulator is a 32-bit Linux i386 library (it also exists as a Windows binary).
Follow these general steps to install the simulator on a Debian-based (e.g., Ubuntu) Linux amd64/x86_64.
-
Enable 32-bit support
sudo dpkg --add-architecture i386Then
sudo apt-get update sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 -
Start the simulator
In
<eval-bundle-6.0.0>\Software\Windows\Simulator\sim5_windows\bin, run.\bl_sim5.exe -h -o -d ..\devices\ -
Make sure the Device in
cs_pkcs11_R3.cfgpoints to the simulator. -
Initialize a slot and create the Security Officer and User pins.
Due to a bug (?) in the simulator, the Security Officer PIN must be set then changed before the User PIN can be set, and then changed as well.
# Set the SO PIN to 11223344 ./p11tool2 Slot=0 login=ADMIN,./key/ADMIN_SIM.key InitToken=11223344 # Change the SO PIN to 12345678 ./p11tool2 Slot=0 LoginSO=11223344 SetPin=11223344,12345678Failing to change the SO PIN before setting the User PIN will result in the following error:
Error 0x000001B8 ( CKR_PIN_TOO_WEAK)# Set the User PIN to 11223344 ./p11tool2 Slot=0 LoginSO=12345678 InitPin=11223344 # Change the User PIN to 12345678 ./p11tool2 Slot=0 LoginUser=11223344 SetPin=11223344,12345678Now, both the SO and User PINs have been set to 12345678.
To list objects on Slot 0, use:
./p11tool2 Slot=0 LoginUser=12345678 ListObjects
The Smartcard HSM integration is supported on Linux (x86_64). It has been tested with the following devices:
- SC HSM 4k (Smartcard and USB variants)
- Nitrokey HSM 2
Smartcard HSM library setup
To use a Smartcard HSM with the KMS, the sc-hsm-embedded PKCS#11 library must be installed.
The integration has been validated with version 2.12.
The KMS expects the library to be installed at /usr/local/lib/libsc-hsm-pkcs11.so.
To build and install the library, follow the instructions in the sc-hsm-embedded GitHub repository.
Smartcard HSM initialisation
⚠️ Warning:
- Initialization is destructive. It will erase all existing keys and objects on the HSM.
- Losing the Security Officer (SO) PIN will prevent future resets of the HSM. This can make the device permanently unusable. Keep it secure.
NOTE: The default PINs shown below are recommended by the manufacturer for development purposes. Always change them in production.
Before use, the HSM must be initialized. There are two ways to accomplish this:
Graphical Initialization (SmartCard-HSM Key Manager)
- Download and install Smart Card Shell.
- Launch Smart Card Shell and insert the HSM.
- From the File menu (or with
CTRL+M), open the SmartCard-HSM Key Manager. - Right-click on the HSM entry and select Initialize Device.
- Follow the on-screen guide.
Using sc-hsm-tool
-
Install the OpenSC for your distribution.
-
Initialize the card with a Security Officer and a User PIN.
sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --label "SC HSM test"Additional initialisation options are documented in the sc-hsm-tool man page.
KMS configuration
At least one slot and its corresponding PIN must be configured. Multiple slots can be used simultaneously, with each represented by a separate slot.
Configuration via config file
When using the TOML configuration file, enable HSM support by setting these parameters:
hsm_model = "smartcardhsm"
hsm_admin = "<HSM_ADMIN_USERNAME>" # defaults to "admin"
hsm_slot = [0, 0, ] # example [0,4] for slots 0 and 4
hsm_password = ["<password>", "<password>", ] # example ["648219", "648219"] for slots 0 and 4
NOTE:
hsm_slotandhsm_passwordmust always be arrays, even if only one slot is used.The order of the passwords must match the order of the slots in the
hsm_slotarray.If you want to login with an empty (null) password, use an empty string.
If you do not want to login, use the special password value
<NO_LOGIN>
Configuration via command-line
HSM support can also be enabled with command-line arguments:
--hsm-model "smartcardhsm" \
--hsm-admin "<HSM_ADMIN_USERNAME>" \
--hsm-slot <number_of_1st_slot> --hsm-password <password_of_1st_slot> \
--hsm-slot <number_of_2and_slot> --hsm-password <password_of_2and_slot>
The hsm-model parameter is the HSM model. Use smartcardhsm.
The hsm-admin parameter is the username of the HSM administrator.
The HSM administrator is the only user who can create objects on the HSM via the KMIP Create operation
and delegate other operations to other users.
The hsm-slot and hsm-password parameters are the slot number and user password (PIN) of the HSM slots used by the KMS.
These options can be repeated to configure multiple slots.
NOTE: To list available slots, run:
pkcs11-tool --module /usr/local/lib/libsc-hsm-pkcs11.so --list-slots
The SoftHSMv2 integration is supported on Linux (x86_64).
SoftHSMv2 library setup
To use SoftHSMv2 with the KMS, the library must first be installed.
The KMS expects the library to be installed at /usr/lib/softhsm/libsofthsm2.so.
Install the library using your distributions package manager, or build it by following the instructions in the SoftHSMv2 GitHub repository.
SoftHSMv2 initialisation
Before use, SoftHSMv2 requires initialization:
softhsm2-util --init-token --slot 0 --so-pin 000000 --pin 000000 --label "SoftHSM"
NOTE: The slot number will be reassigned randomly. Use the new slot number in your KMS configuration.
KMS configuration
At least one slot and its corresponding PIN must be configured. Multiple slots can be used at the same time.
Configuration via config file
When using the TOML configuration file, enable HSM support by setting these parameters:
hsm_model = "softhsm2"
hsm_admin = "<HSM_ADMIN_USERNAME>" # defaults to "admin"
hsm_slot = [0, 0, ] # example [0,4] for slots 0 and 4
hsm_password = ["<password>", "<password>", ] # example ["000000", "444444"] for slots 0 and 4
NOTE:
hsm_slotandhsm_passwordmust always be arrays, even if only one slot is used.The order of the passwords must match the order of the slots in the
hsm_slotarray.If you want to login with an empty (null) password, use an empty string.
If you do not want to login, use the special password value
<NO_LOGIN>
Configuration via command-line
HSM support can also be enabled with command-line arguments:
--hsm-model "softhsm2" \
--hsm-admin "<HSM_ADMIN_USERNAME>" \
--hsm-slot <number_of_1st_slot> --hsm-password <password_of_1st_slot> \
--hsm-slot <number_of_2and_slot> --hsm-password <password_of_2and_slot>
The hsm-model parameter is the HSM model. Use softhsm2.
The hsm-admin parameter is the username of the HSM administrator.
The HSM administrator is the only user who can create objects on the HSM via the KMIP Create operation
and delegate other operations to other users.
The hsm-slot and hsm-password parameters are the slot number and user password (PIN) of the HSM slots used by the KMS.
These options can be repeated to configure multiple slots.
NOTE: To list available slots, run:
softhsm2-util --show-slots
Integration of other HSMs is supported on Linux (x86_64).
Even if your HSM is not explicitly listed in this documentation, there is a great chance that it will work, in particular its PKCS#11 driver API is compatible with that of SofHsmV2.
Library setup
The KMS expects the HSM linux PKCS#11 library to be installed at /lib/libkmshsm.so.
Rename your HSM library to libkmshsm.so if necessary.
HSM initialization
Before using the HSM with the KMS, follow your documentation to initialize a slot and a user pin/password for that slot.
KMS configuration
At least one slot and its corresponding PIN must be configured. Multiple slots can be used at the same time.
Configuration via config file
When using the TOML configuration file, enable HSM support by setting these parameters:
hsm_model = "other"
hsm_admin = "<HSM_ADMIN_USERNAME>" # defaults to "admin"
hsm_slot = [0, 0, ] # example [0,4] for slots 0 and 4
hsm_password = ["<password>", "<password>", ] # example ["000000", "444444"] for slots 0 and 4
NOTE:
hsm_slotandhsm_passwordmust always be arrays, even if only one slot is used.The order of the passwords must match the order of the slots in the
hsm_slotarray.If you want to login with an empty (null) password, use an empty string.
If you do not want to login, use the special password value
<NO_LOGIN>
Configuration via command-line
HSM support can also be enabled with command-line arguments:
--hsm-model "other" \
--hsm-admin "<HSM_ADMIN_USERNAME>" \
--hsm-slot <number_of_1st_slot> --hsm-password <password_of_1st_slot> \
--hsm-slot <number_of_2and_slot> --hsm-password <password_of_2and_slot>
The hsm-model parameter is the HSM model. Use other.
The hsm-admin parameter is the username of the HSM administrator.
The HSM administrator is the only user who can create objects on the HSM via the KMIP Create operation
and delegate other operations to other users.
The hsm-slot and hsm-password parameters are the slot number and user password (PIN) of the HSM slots used by the
KMS.
These options can be repeated to configure multiple slots.
API
The Eviden KMS server implements the JSON TTLV profile of the KMIP 1.x and 2.x specifications. In addition, the server exposes a few additional endpoints for authorization operations.
Calling the KMIP API
This API is documented in the KMIP section of this manual.
Calling the authorization API
This API is documented in the authorization section of this manual.
Authentication
The Eviden server supports various authorization mechanisms: see
the authentication section
of this manual for details. When authenticating using JWT, an HTTP Authorization header must be
passed with the JWT token as a bearer token.
For example: Authorization: Bearer <JWT_TOKEN>
REST Native Crypto API
In addition to the KMIP protocol, the server exposes a lightweight JOSE-compatible REST API
under /v1/crypto for encrypt, decrypt, sign, verify, and MAC operations.
See the REST Native Crypto API page for full documentation.
OpenAPI specification and interactive documentation
The KMS server exposes its full API as an OpenAPI 3.1 specification and serves an interactive Swagger UI browser directly from the server binary.
| Endpoint | Description |
|---|---|
GET /openapi.yaml | Full OpenAPI 3.1 schema in YAML format |
GET /swagger | Interactive Swagger UI (locally served, authentication required) |
Using the Swagger UI
Navigate to <server_url>/swagger in a browser. The page serves Swagger UI assets
directly from the KMS server binary (no external CDN dependency) and applies a strict
Content-Security-Policy header with frame-ancestors 'none' for clickjacking protection.
https://<your-kms-host>:9998/swagger
The UI displays all documented operations grouped by tag:
- KMIP — TTLV-over-HTTP (
POST /kmip/2_1,POST /kmip/1_4) - REST Crypto API — key lifecycle, encrypt/decrypt/sign/verify/MAC under
/v1/crypto - Server — health, version, server-info
- Access control — grant, revoke, list, and check permissions
- HSM — HSM status
- Download — CLI download endpoint
Downloading the spec
curl -O https://<your-kms-host>:9998/openapi.yaml
The downloaded YAML can be imported into any OpenAPI-compatible tooling (Postman, Insomnia, code generators, etc.).
REST Native Crypto API (/v1/crypto)
The Eviden KMS exposes a lightweight REST Native Crypto API under the /v1/crypto path.
This API follows the JOSE (JSON Object Signing and Encryption) conventions from
RFC 7516 (JWE),
RFC 7515 (JWS), and
RFC 7518 (JWA).
Key material never leaves the KMS. Only ciphertext, signatures, and MACs travel over the network.
Table of Contents
- Authentication
- Endpoints
- Key tag management
- Error responses
- Known limitations
- Algorithm support matrix
Authentication
The /v1/crypto endpoints share the same authentication as the rest of the KMS API.
Pass a JWT bearer token, a TLS client certificate, or an API token, depending on your
server configuration. See Authentication.
Endpoints
POST /v1/crypto/keys
Generate or import a cryptographic key (or key pair) in the KMS. The request follows JWK
conventions — specify kty (key type) and alg (algorithm) at minimum.
- Generate: omit key material fields to create a new random key.
- Import: include key material (
kfor symmetric,dfor asymmetric) to import an existing key.
Request body
{
"kty": "oct",
"alg": "A256GCM"
}
| Field | Required | Description |
|---|---|---|
kty | ✓ | Key type: oct (symmetric), RSA, EC, OKP (non-FIPS) |
alg | ✓ | JOSE algorithm identifier (determines key size and usage) |
crv | EC/OKP | Curve name: P-256, P-384, P-521, Ed25519 (non-FIPS) |
k | import oct | Base64url-encoded symmetric key material |
d | import EC/RSA/OKP | Base64url-encoded private key scalar (EC/OKP) or private exponent (RSA) |
n | import RSA | Base64url-encoded RSA modulus |
e | import RSA | Base64url-encoded RSA public exponent |
p | import RSA | Base64url-encoded first prime factor |
q | import RSA | Base64url-encoded second prime factor |
dp | import RSA | Base64url-encoded d mod (p-1) |
dq | import RSA | Base64url-encoded d mod (q-1) |
qi | import RSA | Base64url-encoded CRT coefficient (q^-1 mod p) |
Response body
{
"kid": "<key-uuid>",
"kid_public": "<public-key-uuid>" // only for generated asymmetric key pairs
}
Note: Imported asymmetric keys return
kid_public: nullbecause only the private key is stored. The KMS derives the public key internally when needed for verification or encryption.
Examples
Symmetric key generation (AES-256-GCM):
{ "kty": "oct", "alg": "A256GCM" }
Symmetric key import (HMAC-SHA256):
{ "kty": "oct", "alg": "HS256", "k": "<base64url-encoded-32-byte-key>" }
RSA key pair generation (PS256):
{ "kty": "RSA", "alg": "PS256" }
EC key import (P-256):
{ "kty": "EC", "crv": "P-256", "alg": "ES256", "d": "<base64url-encoded-scalar>" }
RSA key import:
{
"kty": "RSA", "alg": "RS256",
"n": "<modulus>", "e": "AQAB", "d": "<private-exponent>",
"p": "<prime1>", "q": "<prime2>",
"dp": "<exponent1>", "dq": "<exponent2>", "qi": "<coefficient>"
}
DELETE /v1/crypto/keys/{kid}
Destroy (permanently delete) a key from the KMS. The key is first revoked (deactivated) then removed from the database, including any linked public/private key in the pair.
Path parameters
| Parameter | Description |
|---|---|
kid | The UUID of the key to destroy |
Response
- 204 No Content on success (empty body).
POST /v1/crypto/keys/unwrap
Unwrap (decrypt) a JWE encrypted_key using an RSA private key and import the
resulting symmetric CEK into the KMS as a managed key. The raw key material is
never returned to the caller — only a kid identifier is provided.
This endpoint is designed for the JWE decryption use case where the same CEK is
reused across multiple messages: unwrap once, then decrypt subsequent ciphertexts
using POST /v1/crypto/decrypt with alg=dir.
Supported alg values: RSA-OAEP, RSA-OAEP-256.
Supported enc values: A128GCM, A192GCM, A256GCM.
Flow — Unwrap CEK then decrypt
sequenceDiagram
participant Client
participant KMS
Note over Client,KMS: Prerequisite: RSA key pair exists in KMS
Client->>KMS: POST /v1/crypto/keys/unwrap<br/>{protected: {alg,enc,kid}, encrypted_key}
Note over KMS: RSA-OAEP decrypt → CEK<br/>Import CEK as Active symmetric key
KMS-->>Client: {"kid":"<cek-uuid>","kty":"oct","alg":"A256GCM","key_ops":[...]}
Client->>KMS: POST /v1/crypto/decrypt<br/>{protected: {alg:"dir",enc,kid:"<cek-uuid>"},<br/>iv, ciphertext, tag}
Note over KMS: AES-GCM decrypt with persisted CEK
KMS-->>Client: {"kid":"<cek-uuid>","data":"..."}
Request body
{
"protected": "<base64url JWE Protected Header>",
"encrypted_key": "<base64url wrapped CEK>"
}
| Field | Required | Description |
|---|---|---|
protected | ✓ | Base64url-encoded JWE Protected Header (must contain alg, enc, kid) |
encrypted_key | ✓ | Base64url-encoded RSA-OAEP-wrapped CEK (must be non-empty) |
The protected header must decode to a JSON object containing:
| Header field | Required | Description |
|---|---|---|
kid | ✓ | UUID of the RSA private key (or its linked public key) |
alg | ✓ | RSA-OAEP or RSA-OAEP-256 |
enc | ✓ | A128GCM, A192GCM, or A256GCM (determines expected CEK size) |
Response body
{
"kid": "<cek-uuid>",
"kty": "oct",
"alg": "A256GCM",
"key_ops": ["encrypt", "decrypt"]
}
| Field | Description |
|---|---|
kid | UUID of the imported symmetric key in the KMS |
kty | Always oct (symmetric key) |
alg | The enc algorithm from the protected header |
key_ops | Allowed operations: ["encrypt", "decrypt"] |
Error conditions
| Condition | Status | Error code |
|---|---|---|
Invalid base64url in protected or encrypted_key | 400 | bad_request |
Missing kid, alg, or enc in protected header | 400 | bad_request |
Empty encrypted_key | 400 | bad_request |
Unsupported algorithm (e.g., dir, A128KW) | 422 | unsupported_algorithm |
| Private key not found | 404 | not_found |
| Decryption failure (wrong key, corrupted data) | 422 | decryption_failed |
CEK size does not match enc algorithm | 422 | crypto_failure |
Example (curl)
# Assume $PROTECTED and $ENCRYPTED_KEY come from a JWE token
# The protected header contains {"alg":"RSA-OAEP-256","enc":"A256GCM","kid":"<priv-uuid>"}
# 1. Unwrap the CEK
UNWRAP_RESP=$(curl -s -X POST https://kms.example.com/v1/crypto/keys/unwrap \
-H 'Content-Type: application/json' \
-d "{\"protected\":\"$PROTECTED\",\"encrypted_key\":\"$ENCRYPTED_KEY\"}")
CEK_KID=$(echo "$UNWRAP_RESP" | jq -r '.kid')
# 2. Decrypt subsequent ciphertexts using the persisted CEK
# Build a protected header for direct decryption:
DIR_HEADER=$(printf '{"alg":"dir","enc":"A256GCM","kid":"%s"}' "$CEK_KID" \
| base64 | tr '+/' '-_' | tr -d '=')
curl -s -X POST https://kms.example.com/v1/crypto/decrypt \
-H 'Content-Type: application/json' \
-d "{\"protected\":\"$DIR_HEADER\",\"iv\":\"$IV\",\"ciphertext\":\"$CT\",\"tag\":\"$TAG\"}" \
| jq -r '.data | @base64d'
# 3. Clean up
curl -s -X DELETE https://kms.example.com/v1/crypto/keys/$CEK_KID
POST /v1/crypto/encrypt
Encrypt plaintext using either:
- Direct encryption (
alg=dir): uses a symmetric key directly as the content encryption key (CEK). - RSA-OAEP key wrapping (
alg=RSA-OAEPoralg=RSA-OAEP-256): generates an ephemeral CEK, wraps it with the RSA public key, and encrypts data with AES-GCM.
Supported alg values: dir, RSA-OAEP, RSA-OAEP-256.
Supported enc values: A128GCM, A192GCM, A256GCM.
Flow — Direct (dir)
sequenceDiagram
participant Client
participant KMS
Client->>KMS: POST /v1/crypto/keys {"kty":"oct","alg":"A256GCM"}
KMS-->>Client: {"kid":"<uuid>"}
Client->>KMS: POST /v1/crypto/encrypt {"kid":"<uuid>","alg":"dir","enc":"A256GCM","data":"..."}
Note over KMS: AES-GCM encrypt with symmetric key
KMS-->>Client: {"protected":"...","encrypted_key":"","iv":"...","ciphertext":"...","tag":"..."}
Client->>KMS: POST /v1/crypto/decrypt {"protected":"...","iv":"...","ciphertext":"...","tag":"..."}
Note over KMS: AES-GCM decrypt with symmetric key
KMS-->>Client: {"kid":"<uuid>","data":"..."}
Client->>KMS: DELETE /v1/crypto/keys/<uuid>
KMS-->>Client: 204 No Content
Flow — RSA-OAEP
sequenceDiagram
participant Client
participant KMS
Client->>KMS: POST /v1/crypto/keys {"kty":"RSA","bits":2048}
KMS-->>Client: {"kid":"<priv-uuid>","kid_public":"<pub-uuid>"}
Client->>KMS: POST /v1/crypto/encrypt {"kid":"<pub-uuid>","alg":"RSA-OAEP-256","enc":"A256GCM","data":"..."}
Note over KMS: Generate ephemeral CEK<br/>Wrap CEK with RSA-OAEP-256<br/>AES-GCM encrypt data<br/>Wipe CEK from memory
KMS-->>Client: {"protected":"...","encrypted_key":"<wrapped-CEK>","iv":"...","ciphertext":"...","tag":"..."}
Client->>KMS: POST /v1/crypto/decrypt {"protected":"...","encrypted_key":"<wrapped-CEK>","iv":"...","ciphertext":"...","tag":"..."}
Note over KMS: RSA-OAEP unwrap → CEK<br/>AES-GCM decrypt<br/>(implicit rejection on OAEP failure)
KMS-->>Client: {"kid":"<priv-uuid>","data":"..."}
Client->>KMS: DELETE /v1/crypto/keys/<priv-uuid>
KMS-->>Client: 204 No Content (cascades to public key)
Request body
{
"kid": "<key-uuid>",
"alg": "RSA-OAEP",
"enc": "A256GCM",
"data": "<base64url-encoded plaintext>",
"aad": "<base64url-encoded AAD>" // optional
}
| Field | Required | Description |
|---|---|---|
kid | ✓ | Key UUID (symmetric key for dir; RSA private or public key for RSA-OAEP/RSA-OAEP-256) |
alg | ✓ | Key management algorithm: dir, RSA-OAEP, or RSA-OAEP-256 |
enc | ✓ | Content encryption algorithm: A128GCM, A192GCM, A256GCM |
data | ✓ | Base64url-encoded plaintext |
aad | Optional additional authenticated data (base64url) |
Response body (Flattened JWE)
{
"protected": "<base64url JWE Protected Header>",
"encrypted_key": "<base64url wrapped CEK>",
"iv": "<base64url IV>",
"ciphertext": "<base64url ciphertext>",
"tag": "<base64url GCM authentication tag>",
"aad": "<base64url AAD>" // omitted when not supplied
}
For alg=dir, the encrypted_key field is an empty string. For RSA-OAEP, it contains
the RSA-OAEP-wrapped CEK.
Example — Direct encryption (curl)
# 1. Create a 256-bit AES key
KID=$(curl -s -X POST https://kms.example.com/v1/crypto/keys \
-H 'Content-Type: application/json' \
-d '{"kty":"oct","alg":"A256GCM"}' | jq -r '.kid')
# 2. Encrypt
DATA_B64=$(printf 'Hello KMS!' | base64 | tr '+/' '-_' | tr -d '=')
JWE=$(curl -s -X POST https://kms.example.com/v1/crypto/encrypt \
-H 'Content-Type: application/json' \
-d "{\"kid\":\"$KID\",\"alg\":\"dir\",\"enc\":\"A256GCM\",\"data\":\"$DATA_B64\"}")
# 3. Decrypt
curl -s -X POST https://kms.example.com/v1/crypto/decrypt \
-H 'Content-Type: application/json' \
-d "$JWE" | jq -r '.data | @base64d'
# 4. Clean up
curl -s -X DELETE https://kms.example.com/v1/crypto/keys/$KID
Example — RSA-OAEP (curl)
# 1. Create an RSA-2048 key pair
KEYS=$(curl -s -X POST https://kms.example.com/v1/crypto/keys \
-H 'Content-Type: application/json' \
-d '{"kty":"RSA","bits":2048}')
KID=$(echo "$KEYS" | jq -r '.kid')
KID_PUB=$(echo "$KEYS" | jq -r '.kid_public')
# 2. Encrypt with RSA-OAEP-256 using the public key
DATA_B64=$(printf 'Secret message' | base64 | tr '+/' '-_' | tr -d '=')
JWE=$(curl -s -X POST https://kms.example.com/v1/crypto/encrypt \
-H 'Content-Type: application/json' \
-d "{\"kid\":\"$KID_PUB\",\"alg\":\"RSA-OAEP-256\",\"enc\":\"A256GCM\",\"data\":\"$DATA_B64\"}")
# 3. Decrypt (kid in protected header resolves to private key automatically)
curl -s -X POST https://kms.example.com/v1/crypto/decrypt \
-H 'Content-Type: application/json' \
-d "$JWE" | jq -r '.data | @base64d'
# 4. Clean up (cascades to the linked public key)
curl -s -X DELETE https://kms.example.com/v1/crypto/keys/$KID
POST /v1/crypto/decrypt
Decrypt a Flattened JWE token.
Supports both alg=dir (direct AES-GCM) and alg=RSA-OAEP/RSA-OAEP-256
(RSA-OAEP key unwrapping + AES-GCM content decryption).
The kid in the JWE protected header identifies the decryption key. For RSA-OAEP,
this can be either the private key or the public key UUID (the server resolves to
the private key automatically).
The decrypt endpoint has no standalone flow diagram — it is the second half of the encrypt/decrypt flows shown in the encrypt section above.
Request body
{
"protected": "<base64url JWE Protected Header>",
"encrypted_key": "<base64url wrapped CEK>",
"iv": "<base64url IV>",
"ciphertext": "<base64url ciphertext>",
"tag": "<base64url GCM authentication tag>",
"aad": "<base64url AAD>" // optional; must match the value used during encryption
}
| Field | Required | Description |
|---|---|---|
protected | ✓ | Base64url-encoded JWE Protected Header (must contain alg, enc, kid) |
encrypted_key | For RSA-OAEP | The RSA-OAEP-wrapped CEK (empty or absent for dir) |
iv | ✓ | 12-byte initialization vector (base64url) |
ciphertext | ✓ | Encrypted data (base64url) |
tag | ✓ | 16-byte GCM authentication tag (base64url) |
aad | Additional authenticated data (base64url) |
Response body
{
"kid": "<key-uuid>",
"data": "<base64url plaintext>"
}
Security: implicit rejection
For RSA-OAEP decryption, the server implements implicit rejection as recommended
by RFC 7516 §11.5. If the
RSA-OAEP unwrap fails (indicating a tampered or invalid encrypted_key), the server
substitutes a random CEK and proceeds with AES-GCM decryption — which will fail
with the same generic "Decryption failed" error. This prevents padding oracle attacks.
Example (curl)
# JWE is the JSON response from POST /v1/crypto/encrypt
PLAINTEXT=$(curl -s -X POST https://kms.example.com/v1/crypto/decrypt \
-H 'Content-Type: application/json' \
-d "$JWE" | jq -r '.data | @base64d')
echo "$PLAINTEXT"
POST /v1/crypto/sign
Sign data using an asymmetric private key. Returns a detached JWS (payload not included in the response).
Supported algorithms: RS256, RS384, RS512, PS256, PS384, PS512,
ES256, ES384, ES512; EdDSA and MLDSA44 (non-FIPS builds only).
Flow — Sign and verify
sequenceDiagram
participant Client
participant KMS
Client->>KMS: POST /v1/crypto/keys {"kty":"RSA","alg":"PS256"}
KMS-->>Client: {"kid":"<priv-uuid>","kid_public":"<pub-uuid>"}
Client->>KMS: POST /v1/crypto/sign {"kid":"<priv-uuid>","alg":"PS256","data":"<b64>"}
Note over KMS: RSA-PSS sign with private key
KMS-->>Client: {"protected":"<b64-header>","signature":"<b64>"}
Client->>KMS: POST /v1/crypto/verify {"protected":"<b64-header>","data":"<b64>","signature":"<b64>"}
Note over KMS: Decode protected header → kid<br/>Fetch public key<br/>RSA-PSS verify
KMS-->>Client: {"kid":"<pub-uuid>","valid":true}
Client->>KMS: DELETE /v1/crypto/keys/<priv-uuid>
KMS-->>Client: 204 No Content (cascades to public key)
Request body
{
"kid": "<private-key-uuid>",
"alg": "RS256",
"data": "<base64url payload>"
}
Response body
{
"protected": "<base64url JWS Protected Header>",
"signature": "<base64url signature>"
}
Example (curl)
# 1. Create an RSA-2048 key pair
KEYS=$(curl -s -X POST https://kms.example.com/v1/crypto/keys \
-H 'Content-Type: application/json' \
-d '{"kty":"RSA","alg":"RS256"}')
KID=$(echo "$KEYS" | jq -r '.kid')
# 2. Sign
DATA_B64=$(printf 'data to sign' | base64 | tr '+/' '-_' | tr -d '=')
SIGN_RESP=$(curl -s -X POST https://kms.example.com/v1/crypto/sign \
-H 'Content-Type: application/json' \
-d "{\"kid\":\"$KID\",\"alg\":\"RS256\",\"data\":\"$DATA_B64\"}")
# 3. Verify
curl -s -X POST https://kms.example.com/v1/crypto/verify \
-H 'Content-Type: application/json' \
-d "$(jq -n --argjson s "$SIGN_RESP" --arg d "$DATA_B64" \
'{protected:$s.protected,data:$d,signature:$s.signature}')"
# 4. Clean up
curl -s -X DELETE https://kms.example.com/v1/crypto/keys/$KID
POST /v1/crypto/verify
Verify a detached JWS signature. The KMS looks up the public key from the protected header.
Required: the JWS protected header decoded from
protectedmust contain akidfield set to the KMS public key UUID. Requests withoutkidare rejected with400. This field is set automatically byPOST /v1/crypto/sign.The verify endpoint is the second half of the sign/verify flow shown in the sign section above.
Request body
{
"protected": "<base64url JWS Protected Header (contains kid + alg)>",
"data": "<base64url payload>",
"signature": "<base64url signature>"
}
Response body
{
"kid": "<public-key-uuid>",
"valid": true // false when the signature does not match
}
POST /v1/crypto/mac
Compute or verify a MAC (Message Authentication Code).
- Compute: omit the
macfield → the KMS returns the computed MAC value. - Verify: include the
macfield → the KMS returnsvalid: true/false.
Supported algorithms: HS256, HS384, HS512.
Flow — MAC compute and verify
sequenceDiagram
participant Client
participant KMS
Client->>KMS: POST /v1/crypto/keys {"kty":"oct","alg":"HS256"}
KMS-->>Client: {"kid":"<uuid>"}
Client->>KMS: POST /v1/crypto/mac {"kid":"<uuid>","alg":"HS256","data":"<b64>"}
Note over KMS: HMAC-SHA256 compute
KMS-->>Client: {"kid":"<uuid>","mac":"<b64>"}
Client->>KMS: POST /v1/crypto/mac {"kid":"<uuid>","alg":"HS256","data":"<b64>","mac":"<b64>"}
Note over KMS: HMAC-SHA256 verify
KMS-->>Client: {"kid":"<uuid>","valid":true}
Client->>KMS: DELETE /v1/crypto/keys/<uuid>
KMS-->>Client: 204 No Content
Request body
{
"kid": "<key-uuid>",
"alg": "HS256",
"data": "<base64url data>",
"mac": "<base64url MAC to verify>" // omit to compute
}
Response body — compute
{
"kid": "<key-uuid>",
"mac": "<base64url MAC>"
}
Response body — verify
{
"kid": "<key-uuid>",
"valid": true // false when the MAC does not match
}
RFC 7515 §A.1 known-answer vector
The MAC value below is pinned by an integration test (test_rfc7515_a1_hs256_known_answer).
It reproduces the exact HS256 result from RFC 7515 §Appendix A.1.
| Field | Value |
|---|---|
| Key (base64url) | AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow |
| Data | JWS Signing Input from RFC 7515 §A.1 |
alg | HS256 |
Expected mac | dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk |
Example (curl)
# 1. Create an HMAC-SHA256 key
KID=$(curl -s -X POST https://kms.example.com/v1/crypto/keys \
-H 'Content-Type: application/json' \
-d '{"kty":"oct","alg":"HS256"}' | jq -r '.kid')
# 2. Compute MAC
DATA_B64=$(printf 'message' | base64 | tr '+/' '-_' | tr -d '=')
MAC_RESP=$(curl -s -X POST https://kms.example.com/v1/crypto/mac \
-H 'Content-Type: application/json' \
-d "{\"kid\":\"$KID\",\"alg\":\"HS256\",\"data\":\"$DATA_B64\"}")
MAC_VALUE=$(echo "$MAC_RESP" | jq -r '.mac')
# 3. Verify MAC
curl -s -X POST https://kms.example.com/v1/crypto/mac \
-H 'Content-Type: application/json' \
-d "{\"kid\":\"$KID\",\"alg\":\"HS256\",\"data\":\"$DATA_B64\",\"mac\":\"$MAC_VALUE\"}"
# 4. Clean up
curl -s -X DELETE https://kms.example.com/v1/crypto/keys/$KID
Key tag management
User-defined string tags can be attached to any key stored in the KMS. Tags
enable key discovery (for example the JWKS endpoint returns only keys tagged
"jwks") and custom key grouping.
Rules:
- Tags are arbitrary, non-empty strings.
- Tags starting with
_are system tags (_kk,_sk,_pk,_cert, …) and cannot be created or deleted through these endpoints. - All write operations are idempotent: adding an existing tag or removing a missing tag has no effect.
POST /v1/crypto/keys/{kid}/tags
Add one or more user tags to a key. Existing tags are preserved.
Request body
{ "tags": ["jwks", "prod"] }
| Field | Required | Description |
|---|---|---|
tags | ✓ | Array of non-empty tag strings (must not start with _) |
Response body
{ "kid": "<key-uuid>", "tags": ["jwks", "prod"] }
The tags array reflects the complete current set of user tags after the
operation (sorted, system tags excluded).
Status codes
| Status | Meaning |
|---|---|
200 | Tags updated successfully |
400 | Empty tag string or _-prefixed (system) tag supplied |
403 | Key access denied |
404 | Key not found |
curl example
curl -s -X POST "https://kms.example.com/v1/crypto/keys/${KID}/tags" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"tags": ["jwks", "prod"]}'
DELETE /v1/crypto/keys/{kid}/tags
Remove one or more user tags from a key. Tags not present on the key are silently ignored.
Request body
{ "tags": ["prod"] }
| Field | Required | Description |
|---|---|---|
tags | ✓ | Array of tag strings to remove (must not start with _) |
Response body
{ "kid": "<key-uuid>", "tags": ["jwks"] }
The tags array reflects the remaining user tags after removal.
Status codes
| Status | Meaning |
|---|---|
200 | Tags updated successfully |
400 | Empty tag string or _-prefixed (system) tag supplied |
403 | Key access denied |
404 | Key not found |
curl example
curl -s -X DELETE "https://kms.example.com/v1/crypto/keys/${KID}/tags" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"tags": ["prod"]}'
GET /v1/crypto/keys/{kid}/tags
List the current user tags on a key. No body required.
Response body
{ "kid": "<key-uuid>", "tags": ["jwks"] }
System tags are never included.
Status codes
| Status | Meaning |
|---|---|
200 | OK |
403 | Key access denied |
404 | Key not found |
curl example
curl -s "https://kms.example.com/v1/crypto/keys/${KID}/tags" \
-H "Authorization: Bearer ${TOKEN}"
Error responses
All endpoints return a JSON body { "error": "<type>", "description": "<detail>" } with
an appropriate HTTP status code:
| Status | Meaning |
|---|---|
400 | Bad request (malformed base64, missing field, etc.) |
403 | Forbidden (key access denied) |
404 | Key not found |
422 | Unsupported or unknown algorithm |
500 | Internal server error / cryptographic failure |
Known limitations
The following JOSE features are not yet implemented in this API.
| Missing feature | Blocked by |
|---|---|
JWE alg=RSA-PKCS1-v1_5 + enc=A128CBC-HS256 (RFC 7516 §A.2) | RSA-PKCS1v1.5 + AES-CBC not implemented |
JWE alg=A128KW + enc=A128CBC-HS256 (RFC 7516 §A.3) | AES key-wrap + AES-CBC not implemented |
JWE alg=dir + enc=A128CBC-HS256 (RFC 7516 §A.5) | AES-CBC enc not implemented |
JWE alg=ECDH-ES (RFC 7518 §C) | ECDH-ES key agreement not implemented |
JWS verify without kid in protected header | kid-less verify not yet supported |
Full RFC 7515 §A.2/A.3/A.4 known-answer tests are deferred until kid-less verification is supported (current tests do round-trips with freshly generated keys).
Algorithm support matrix
Key management algorithms (alg)
| Algorithm | FIPS | Operation | Notes |
|---|---|---|---|
dir | ✓ | encrypt / decrypt | Direct use of symmetric key as CEK |
RSA-OAEP | ✓ | encrypt / decrypt / unwrap | RSA-OAEP with SHA-1 (RFC 7518 §4.3) |
RSA-OAEP-256 | ✓ | encrypt / decrypt / unwrap | RSA-OAEP with SHA-256 (RFC 7518 §4.3) |
Content encryption algorithms (enc)
| Algorithm | FIPS | Key size | Notes |
|---|---|---|---|
A128GCM | ✓ | 128 bits | AES-GCM with 96-bit IV, 128-bit tag |
A192GCM | ✓ | 192 bits | AES-GCM with 96-bit IV, 128-bit tag |
A256GCM | ✓ | 256 bits | AES-GCM with 96-bit IV, 128-bit tag |
Signature algorithms
| Algorithm | FIPS | Operation |
|---|---|---|
RS256/384/512 | ✓ | sign / verify |
PS256/384/512 | ✓ | sign / verify |
ES256/384/512 | ✓ | sign / verify |
EdDSA | ✗ | sign / verify (non-FIPS) |
MLDSA44 | ✗ | sign / verify (non-FIPS) |
MAC algorithms
| Algorithm | FIPS | Operation |
|---|---|---|
HS256/384/512 | ✓ | mac compute / verify |
JWE Decryption — Unwrap without Key Exposure
This use case describes how to decrypt JWE (JSON Web Encryption) tokens using the Cosmian KMS without ever exposing the symmetric content encryption key (CEK) to the calling application.
Problem Statement
You receive JWE tokens with the structure: Kpub(Ksym) . Ksym(value)
Ksym(value): the payloadvalueis encrypted with a symmetric AES keyKsym(the CEK)Kpub(Ksym): the CEK is wrapped (encrypted) with an RSA public keyKpub- The
kid(Key ID) of the RSA key pair is known
Security constraint: the calling application must never have access to Ksym.
Solution: One-Shot JWE Decrypt (No Key Persistence)
If the full JWE is available at each decryption call (including the encrypted_key
field), the REST crypto endpoint performs all operations server-side in a single request.
Ksym is used ephemerally in memory and immediately zeroized.
No additional development required.
Flow
sequenceDiagram
participant App as Application
participant KMS as KMS Server
participant HSM as HSM (optional)
App->>KMS: POST /v1/crypto/decrypt<br/>{protected, encrypted_key=Kpub(Ksym),<br/>iv, ciphertext=Ksym(value), tag}
alt Kpriv in HSM
KMS->>HSM: C_Decrypt(handle_kpriv, Kpub(Ksym))
HSM-->>KMS: Ksym (stays in server RAM only)
else Kpriv in database
KMS->>KMS: RSA-OAEP decrypt(Kpriv, Kpub(Ksym)) → Ksym
end
KMS->>KMS: AES-GCM decrypt(Ksym, iv, ciphertext, tag) → value
KMS->>KMS: Zeroize(Ksym)
KMS-->>App: {"kid":"<kid>", "data":"<base64url(value)>"}
Request
curl -s -X POST https://kms.example.com/v1/crypto/decrypt \
-H 'Content-Type: application/json' \
-d '{
"protected": "<base64url JWE header: {\"alg\":\"RSA-OAEP-256\",\"enc\":\"A256GCM\",\"kid\":\"<kid>\"}>",
"encrypted_key": "<base64url of Kpub(Ksym)>",
"iv": "<base64url of 12-byte IV>",
"ciphertext": "<base64url of Ksym(value)>",
"tag": "<base64url of 16-byte GCM tag>"
}'
Response
{ "kid": "<kid>", "data": "<base64url of decrypted value>" }
The application receives value — never Ksym.
Server Configuration (TOML)
Minimal configuration with HSM holding the RSA private key:
[[hsm_instances]]
hsm_model = "softhsm2" # or: utimaco, proteccio, crypt2pay, smartcardhsm
hsm_admin = ["admin"]
hsm_slot = [0]
hsm_password = ["changeme"]
[http]
port = 9998
hostname = "0.0.0.0"
[db]
database_type = "sqlite"
sqlite_path = "data/kms-objects"
If Kpriv is stored in the HSM with UID hsm::softhsm2::0::my_rsa_key, set the
kid in the JWE protected header to this UID. The KMS automatically routes the
RSA-OAEP decrypt to the HSM via the crypto oracle.
Re-encryption
After decryption, re-encrypt value with a new key in the same call flow:
curl -s -X POST https://kms.example.com/v1/crypto/encrypt \
-H 'Content-Type: application/json' \
-d '{
"kid": "<kid_new_key>",
"alg": "RSA-OAEP-256",
"enc": "A256GCM",
"data": "<base64url of value>"
}'
Advanced: Persisting Ksym in the KMS (Key Unwrap Endpoint)
If the application receives subsequent ciphertexts Ksym(value) without the
Kpub(Ksym) wrapper (i.e., the same CEK is reused across multiple messages), then
Ksym must be persisted for later reuse. The POST /v1/crypto/keys/unwrap endpoint
unwraps the CEK using RSA-OAEP and imports it as a managed symmetric key — without
ever exposing the raw key material to the calling application.
Flow
sequenceDiagram
participant App as Application
participant KMS as KMS Server
participant HSM as HSM (optional)
Note over App,KMS: Step 1 — Unwrap and persist Ksym (once)
App->>KMS: POST /v1/crypto/keys/unwrap<br/>{protected: {alg:"RSA-OAEP-256",<br/>enc:"A256GCM", kid:"<kpriv_uid>"},<br/>encrypted_key: Kpub(Ksym)}
alt Kpriv in HSM
KMS->>HSM: C_Decrypt(handle_kpriv, Kpub(Ksym))
HSM-->>KMS: Ksym
else Kpriv in database
KMS->>KMS: RSA-OAEP decrypt(Kpriv, Kpub(Ksym)) → Ksym
end
KMS->>KMS: Import Ksym as Active symmetric key
KMS-->>App: {"kid":"<ksym_uid>", "kty":"oct",<br/>"alg":"A256GCM", "key_ops":["encrypt","decrypt"]}
Note over App,KMS: Step 2 — Decrypt with persisted Ksym (subsequent calls)
App->>KMS: POST /v1/crypto/decrypt<br/>{protected: {alg:"dir", enc:"A256GCM",<br/>kid:"<ksym_uid>"},<br/>iv, ciphertext, tag}
KMS->>KMS: AES-GCM decrypt(Ksym, iv, ciphertext, tag) → value
KMS-->>App: {"kid":"<ksym_uid>", "data":"<base64url(value)>"}
Step 1: Unwrap the CEK
curl -s -X POST https://kms.example.com/v1/crypto/keys/unwrap \
-H 'Content-Type: application/json' \
-d '{
"protected": "<base64url of {\"alg\":\"RSA-OAEP-256\",\"enc\":\"A256GCM\",\"kid\":\"<kpriv_uid>\"}>",
"encrypted_key": "<base64url of Kpub(Ksym)>"
}'
Response
{
"kid": "<ksym_uid>",
"kty": "oct",
"alg": "A256GCM",
"key_ops": ["encrypt", "decrypt"]
}
The symmetric key is now stored in the KMS. The application receives only the kid
identifier — never the raw key bytes.
Step 2: Decrypt with the Persisted Key
curl -s -X POST https://kms.example.com/v1/crypto/decrypt \
-H 'Content-Type: application/json' \
-d '{
"protected": "<base64url of {\"alg\":\"dir\",\"enc\":\"A256GCM\",\"kid\":\"<ksym_uid>\"}>",
"iv": "<base64url of 12-byte IV>",
"ciphertext": "<base64url of Ksym(value)>",
"tag": "<base64url of 16-byte GCM tag>"
}'
Response
{ "kid": "<ksym_uid>", "data": "<base64url of decrypted value>" }
Supported Algorithms
alg (key wrapping) | enc (content encryption) |
|---|---|
RSA-OAEP | A128GCM, A192GCM, A256GCM |
RSA-OAEP-256 | A128GCM, A192GCM, A256GCM |
Error Conditions
| Condition | HTTP Status | Error Code |
|---|---|---|
Invalid base64url in protected or encrypted_key | 400 | bad_request |
Missing kid, alg, or enc in protected header | 400 | bad_request |
Empty encrypted_key | 400 | bad_request |
Unsupported algorithm (e.g., dir, A128KW) | 422 | unsupported_algorithm |
| Private key not found | 404 | not_found |
| Decryption failure (wrong key, corrupted data) | 422 | decryption_failed |
CEK size mismatch with enc algorithm | 422 | crypto_failure |
Advanced: Persisting Ksym in the HSM (Requires Development)
If the application requires that Ksym never leaves the HSM boundary (even transiently
in KMS server memory), the PKCS#11 C_UnwrapKey operation can be used to import the
key directly into the HSM hardware.
The PKCS#11 C_UnwrapKey operation is implemented in the HSM driver code but is
not yet exposed by any production KMS endpoint. Integrating it into a server
endpoint requires additional development.
Target Flow (After Development)
sequenceDiagram
participant App as Application
participant KMS as KMS Server
participant HSM as HSM
Note over App,HSM: Step 1 — Unwrap and persist Ksym (once)
App->>KMS: KMIP Import {wrapped_key=Kpub(Ksym),<br/>wrapping_key="hsm::softhsm2::0::kpriv",<br/>store_in_hsm=true}
KMS->>HSM: C_UnwrapKey(CKM_RSA_PKCS_OAEP, handle_kpriv, Kpub(Ksym))
HSM->>HSM: Decrypt + store AES key<br/>CKA_SENSITIVE=TRUE, CKA_EXTRACTABLE=FALSE
HSM-->>KMS: handle_ksym (opaque)
KMS-->>App: {"UniqueIdentifier": "hsm::softhsm2::0::ksym_123"}
Note over App,HSM: Step 2 — Decrypt with persisted Ksym (subsequent calls)
App->>KMS: POST /v1/crypto/decrypt<br/>{protected: {alg:"dir", enc:"A256GCM",<br/>kid:"hsm::softhsm2::0::ksym_123"},<br/>iv, ciphertext, tag}
KMS->>HSM: C_Decrypt(handle_ksym, iv||ciphertext||tag)
HSM-->>KMS: value
KMS-->>App: {"kid":"hsm::softhsm2::0::ksym_123", "data":"<base64url(value)>"}
The POST /v1/crypto/decrypt endpoint with alg=dir and a kid referencing an
HSM key (hsm::...) already routes to C_Decrypt on the HSM. Only Step 1
(C_UnwrapKey integration) requires development.
What Needs to be Developed
| Component | Current State | Required Change |
|---|---|---|
PKCS#11 C_UnwrapKey wrapper | ✅ Implemented (test-only) | Wire into production endpoint |
HsmStore::atomic() | Only RSA keypairs | Support symmetric key import |
| UID routing for unwrapped keys | N/A | Assign hsm::model::slot::label UID |
| KMIP Import with HSM target | Not supported | Add store_in_hsm flag or detect HSM wrapping key |
Summary
| Approach | Ksym exposed? | Ksym persisted? | Dev required? | Conformant? |
|---|---|---|---|---|
POST /v1/crypto/decrypt (RSA-OAEP, full JWE) | ❌ No | ❌ No | ❌ No | ✅ If full JWE always available |
POST /v1/crypto/keys/unwrap + alg=dir decrypt | ❌ No | ✅ Yes (KMS DB) | ❌ No | ✅ Yes |
| KMIP Decrypt + Import | ✅ Yes | ✅ Yes | ❌ No | ❌ No (violates constraint) |
HSM C_UnwrapKey + alg=dir | ❌ No | ✅ Yes (HSM) | ⚠️ Yes | ✅ Yes |
JWKS endpoint
The KMS exposes a standard RFC 7517 JWKS endpoint at:
GET /.well-known/jwks.json
By default, every public key pair created through the REST API is automatically tagged
jwks and immediately advertised in the JWKS document. No extra step is
needed for the common case.
To exclude a specific public key from the JWKS remove its jwks tag via the tag management
endpoint.
How it works
sequenceDiagram
participant Client
participant KMS
Client->>KMS: POST /v1/crypto/keys {kty, alg}
KMS-->>Client: {kid, kid_public}
Note over Client,KMS: kid_public is auto-tagged "jwks" — no extra step
Client->>KMS: GET /.well-known/jwks.json
KMS-->>Client: {keys: [{kid, kty, alg, use, n, e, ...}]}
Quickstart
# EC P-256 key for JWS (ES256)
curl -s -X POST "https://kms.example.com/v1/crypto/keys" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"kty":"EC","alg":"ES256"}'
The response contains the KMS identifier for both the private key (kid) and
the public key (kid_public):
{
"kid": "<private-key-uuid>",
"kid_public": "<public-key-uuid>",
"kty": "EC",
"alg": "ES256",
"crv": "P-256",
"key_ops": ["sign", "verify"]
}
Verify the key is advertised
curl -s "https://kms.example.com/.well-known/jwks.json" | jq .
Expected output (abbreviated):
{
"keys": [
{
"kty": "EC",
"use": "sig",
"alg": "ES256",
"kid": "<public-key-uuid>",
"crv": "P-256",
"x": "...",
"y": "..."
}
]
}
Opt a key out of JWKS
Remove the jwks tag from the public key to stop advertising it. The key
material is not deleted.
curl -s -X DELETE "https://kms.example.com/v1/crypto/keys/${KID_PUBLIC}/tags" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"tags": ["jwks"]}'
The response confirms the updated tag set (the jwks tag is absent):
{ "kid": "<public-key-uuid>", "tags": [] }
If you later want to re-advertise a key that was previously opted out, add thejwks tag back via https://kms.example.com/v1/crypto/keys/${KID_PUBLIC}/tags
Key rotation
During rotation, both the retiring key and the new key are present in the JWKS document for a brief overlap period, allowing relying parties to verify tokens signed by either key.
# 1. Create the new key pair — automatically tagged "jwks".
NEW_KID_PUBLIC=$(curl -s -X POST "https://kms.example.com/v1/crypto/keys" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"kty":"EC","alg":"ES256"}' | jq -r .kid_public)
# 2. (overlap window) Both old and new keys appear in JWKS.
# 3. Opt the old key out of JWKS once all outstanding tokens have expired.
curl -s -X DELETE "https://kms.example.com/v1/crypto/keys/${OLD_KID_PUBLIC}/tags" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"tags": ["jwks"]}'
Keys created outside the REST API
Keys created directly through the KMIP protocol (e.g. via ckms or a KMIP
client library) are not auto-tagged. To include such a key in the JWKS
document, explicitly add the jwks tag:
curl -s -X POST "https://kms.example.com/v1/crypto/keys/${KID_PUBLIC}/tags" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"tags": ["jwks"]}'
Disable auto-tagging globally
By default the KMS tags every REST-created key pair for JWKS inclusion. If you prefer a fully manual opt-in model, disable auto-tagging in the server configuration:
| Method | Value |
|---|---|
| CLI flag | --jwks-endpoint-auto-tag=false |
| Environment variable | KMS_JWKS_ENDPOINT_AUTO_TAG=false |
| TOML config | jwks_endpoint_auto_tag = false |
When auto-tagging is disabled, newly created key pairs do not receive the
jwks tag. To publish a key you must tag it explicitly:
curl -s -X POST "https://kms.example.com/v1/crypto/keys/${KID_PUBLIC}/tags" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"tags": ["jwks"]}'
Existing keys are not affected when you change this setting.
See also
- JOSE API — full endpoint reference
- JWE Decryption — using the KMS as a JWE decryption oracle
Eviden KMS on AWS ECS
Deploy Eviden KMS on AWS ECS (Fargate) using either a production-ready setup with an Application Load Balancer (ALB) or a fast, fully managed Express Mode deployment.
Overview
This repository documents two supported ways to run Eviden KMS on AWS ECS.
| Mode | Use case |
|---|---|
| Fargate + ALB | Production, custom networking, HTTPS, persistence |
| Express Mode | PoC, demos, quick testing |
Prerequisites
- AWS account with access to:
- ECS
- EC2 (Security Groups)
- Elastic Load Balancing
- A VPC with at least two subnets
- Docker image:
ghcr.io/cosmian/kms:latest - KMS CLI installed https://docs.cosmian.com/kms_clients/installation/
Standard Deployment (Fargate + ALB)
1. Architecture
Traffic flows from the client to the ALB on the public HTTP port, which then routes requests to the private Fargate container on the application port.
flowchart LR
client["Client Station<br/>(KMS CLI)"]
subgraph aws["AWS Cloud"]
alb["ALB<br/>(Public Subnet)<br/>Listener Port 80"]
subgraph ecs["ECS Fargate (Private/Public)"]
container["Container<br/>Port 9998"]
end
sg_alb["Security Group<br/>(SG-ALB)"]
sg_ecs["Security Group<br/>(SG-ECS)"]
end
client -- "HTTP :80" --> alb
alb --> container
sg_alb -. controls .-> alb
sg_ecs -. controls .-> container
2. Deployment Steps
Networking
- ALB runs in public subnets
- ECS tasks can run in public or private subnets
- NAT Gateway is required if tasks run in private subnets
Security Groups
ALB Security Group
- Inbound: 80/TCP (and 443/TCP if HTTPS is enabled)
- Outbound: all traffic
ECS Task Security Group
- Inbound: 9998/TCP
- Source: ALB security group only
- Outbound: as required (database, external services)
Application Load Balancer
- Type: Internet-facing ALB
- Listener: HTTP on port 80
Target Group
- Target type: IP
- Protocol and port: HTTP / 9998
Health Check
- Path: /ui
- Success codes: 200
- Interval: 30 seconds
- Timeout: 10 seconds
ECS Task Definition
- Image: ghcr.io/cosmian/kms:latest
- Container port: 9998
- Environment variables:
- KMS configuration
- Database connection (if persistence is enabled)
ECS Service
- Attach the target group to container port 9998
- Health check grace period: minimum 60–120 seconds
3. Client Setup (KMS CLI)
Run: ckms configure
KMS URL example:
http(s)://<ALB-DNS-NAME>
4. Validation & Testing
Connectivity Test Verify that the ALB is correctly routing traffic to a healthy container.
curl http(s)://<YOUR-ALB-DNS-NAME>/ui
# Expected response: 200 OK with a JSON payload containing the version.
Create a symmetric key:
ckms sym keys create --tag test --algorithm aes --number-of-bits 256
# Expected response:
The symmetric key was successfully generated.
Unique identifier: xxxxxxx_xxxxxxx
Tags:
- test
5. Troubleshooting
503 Service Unavailable usually means:
- No running ECS tasks
- No healthy targets in the target group
- Health checks failing
Actions:
- Check ECS Service events
- Verify target group target health
- Increase health check grace period
Unhealthy targets:
- Ensure port 9998 is exposed
- Ensure ECS SG allows traffic from ALB SG
- Confirm /ui endpoint is reachable
6. Production Recommendations
- Enable HTTPS using ACM certificates
- Redirect HTTP to HTTPS
- Use an external database (e.g. RDS PostgreSQL) for persistence
- Configure Route53 DNS pointing to the ALB
Express Mode Deployment
Express Mode Architecture
flowchart LR
client["Client (CLI)"]
alb["Express ALB"]
task["Fargate Task (KMS:9998)"]
container["Container"]
client -->|HTTPS| alb
alb -->|HTTP| task
task --> container
Express Mode Deployment Steps
AWS Console → ECS → Express Mode
- Image: ghcr.io/cosmian/kms:latest
- Service name: kms-express
- Container port: 9998
- Desired tasks: 1
- healthcheck path : /ui
Wait until service status is Active.
Express Mode Client Setup
Run:
ckms configure
KMS URL example:
https://ex-xxxxxxxx.ecs.<region>.on.aws
Express Mode Validation
Connectivity test:
curl https://ex-xxxxxxxx.ecs.<region>.on.aws/ui
# Expected response: 200 OK with a JSON payload containing the version.
Create a symmetric key:
ckms sym keys create --tag test-express --algorithm aes --number-of-bits 256
# Expected response:
The symmetric key was successfully generated.
Unique identifier: xxxxxxx_xxxxxxx
Tags:
- test-express
Production Notes
- Express Mode is suitable for development, demos, and PoCs
- HTTPS is included by default
- Storage is ephemeral
- Use an external database for persistence
- Deleting the service removes all associated resources
License
Refer to Eviden documentation for licensing and support details.
Integration to AWS External Key Service (XKS)
Background
AWS XKS (External Key Store) is a feature of AWS Key Management Service (AWS KMS) that allows you to use cryptographic keys stored in an external key management system with AWS KMS. It enables you to maintain control over your keys while leveraging AWS services that integrate with AWS KMS.
Source: AWS KMS XKS Proxy API Specification - Background
Architecture
The Eviden KMS integrates to AWS XKS and proposes a novel architecture (dubbed xksv2) that solves the traditional XKS performance issues without compromising on security.
The Eviden XKSv2 architecture is composed of the following components:
Eviden Confidential KMS
This is the Confidential Key Management System, deployed as IaaS, in the customer AWS tenant. It is responsible for managing the Key Encryption Keys (KEKs) wrapping the XKS keys in AWS KMS and for answering encryption and decryption requests from the AWS KMS.
To protect the KEKs, the Eviden KMS runs inside an Eviden VM on top of confidential computing machines. Eviden VM provides strong security and verifiability guarantees.
The Eviden KMS is deployed in AWS infrastructure, solving the XKS scaling problem, as it benefits from a stable high bandwidth network and can easily scale to reliably support large amount of transactions from the AWS KMS.
The Confidential KMS is available as a ready-to-deploy product from the AWS Marketplace.
HSM
The HSM is responsible for storing the Master keys and securing the Eviden KMS keys. It is deployed in the customer premises or offered as a managed service by Atos. See the HSM integration documentation for more details.
Deployment
-
Deploy a Eviden KMS in your AWS tenant. You can find the product on the AWS Marketplace and follow the deployment instructions in the product documentation.
-
Configure the KMS for use with AWS XKS by filling up the
aws_xks_configsection of the configuration file with the following values:[aws_xks_config] # set this to true aws_xks_enable = true # this is the region you Eviden KMS is deployed in aws_xks_region = "us-east-1" # keep this to this value aws_xks_service = "xks-kms" # used for sigv4. The values set here must match the values configured # when setting up the KMS as an external keystore for AWS KMS (see next step) aws_xks_sigv4_access_key_id = "AKIAIOSFODNN7EXAMPLE" aws_xks_sigv4_secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" -
Configure the KMS to act as an External Key Store for AWS KMS. Follow the instructions in the AWS documentation to create an External Key Store.
-
Create an external key in AWS KMS and specify the key store created in the previous step as the key store for the key.

-
Enforce the correct permissions for the key on the Eviden KMS. Make sure the user used by AWS has the permissions for
Encrypt,DecryptandGetAttributes. For instance, when using DynamoDB, the user should be called something likedynamodb.amazonaws.com, for Salesforce, it is the user configured as part of the setup. In doubt, or for testing, grant theses permissions to all users (*).
Migrating an AWS External Key Store to a New Eviden KMS Instance
This guide describes how to migrate an AWS External Key Store (XKS) from one Eviden KMS instance (Server A, the source) to another (Server B, the target). This is typically required when moving to a new server, a new region, or upgrading infrastructure.
The migration must be performed with minimal downtime. During the transition window, AWS KMS marks
the key store as DISCONNECTED, meaning any AWS service that attempts to use an XKS key will
receive a KMSInvalidStateException until the connection is restored on Server B.
Prerequisites
- Server B must be deployed and configured with AWS XKS enabled (see the XKS deployment guide).
- You must know the AWS principal ARN that was granted permissions on each key (e.g.
dynamodb.amazonaws.com,arn:aws:iam::123456789012:user/Alice). - The SigV4 credentials configured on Server B must match (or be updated in) the AWS XKS key store settings.
Step 1 — Export all XKS keys from Server A
On Server A, export every key used by the XKS integration in json-ttlv format (the default).
This format preserves all KMIP metadata and can be re-imported identically on Server B.
For each key (replace <KEY_ID> with the actual unique identifier or tag):
# Export a single key to a local file
ckms -c /path/to/server_a.toml \
sym keys export \
--key-id <KEY_ID> \
keys/<KEY_ID>.json
Security note: The exported file contains the raw key material in KMIP JSON TTLV format. Store these files securely (encrypted storage, restricted filesystem permissions) and delete them once the import on Server B is complete.
Step 2 — Disconnect the XKS key store in AWS KMS
Before switching the endpoint, disconnect the external key store in the AWS Management Console or via the AWS CLI. This prevents AWS from sending requests to Server A while the endpoint is being updated.
Using the AWS CLI:
aws kms disconnect-custom-key-store \
--custom-key-store-id <CUSTOM_KEY_STORE_ID>
Confirm that the key store status is DISCONNECTED:
aws kms describe-custom-key-stores \
--custom-key-store-id <CUSTOM_KEY_STORE_ID> \
--query 'CustomKeyStores[0].ConnectionState'
Expected output:
"DISCONNECTED"
Alternatively, from the AWS Management Console, open the key store and click Key store actions → Disconnect:

Type disconnect in the confirmation dialog and click Disconnect key store:

A success banner confirms the key store is now disconnected:

Step 3 — Configure Server B
Ensure Server B's configuration file contains the correct AWS XKS parameters. The SigV4 credentials must match the values registered in the AWS key store configuration. If you are rotating the credentials, update both the KMS config and the AWS key store settings in the same operation (step 4).
[aws_xks_config]
aws_xks_enable = true
aws_xks_region = "eu-west-1" # region where your new KMS is deployed
aws_xks_service = "xks-kms"
aws_xks_sigv4_access_key_id = "YOUR_AWS_KEYID"
aws_xks_sigv4_secret_access_key = "YOUR_AWS_SECRETKEY"
aws_xks_kek_user = "admin"
Start (or restart) Server B after updating the configuration.
Step 4 — Update the XKS proxy URI in AWS KMS
Update the external key store to point to Server B's public endpoint. This can be done via the AWS Management Console (KMS → Custom key stores → Edit) or with the AWS CLI:
aws kms update-custom-key-store \
--custom-key-store-id <CUSTOM_KEY_STORE_ID> \
--xks-proxy-uri-endpoint "https://<SERVER_B_PUBLIC_HOSTNAME>" \
--xks-proxy-authentication-credential \
"AccessKeyId=YOUR_AWS_KEYID,RawSecretAccessKey=YOUR_AWS_SECRETKEY"
If you are keeping the same SigV4 credentials, the
--xks-proxy-authentication-credentialargument can be omitted.
Alternatively, from the AWS Management Console, click Key store actions → Edit:

Update the Proxy URI endpoint field with Server B's hostname, then click Update external key store:

Check the acknowledgement checkbox and confirm:

A success banner confirms the endpoint has been updated:

Step 5 — Import keys on Server B
On Server B, import each key exported in step 1. The --key-id parameter must preserve the
exact same unique identifier that was used on Server A, because AWS KMS references keys by their
ID in the XKS metadata endpoint path (/kms/xks/v1/keys/{key_id}/metadata).
ckms -c /path/to/server_b.toml \
sym keys import \
--key-id <KEY_ID> \
keys/<KEY_ID>.json
Repeat for every XKS key.
Step 6 — Re-grant access rights on Server B
The Eviden KMS access control is per-instance: permissions granted on Server A are not transferred
automatically. For each imported key, re-grant the operations required by AWS KMS
(get_attributes, encrypt, decrypt).
# Grant the required permissions to the AWS principal ARN
ckms -c /path/to/server_b.toml \
access-rights grant \
--id <KEY_ID> \
<AWS_PRINCIPAL_ARN> \
get_attributes encrypt decrypt
Step 7 — Reconnect the XKS key store
Once Server B is ready and all keys are imported with the correct permissions, reconnect the AWS external key store:
aws kms connect-custom-key-store \
--custom-key-store-id <CUSTOM_KEY_STORE_ID>
Poll until the status returns CONNECTED:
aws kms describe-custom-key-stores \
--custom-key-store-id <CUSTOM_KEY_STORE_ID> \
--query 'CustomKeyStores[0].ConnectionState'
Expected output:
"CONNECTED"
If the connection fails, check Server B's logs for SigV4 authentication errors or TLS issues. Verify the
aws_xks_sigv4_access_key_idandaws_xks_sigv4_secret_access_keyvalues match exactly what was provided toupdate-custom-key-store.
Step 8 — Verify the migration
Test an encrypt/decrypt round-trip through AWS KMS using one of the migrated keys to confirm end-to-end connectivity:
# Encrypt a small test payload
aws kms encrypt \
--key-id <AWS_KMS_KEY_ARN> \
--plaintext "SGVsbG8gV29ybGQ=" \
--output text \
--query CiphertextBlob \
> /tmp/ciphertext.b64
# Decrypt it back
aws kms decrypt \
--key-id <AWS_KMS_KEY_ARN> \
--ciphertext-blob fileb://<(base64 -d /tmp/ciphertext.b64) \
--output text \
--query Plaintext | base64 -d
Expected output: Hello World
Post-migration cleanup
Once the migration is validated:
-
Delete the exported key files from your local filesystem:
rm keys/*.json -
Shut down Server A (or reconfigure it to no longer serve the XKS endpoints).
-
If applicable, revoke access rights on Server A to prevent any residual use:
ckms -c /path/to/server_a.toml \ access-rights revoke \ --id <KEY_ID> \ <AWS_PRINCIPAL_ARN> \ get_attributes encrypt decrypt
AWS KMS - Bring Your Own Key (BYOK)
Eviden KMS provides an aws byok command in its CLI (also available in the ui) to facilitate the import of an AWS wrapping key (KEK) in Eviden KMS, and the export of the wrapped keys for direct import in AWS KMS. To use the AWS KMS terminology, the key that will be created in the Eviden KMS will be called the external key material as stated in the AWS KMS docs.
The key material refers to the actual cryptographic key bytes that form the basis of a KMS key. While AWS KMS keys include additional metadata, policies, and access controls, the BYOK process allows Eviden KMS users to maintain full control over key generation while leveraging AWS KMS's infrastructure for other usages.
Table of Contents
Overview
Since AWS KMS is a managed service where private key material never leaves AWS HSMs, the key import process requires:
- Creating a KMS key with
EXTERNALorigin (no key material) - Download the wrapping public key and import token from AWS
- Wrap your key material using Eviden KMS
- Import the wrapped key material into AWS KMS
Supported wrapping algorithms:
| Wrapping Algorithm | Description | Supported Key Material Types |
|---|---|---|
| RSAES_OAEP_SHA_256 RSAES_OAEP_SHA_1 | The RSA encryption algorithm with Optimal Asymmetric Encryption Padding (OAEP) with SHA-256 or SHA-1 hash function. | • 256-bit AES Symmetric keys • HMAC keys • Asymmetric ECC private keys* |
| RSA_AES_KEY_WRAP_SHA_256 RSA_AES_KEY_WRAP_SHA_1 | Hybrid wrapping (RSA + AES Key Wrap) with SHA-256 or SHA-1 hash function. | • Asymmetric RSA private keys • Asymmetric ECC private keys |
Wrapping Key Specs:
- RSA_2048 (Note: cannot be used to wrap ECC_NIST_P521 keys with RSAES_OAEP_SHA*_)
- RSA_3072
- RSA_4096
⚠️ WARNING: Invalid combinations of wrapping algorithms, key material types may lead to errors. Ensure that your selected key material type is supported by the chosen wrapping algorithm and that the wrapping key spec is compatible with both.
Prerequisites
- An active AWS account
- Either: AWS CLI installed and configured on your machine (recommended) or an access to AWS Management Console and open the AWS Key Management Service (AWS KMS) console at https://console.aws.amazon.com/kms.
- A running Eviden KMS instance.
- Either: Eviden KMS CLI installed and configured on your machine or an access to the Eviden KMS UI of your deployed KMS instance.
- Any tool to convert base64 values to their binary counterparts (e.g. openssl, python, etc).
Creating an AES key and importing it using the AWS CLI and the Eviden CLI
1. Create a KMS key with EXTERNAL origin
To use the AWS KMS API to create a symmetric encryption KMS key with no key material, send a CreateKey request with the Origin parameter set to EXTERNAL :
aws kms create-key --origin EXTERNAL
If successful, the output should look like :
{
"KeyMetadata": {
"AWSAccountId": "447182645454",
"KeyId": "350e35ef-ac51-4dbb-82a4-9bc50b0ea42b",
"Arn": "arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b",
"CreationDate": "2026-02-18T15:05:59.358000+01:00",
"Enabled": false,
"Description": "",
"KeyUsage": "ENCRYPT_DECRYPT",
"KeyState": "PendingImport",
"Origin": "EXTERNAL",
"KeyManager": "CUSTOMER",
"CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
"KeySpec": "SYMMETRIC_DEFAULT",
"EncryptionAlgorithms": [
"SYMMETRIC_DEFAULT"
],
"MultiRegion": false
}
}
Copy the key ARN, you will need it in the next step. In this example, the key ARN is
arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b.
Note: If no key spec is specified, a symmetric key is created by default. To create a different key, pass the key-spec argument like below for an ECC_NIST_P384 key :
aws kms create-key \
--origin EXTERNAL \
--key-spec ECC_NIST_P384 \
--description "External NIST-P384 key for signing"
2. Create a symmetric key in Eviden KMS
ckms sym keys create symmetric_key_test1
Response:
The symmetric key was successfully generated.
Unique identifier: symmetric_key_test1
3. Download wrapping public key and import token from AWS
After you create a AWS KMS key with no key material, download a wrapping public key and an import token for that KMS key by using the AWS KMS console or the GetParametersForImport API. The wrapping public key and import token are an indivisible set that must be used together.
A very detailed example on how to do this is detailed on this page, please refer to it for more info.
The command you should use is the following :
aws kms get-parameters-for-import \
--key-id arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b \
--wrapping-algorithm RSAES_OAEP_SHA_256 \
--wrapping-key-spec RSA_4096
Response:
{
"KeyId": "arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b",
"ImportToken": "<YourBase64EncodedToken>",
"PublicKey": "<YourBase64EncodedPublicKey>",
"ParametersValidTo": "2026-02-19T15:07:13.227000+01:00"
}
As mentioned in the AWS documentation for importing key material, you will have to convert the base64 values to their binary counterparts before importing them. This can be done with the method of your choice, the most straightforward method (If you have openssl on your cli), would be to copy the token and paste it with the following command to get the file token.bin :
echo -n "<YourBase64EncodedToken>" | openssl enc -d -base64 -A -out token.bin
In a similar manner, you can use the command if you want to keep your public key as a binary blob :
echo -n "<YourBase64EncodedPublicKey>" | openssl enc -d -base64 -A -out kek.bin
4. Import the AWS KEK into Eviden KMS
ckms aws byok import \
--kek-base64 "<YourBase64EncodedPublicKey>" \
--wrapping-algorithm RSAES_OAEP_SHA_256 \
--key-arn "<YourKeyArn>" \
--key-id aws_kek_1
Feel free to change the key id to whatever you want, we will call the kek aws_kek_1 in this example.
Alternative : importing the kek as file
ckms aws byok import \
--kek-file kek.bin \
--wrapping-algorithm RSAES_OAEP_SHA_256 \
--key-arn arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b \
--key-id aws_kek_1
Response:
The PublicKey in file /tmp/ca9f45ad-8596-45a6-bc57-5591e662cb61 was successfully imported with id: aws_kek_1.
Unique identifier: aws_kek_1
Tags:
- aws
- wrapping_algorithm:RsaesOaepSha256
- key_arn:arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b
5. Export the wrapped key material from Eviden KMS
# Provide token file simply to display the correct AWS CLI command for import
# If the output file is not specified, the CLI returns base64 encoded encrypted key material
ckms aws byok export \
symmetric_key_test1 \
kek_test1 \
token.bin \
EncryptedKeyMaterial.bin
Response:
The encrypted key material was successfully written to 512 for key symmetric_key_test1.
To import into AWS KMS using the API, run:
aws kms import-key-material \
--key-id arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b \
--encrypted-key-material fileb://EncryptedKeyMaterial.bin \
--import-token fileb://token.bin \
--expiration-model KEY_MATERIAL_DOES_NOT_EXPIRE
6. Import the wrapped key material into AWS KMS
If you have filled all the fields on the previous step, you can directly use the command that the Eviden CLI automatically generated for you:
aws kms import-key-material \
--key-id arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b \
--encrypted-key-material fileb://EncryptedKeyMaterial.bin \
--import-token fileb://token.bin \
--expiration-model KEY_MATERIAL_DOES_NOT_EXPIRE
Response:
{
"KeyId": "arn:aws:kms:eu-west-3:447182645454:key/350e35ef-ac51-4dbb-82a4-9bc50b0ea42b",
"KeyMaterialId": "60a5374a2457941eaf5c26b75fea0236bcdc5ddbe70c4aa15046e6fdda49e334"
}
Receiving this response means that the key material has been successfully imported into AWS KMS.
Creating an RSA key and importing it using the AWS CLI and the Eviden CLI
For this example, we will create an 2048 bits RSA key material, wrapped using a 4096 kek with RSAES_OAEP_SHA_256.
First, Sign in to the AWS Management Console and open the AWS Key Management Service (AWS KMS) console at https://console.aws.amazon.com/kms and complete the necessary steps to create a KMS key with external key material. Be mindful to provide the correct key spec - otherwise the console will expect a symmetric key by default. For this example, we will use RSA_2048.
The next step is to download the wrapping public key and import token. Be mindful that an RSA_AES_KEY_WRAP_SHA wrapping algorithm is required for wrapping RSA private key material (except in China Regions). Choosing RSAES_OAEP_SHA_256 will work for this example.
Once this is done, create your key on the cosmian KMS like follow, we call it rsa_key_material :

Then, navigate to the AWS - Import Kek section and fill with the adequate data. In this example, we paste the kek in the base64 format for convenience, and call it aws_kek_2.

Finally, export the wrapped key material from Eviden KMS to import it into AWS KMS.

We named the file to export EncryptedKeyMaterial.bin. You can import the wrapped key material using the AWS CLI or the AWS Management Console.
An in depth explanation of the import process can be found in the AWS documentation to Import key material (console).
Automated BYOK Scripts
To facilitate testing and automating the BYOK flow, we provide ready-to-use Bash scripts that demonstrate the end-to-end process of creating an AWS KMS key, generating the corresponding key material using the Eviden CLI, and performing the import/export procedures.
The following scripts are available for download:
-
RSA BYOK Script: Automates the import of RSA private key material. Supports RSA key sizes:
2048,3072, and4096. Findrun_rsa_byok.shon repository -
ECC BYOK Script: Automates the import of Elliptic Curve private key material. Supports NIST curves:
p256,p384, andp521. Findrun_ecc_byok.shon repository -
AES BYOK Script: Automates the import of 256-bit AES symmetric key material. Find
run_aes_byok.shon repository
Usage
Each script requires the cosmian CLI to be available either in your PATH, the current directory, or specified via the COSMIAN_KMS_CLI environment variable. Also, ensure the aws CLI is available in your PATH, authenticated, and configured.
Example usage:
# Make the script executable
chmod +x run_rsa_byok.sh
# Run the script with the desired key size and an optional description
./run_rsa_byok.sh 2048 "My RSA External Key"
Eviden KMS provides a azure byok command in its CLI to facilitate the import of an Azure wrapping key (KEK) in
Eviden KMS, and the export of the wrapped keys in the .byok format for easy import in Azure Key Vault.
Follow this Azure documentation, for a description of Bring Your Own Key (BYOK) in Azure Key Vault,
The vault must be a premium Azure Key Vault, and the user performing the operations
must have the role of Crypto Officer.
Table of Contents
Create two test keys in the Eviden KMS
These keys will later be exported wrapped by the Azure (KEK) key, and imported into Azure Key Vault.
Create an RSA Key
The key will be a 4096-bit key.
ckms rsa keys create --size_in_bits 4096 TestRSAKey
Public key unique identifier: TestRSAKey_pk
Private key unique identifier: TestRSAKey
Create an Elliptic Curve Key
The key will be created on the NIST P-256 curve.
ckms ec keys create --curve nist-p256 TestECKey
Public key unique identifier: TestECKey_pk
Private key unique identifier: TestECKey
Create an Azure Key Encryption Key (KEK)
This key will be used to wrap the KMS RSA and EC private keys on export.
Using the Azure console:
Navigate to the Key Vault (say MyPremiumKeyVault) and create a 4096-bit RSA key.
Make sure to select Generate Key Encryption Key for importing HSM-protected Keys.

Using the az CLI:
The supported operations must be restricted to import.
az keyvault key create --kty RSA-HSM --size 4096 --name KEK-BYOK --ops import --vault-name MyPremiumKeyVault
In the azoutput, the key identifier (kid) will be something like:
"https://mypremiumkeyvault.vault.azure.net/keys/KEK-BYOK/664f5aa2797a4075b8e36ca4500636d8"
Please take note of the kid for next steps.
Export the Key Encryption (Public) Key
The KEK public key must be exported, then imported into the KMS.
Using the Azure console:
Edit the KEK by double-clicking on it.
Please take note of the key identifier (kid), which will be required later.
Download the public key and rename the file KEK-BYOK.public.pem.

Using the az CLI:
az keyvault key download --name KEK-BYOK --vault-name MyPremiumKeyVault --file KEK-BYOK.public.pem
Import the key encryption key in Eviden KMS
The KMS CLI provides an azure byok command to facilitate both the import of the key encryption key in Eviden KMS,
and the export of the wrapped keys in the .byok format for easy import in Azure Key Vault.
ckms azure byok import KEK-BYOK.public.pem \
https://hsmbackedkeyvault.vault.azure.net/keys/BYOK_KEK/5e617a4d39c74f47b0b7d345f6a49d1b \
BYOK_KEK
The PublicKey in file KEK-BYOK.public.pem was imported with id: BYOK_KEK
Unique identifier: BYOK_KEK
Tags:
- azure
- kid:https://hsmbackedkeyvault.vault.azure.net/keys/BYOK_KEK/5e617a4d39c74f47b0b7d345f6a49d1b
Please note the presence of the azure and kid: tags on the key.
These identify the key as an Azure Key Encryption Key (KEK) in the Eviden KMS.
Export the wrapped keys from the Eviden KMS
The KMS CLI azure byok export command will generate a .byok file
containing the wrapped private key, which can be directly imported into Azure Key Vault.
Export the RSA key
ckms azure byok export TestRSAKey BYOK_KEK
The byok file was written to "TestRSAKey.byok" for key TestRSAKey
Export the EC key
ckms azure byok export TestECKey BYOK_KEK
The byok file was written to "TestECKey.byok" for key TestECKey
Upload the byok transfer blob in Azure Key Vault
Wrapped private RSA keys can be imported using either the console or the az LI.
Elliptic curve keys can only be imported using the az CLI.
For an RSA Private Key
Using the Azure console:

Using the az CLI:
az keyvault key import --vault-name MyPremiumKeyVault --name TestRSAKey --byok-file TestRSAKey.byok \
--ops sign verify
For an EC Private Key
The key type and curve must be specified on import for elliptic curve keys.
az keyvault key import --vault-name MyPremiumKeyVault --name TestECKey --byok-file TestECKey.byok \
--kty EC --curve P-256 --ops sign verify
Eviden KMS implements the Azure External Key Manager (EKM) Proxy API, enabling it to serve as an external key management service for an Azure Managed HSM.
This integration allows organizations to maintain complete physical control over their encryption keys outside of Azure infrastructure while seamlessly integrating with Azure services that support Customer Managed Keys (CMK).
The Eviden KMS implementation follows and implements the Microsoft EKM Proxy API Specification for v0.1-preview.
High level architecture

The customer's Azure services (configured with Customer Managed Keys) communicate with Azure Managed HSM to perform encryption/decryption operations. A full list of Azure services that support CMK can be consulted on this page.
With this integration, your protected secrets remain under your complete control while maintaining compatibility with Azure's managed services.
The following diagram illustrates a possible use case where Eviden KMS acts as the EKM Proxy :
Api specification
URL format
All requests and responses for Azure EKM APIs are sent as JSON objects over HTTPS. Each request includes context information to associate Azure Managed HSM logs and audits with Eviden KMS logs.
The URI format for EKM Proxy API calls is:
https://{public-KMS-URI}/azureekm/[path-prefix]/{api-specific-paths}?api-version={client-api-version}
The parameters between brackets {} can be edited on the KMS configuration and must follow the following constraints :
Path Prefix:
- Maximum 64 characters
- Allowed characters: letters (a-z, A-Z), numbers (0-9), slashes (/), and dashes (-)
External Key ID:
- Referenced as
{key-name}in the endpoints below - Maximum 64 characters
- Allowed characters: letters (a-z, A-Z), numbers (0-9), and dashes (-)
Endpoints
| Endpoint | Method | Path | Description |
|---|---|---|---|
| Get Proxy Info | POST | /azureekm/[path-prefix]/info | Health check and proxy details |
| Get Key Metadata | POST | /azureekm/[path-prefix]/{key-name}/metadata | Retrieve key type, size, and supported operations |
| Wrap Key | POST | /azureekm/[path-prefix]/{key-name}/wrapkey | Wrap (encrypt) a DEK with a KEK |
| Unwrap Key | POST | /azureekm/[path-prefix]/{key-name}/unwrapkey | Unwrap (decrypt) a previously wrapped DEK |
Supported algorithms
| Algorithm | Key Type | Description |
|---|---|---|
| A256KW | AES-256 | AES Key Wrap (RFC 3394) |
| A256KWP | AES-256 | AES Key Wrap with Padding (RFC 5649) |
| RSA-OAEP-256 | RSA | RSA-OAEP using SHA-256 and MGF1 |
| RSA-OAEP | RSA | RSA-OAEP using SHA-1 and MGF1 |
⚠️ Notice: For RSA operations, always use the private key reference as
{key-name}in all endpoints, including wrap operations. The KMS will automatically derive and use the associated public key for encryption (wrap) operations. Passing the public key ID might lead to errors.
Getting started
Azure Managed HSM Setup
You must have an Azure Managed HSM Pool already created and activated in your Azure subscription. Refer to the Azure Managed HSM documentation for setup instructions.
Once the configuration is done, you will need the root CA certificate that the Azure Managed HSM uses for client authentication. This certificate will be configured in Eviden KMS to validate incoming mTLS connections.
Let's save the root CA as mhsm-root-ca.pem - We will need it in the next step.
Eviden KMS setup
Follow the Eviden KMS installation guide to install the KMS server on your infrastructure. The KMS server typically uses the configuration file located at /etc/cosmian/kms.toml when installed manually with default parameters.
Alternatively, you can deploy a pre-configured Eviden Confidential VM like explained in this guide.. For confidential VMs, the KMS configuration file is located in the encrypted LUKS container at /var/lib/cosmian_vm/data/app.conf.
Environment variables can also be used for all the configurations below.
The following guide will consider running Eviden KMS on confidential VM in non-FIPS mode.
mTLS Configuration
Configure mutual TLS authentication to accept connections from Azure Managed HSM by adding of editing to following lines in your configuration file: For detailed information about TLS client certificate authentication, see the TLS Client Certificate configuration guide.
[tls]
# Your server certificate and private key (PKCS#12 format)
tls_p12_file = "/etc/cosmian/server-cert.p12"
tls_p12_password = "your-secure-password"
# The certificate downloaded in the previous section
# This validates the client certificate presented by Azure MHSM
clients_ca_cert_file = "/etc/cosmian/mhsm-root-ca.pem"
Note : If you have a server's key and certificate files, you can convert them to PKCS#12 format using openssl:
openssl pkcs12 -export \
-in server.crt \
-inkey server.key \
-out server-cert.p12 \
-name "cosmian-kms-server" \
-passout pass:your-secure-password
Azure EKM Configuration
[azure_ekm_config]
# Enable Azure EKM endpoints
azure_ekm_enable = true
# Optional: Path prefix for multi-tenant isolation (max 64 chars: a-z, A-Z, 0-9, /, -)
azure_ekm_path_prefix = "cosmian0"
# The fields below will be reported in the /info endpoint, edit according to your needs
azure_ekm_proxy_vendor = "Eviden"
azure_ekm_proxy_name = "EKM Proxy Service v0.1-preview"
azure_ekm_ekm_vendor = "Eviden"
azure_ekm_ekm_product = "Eviden KMS"
# WARNING: Only set to true for testing! Never in production.
azure_ekm_disable_client_auth = false
Configuration Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
azure_ekm_enable | boolean | false | Enable/disable Azure EKM API endpoints. |
azure_ekm_path_prefix | string | none | Optional path prefix for routing and multi-tenant isolation. Max 64 chars: a-z, A-Z, 0-9, /, -. Example: "cosmian0", "customer-a/prod" |
azure_ekm_proxy_vendor | string | "Eviden" | Proxy vendor name reported in /info endpoint. |
azure_ekm_proxy_name | string | "EKM Proxy Service" | Proxy name and version reported in /info endpoint. Auto-inserts the KMS package version by default. |
azure_ekm_ekm_vendor | string | "Eviden" | EKMS vendor name reported in /info endpoint. |
azure_ekm_ekm_product | string | "Eviden KMS v{CARGO_PKG_VERSION}" | EKMS product name and version reported in /info endpoint. |
azure_ekm_disable_client_auth | boolean | false | ⚠️ Bypasses mTLS authentication. Only use for testing. |
Grant the Managed HSM identity access rights on the KMS
When Azure Managed HSM connects to the EKM proxy over mTLS, Eviden KMS authenticates it as a regular KMIP user, using the Subject CN of the client certificate as the username (see TLS Client Certificate configuration and the Authentication guide). This identity is generally of the form <hsm-name>.managedhsmclient.azure.net — check your own Managed HSM client certificate to confirm its exact Subject CN.
Because the external key is owned by whichever KMS user created it, you must explicitly grant this Managed HSM identity the rights to read and use that key, using ckms access-rights grant:
ckms access-rights grant <hsm-name>.managedhsmclient.azure.net -i <kms-key-uid> get get_attributes encrypt decrypt
Without this step, Azure's key registration call (see below) fails with a KeyNotFound-type error, because the KMS rejects the Managed HSM identity's request for an object it does not own and has not been granted access to.
Connect Azure Managed HSM to the EKM proxy
The following az keyvault ekm-connection commands configure the Managed HSM side of the connection to your Eviden KMS.
First, create the EKM connection on the Managed HSM, pointing it at your Eviden KMS:
az keyvault ekm-connection create \
--hsm-name <hsm-name> \
--host <kms-fqdn>:443 \
--path-prefix /azureekm/<azure_ekm_path_prefix> \
--server-ca-certificate <path-to-kms-tls-ca-or-server-cert.pem>
⚠️ Port 443 is required. The
--hostargument's own help text states: "EKM proxy host (FQDN or FQDN:port). If port is omitted, 443 is assumed." In practice, the Managed HSM EKM proxy calls have been observed to require port 443 — make sure your Eviden KMS is reachable on port 443 (in addition to any other port you use for KMIP/administrative access), even if[http] portin your KMS configuration is set to a different value.
--path-prefixmust matchazure_ekm_path_prefix. If you configuredazure_ekm_path_prefix = "cosmian0"on the KMS side, the Azure-side--path-prefixmust be the corresponding path (e.g./azureekm/cosmian0). A mismatch here causes requests to fail to route, without necessarily producing an obvious error on the Azure side.
Verify the connection:
az keyvault ekm-connection check --hsm-name <hsm-name>
A successful check returns the /info payload reported by the KMS (apiVersion, proxyVendor, proxyName, ekmVendor, ekmProduct).
Register the external key and grant Azure RBAC
Register the KMS key as an external Managed HSM key, referencing its KMS UID:
az keyvault key create \
--hsm-name <hsm-name> \
--name <azure-key-name> \
--external-key-id <kms-key-uid>
The consuming Azure service (for example, a Storage account's managed identity) then needs the Managed HSM Crypto Service Encryption User role (built-in Managed HSM local RBAC role, which grants the keys/wrap, keys/unwrap, and keys/read data actions) on that key:
az keyvault role assignment create \
--hsm-name <hsm-name> \
--role "Managed HSM Crypto Service Encryption User" \
--assignee <consuming-service-principal-id> \
--scope /keys/<azure-key-name>
Testing the integration
For testing purposes or for debugging, you can temporarily disable client authentication by commenting out the following configuration fields:
[tls]
# Comment this field to disable client auth and allow incoming requests from anyone
# clients_ca_cert_file = "/etc/cosmian/mhsm-root-ca.pem"
[azure_ekm_config]
# Set to true to bypass mTLS for local testing only — NEVER use in production
azure_ekm_disable_client_auth = true
Restart the KMS server:
sudo systemctl restart cosmian-kms
Test the /info endpoint:
curl -X POST "https://ekm.yourdomain.com/azureekm/cosmian0/info?api-version=0.1-preview" \
-H "Content-Type: application/json" \
-d '{
"request_context": {
"request_id": "test-request-123",
"correlation_id": "test-correlation-456",
"pool_name": "test-pool"
}
}'
Expected response (if you used the config above):
{
"api_version": "0.1-preview",
"proxy_vendor": "Eviden",
"proxy_name": "EKM Proxy Service v=0.1-preview",
"ekm_vendor": "Eviden",
"ekm_product": "Eviden KMS v5.15.0"
}
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
az keyvault ekm-connection create succeeds, but Azure later fails to reach the proxy | KMS not reachable on port 443 | Expose the KMS on port 443, in addition to any other configured port — see the port 443 note above. |
| Requests never reach the KMS logs, or Azure reports a connectivity/routing error | --path-prefix used in az keyvault ekm-connection create does not match azure_ekm_path_prefix in the KMS configuration | Make both values match exactly, including the /azureekm/ prefix. |
az keyvault key create --external-key-id ... fails with a KeyNotFound-type error | The Managed HSM's mTLS identity has not been granted access rights on the KMS key | Grant get, get_attributes, encrypt, decrypt to the Managed HSM identity with ckms access-rights grant — see above. |
| Wrap/unwrap fails during a CMK-enabling operation (for example Azure Storage CMK) with a generic error on the Azure side | The client sent a wrapping algorithm not currently listed under Supported algorithms | Check the KMS server logs for the exact alg value received, and confirm it is one of the algorithms in the table above. |
Microsoft Double Key Encryption (DKE)
Microsoft Double Key Encryption (DKE) is a feature of Microsoft 365 that allows you to protect your most sensitive data by encrypting data on the client computer before sending it to Microsoft servers. One of the keys used to encrypt remains under your control and makes the data unreadable by Microsoft. This key is kept inside your instance of Eviden KMS which exposes the required API to integrate with Microsoft DKE.
See How it works for details on the cryptographic process.
Microsoft Prerequisites
The DKE feature is currently only available for the Office Windows clients. In addition, to use Microsoft Double Key Encryption (DKE) you must have a Microsoft 365 Business Premium license and must have access to the Microsoft Purview compliance portal.
How it works
Once DKE is configured, the whole process consists in assigning a specific sensitivity label to a document. The label will indicate that the document is encrypted and that the key to decrypt it is stored in your Eviden KMS.
Please check the dedicated Microsoft documentation for a complete overview of the feature.
From a cryptographic standpoint, the feature works as follows:
Before saving an encrypted document, the Office client will:
- Generate an ephemeral 128-bit AES key and use it to encrypt the document
- Call the Eviden KMS to get your 2048-bit RSA public key (the Office client will cache the key for 24 hours)
- Use that key to wrap the AES key using the PKCS#11 CKM_RSA_PKCS_OAEP (NIST 800 56B Rev2) algorithm; the hashing algorithm is set to SHA-256 (see the list of supported algorithms for details)
- Send the wrapped AES key and the encrypted document to Microsoft servers, where Azure RMS will also wrap the wrapped AES key with their own key (hence the "double key" acronym)
Retrieving an encrypted document works as follows, the Office client will:
- Request Azure RMS to perform the first unwrapping using their key, to recover the wrapped AES key
- Download the encrypted document and the wrapped AES key
- Call your Eviden KMS to unwrap the AES key using your private RSA key. Please note that the private RSA key never leaves the Eviden KMS.
- Decrypt the document using the recovered AES key and display it.
Note: The Eviden KMS implementation of the PKCS#11 CKM_RSA_PKCS_OAEP algorithm is FIPS compliant. The DKE API is therefore available on the Eviden server running in FIPS mode.
Configuring the Eviden KMS server
The Eviden KMS server needs to be started with the --ms-dke-service-url <MS_DKE_SERVICE_URL> option.
The <MS_DKE_SERVICE_URL>should contain the external URL of this server as configured in Azure App Registrations
for the DKE Service
The URL should be something like https://kms.my_domain.com/ms_dke
Alternatively, you can set the KMS_MS_DKE_SERVICE_URL environment variable to the same value, or set the
corresponding entry in the server TOML configuration file.
The Office client does not send any authentication information when calling the Eviden KMS. Firewalling the Eviden KMS server to only accept requests from valid Office clients is critical.
It is possible to confidentially run the Eviden KMS server in the cloud inside an Eviden VM. However, due to the lack of authentication, and thus the need to firewall the server, one should make sure to use OS-level firewalling and not rely on the cloud provider's firewalling capabilities, particularly if running on Azure.
Create an RSA key with tag dke_key
Using the KMS CLI, create a 2048-bit RSA key with the tag dke_key:
ckms rsa keys create --tag dke_key --size_in_bits 2048
The tag can be changed to any value, but it must be used in the URL of the sensitivity label in the Microsoft Purview compliance portal. See Create a sensitivity label for encryption for details.
Rotate the DKE key
If later on you need to rotate the DKE key, you can use the KMS CLI to create a new key with a new tag. You must then create a new sensitivity label where the Double Key Encryption URL ends with the new tag value. See Create a sensitivity label for encryption for details.
Users should now select the new label when creating new documents. As long as the old key is available in the Eviden KMS, users will still be able to open documents encrypted with the old key.
Configuring Microsoft DKE in Purview
Please follow the main documentation provided by Microsoft. The following paragraphs add details and tips to the process.
Activating the protection service from Azure Information Protection
The protection service must be activated in order to use DKE. If not activated, "Group and Sites" will not be available in the scopes of the sensitivity label.
Run PowerShell as Admin
Install-Module -Name AIPService
In case of troubles with the execution policy, try
powershell -ExecutionPolicy ByPass
Get the status of the AIP service
Import-Module AIPService
Get-AIPService
You may have to connect to it first
Connect-AipService
If it is disabled, enable it
Enable-AipService
More options for phased deployments here.
Microsoft Entra configuration for encrypted content
Check if there is anything to configure.
Activate sensitivity labels for MS 365 groups
Sensitivity labels must be activated for MS 365 groups which are also called unified groups. The main documentation on configuring sensitivity labels is available here.
The objective is to set the EnableMIPLabels parameter to True at the Entra ID Directory level (which is set
to False by default), using Group.Unified template.
The
EnableMIPLabelsflag indicates whether sensitivity labels published in Microsoft Purview compliance portal can be applied to Microsoft 365 groups. For more information, see Assign Sensitivity Labels for Microsoft 365 groups.
To verify the current value of the EnableMIPLabels parameter, run the following command:
$Setting = Get-AzureADDirectorySetting | ? { $_.DisplayName -eq "Group.Unified"}
&Setting.Values
See this doc and Enable sensitivity label support in PowerShell which will probably require configuring groups first.
De-activate co-authoring in Microsoft Purview
Do NOT click the box on this page, doing so will prevent the use of DKE in Sensitivity Labels.
If you need to deactivate co-authoring, you can do so by running the following commands:
Install-Module -Name PSWSMan # if not already installed
Install-WSMan
Install-Module -Name ExchangeOnlineManagement
Import-Module ExchangeOnlineManagement
Connect-IPPSSession -UserPrincipalName you_admin_user@your_domain.com
Set-PolicyConfig -EnableLabelCoauth:$false
Create a sensitivity label for encryption
Navigate to Purview then Solutions > Information protection > Labels
Follow these instructions
to create the label.
Select Use Double Key Encryption on the encryption configuration screen and make sure
you do not activate co-authoring.
The URL must be set to a form similar to https://dke.acme.com/ms_dke/dke_key where
dke.acme.comis the address of the Eviden KMS server. A valid certificate must be installed on the server.ms_dkeis the root of REST path for the DKE services.dke_keyis the tag set for the RSA key pair to use for this label.

Activating the label (scope) for meetings does not seem to work.

Windows CNG Key Storage Provider (KSP)
Microsoft Intune integration — The Cosmian KMS CNG KSP integrates natively with Microsoft Intune SCEP and PKCS certificate profiles. When Intune provisions a device certificate, the private key is created and permanently stored in Cosmian KMS — never on the endpoint. See the Intune integration section for setup details.
Intune + CNG KSP architecture
sequenceDiagram
participant Admin as IT Administrator
participant Intune as Microsoft Intune<br/>(Cloud UEM)
participant Endpoint as Windows Endpoint<br/>(Intune-managed)
participant KSP as cosmian_cng.dll<br/>(CNG KSP)
participant KMS as Cosmian KMS<br/>(KMIP 2.1)
participant SCEP as SCEP / PKCS<br/>Certificate Authority
Admin->>Intune: 1. Create SCEP certificate profile<br/>KSP = "Cosmian KMS Key Storage Provider"
Intune->>Endpoint: 2. Push certificate profile
Endpoint->>KSP: 3. NCryptCreatePersistedKey()
KSP->>KMS: 4. KMIP CreateKeyPair<br/>(private key stays in KMS)
KMS-->>KSP: 5. Public key + key UUID
KSP-->>Endpoint: 6. Key handle (public key blob)
Endpoint->>SCEP: 7. Submit CSR<br/>(public key only)
SCEP-->>Endpoint: 8. Signed certificate
Note over Endpoint,KMS: All subsequent Sign / Decrypt operations<br/>are forwarded to Cosmian KMS via the KSP
Endpoint->>KSP: 9. NCryptSignHash() (e.g. TLS handshake)
KSP->>KMS: 10. KMIP Sign
KMS-->>KSP: 11. Signature
KSP-->>Endpoint: 12. Signature bytes
What is it?
Cosmian KMS provides a Windows CNG Key Storage Provider (KSP) DLL —
cosmian_cng.dll — that stores private keys inside Cosmian KMS rather
than the local Windows machine store.
A Key Storage Provider is a pluggable module defined by the Windows
Cryptography API: Next Generation (CNG) framework (introduced in Windows
Vista / Server 2008). CNG replaces the older CAPI (CryptoAPI). Any application
that calls the standard NCrypt* family of functions — including the Windows
certificate enrollment engine, Schannel (TLS), and Code Signing — automatically
uses whichever KSP is associated with a given key, with no application changes
required. By deploying cosmian_cng.dll, all private key material is
kept inside Cosmian KMS: it never exists on the device disk.
Why use it?
| Need | How the KSP addresses it |
|---|---|
| Private-key protection | Keys are generated and stored exclusively inside Cosmian KMS — never on the endpoint disk or in the Windows registry. |
| FIPS 140-3 compliance | Cosmian KMS is FIPS 140-3 validated. All cryptographic operations (sign, decrypt, key generation) are executed by the KMS, not by Windows. |
| Centralised audit trail | Every sign / decrypt operation is logged in the KMS with user identity, timestamp, and key identifier. |
| Key revocation | Revoking a key in the KMS immediately blocks all devices using it, without requiring an MDM policy push. |
| Zero-touch provisioning | Works natively with Microsoft Intune SCEP and PKCS certificate profiles — no custom enrollment agent is needed. |
| Export prevention | Export policy is disabled by default (NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG is off), so private keys cannot be extracted from the device. |
Who should use it?
- Enterprise IT / Security teams deploying Microsoft Intune device certificates where device private keys must be hardware-protected or centrally managed.
- PKI administrators who need a hardware-security-module (HSM)-equivalent experience without deploying a physical HSM on every endpoint.
- Compliance officers who need full audit logs of every private key usage on corporate endpoints.
- Windows developers integrating with any NCrypt-based API (Schannel, Code Signing, S/MIME, BitLocker recovery) who want keys protected by a remote KMS.
When to use it?
Use the CNG KSP when:
- You are enrolling device certificates through Microsoft Intune SCEP or PKCS profiles and you want the private key to remain inside Cosmian KMS rather than in the Windows software KSP or TPM.
- You need to remotely wipe a key (e.g. lost device): destroy the key in the KMS and all signing / decryption operations on that device fail immediately.
- Your organisation is subject to regulations (FIPS 140-3, Common Criteria, eIDAS, NIS2) that mandate private key custody inside a certified key store.
- You want a single, centralised, KMIP 2.1-compliant inventory of all device keys with metadata and access-control policies.
Do not use the CNG KSP for keys that must be available offline (e.g. full-disk encryption unlock keys), because operations require a live HTTPS connection to the KMS.
How it works
CNG plug-in mechanism
Windows CNG defines the NCRYPT_KEY_STORAGE_FUNCTION_TABLE interface: a struct
of 30 function pointers that Windows calls for every key operation. A KSP DLL
exports a single entry point:
SECURITY_STATUS GetKeyStorageInterface(
LPCWSTR pszProviderName,
NCRYPT_KEY_STORAGE_FUNCTION_TABLE **ppFunctionTable,
DWORD dwFlags
);
cosmian_cng.dll implements this interface entirely in Rust. When
Windows loads the DLL, it calls GetKeyStorageInterface to obtain the function
table, and from that point on every NCrypt* call is handled by the
corresponding Rust function.
Request flow
sequenceDiagram
participant App as Windows Application<br/>(Intune SCEP, MMC, certutil)
participant DLL as cosmian_cng.dll
participant KMS as Cosmian KMS<br/>(HTTPS / KMIP 2.1)
App->>DLL: NCrypt* call<br/>(OpenStorageProvider, SignHash, …)
Note over DLL: 1. Validate handle (magic check)<br/>2. Translate NCrypt params → KMIP request<br/>3. Block on shared Tokio runtime
DLL->>KMS: KMIP operation<br/>(CreateKeyPair, Sign, Decrypt, …)
KMS-->>DLL: KMIP response
Note over DLL: 4. Translate KMS response → NCrypt buffer<br/>5. Return SECURITY_STATUS
DLL-->>App: SECURITY_STATUS + output buffer
Private keys never leave the KMS: only the public key blob
(BCRYPT_RSAKEY_BLOB or BCRYPT_ECCKEY_BLOB) is serialised and returned to
Windows for certificate construction.
Provider and key context objects
| Windows concept | Rust type | What it holds |
|---|---|---|
NCRYPT_PROV_HANDLE | CngProviderCtx (heap box → raw usize) | Shared Arc<KmsClient>, provider config path |
NCRYPT_KEY_HANDLE | CngKeyCtx (heap box → raw usize) | Key state (Persisted or Pending), Arc<KmsClient> |
Both types carry a magic number (0xC05_1A_AC) that is validated on every
handle dereference — a stale or forged handle returns NTE_INVALID_HANDLE
instead of causing undefined behaviour.
Key lifecycle
flowchart LR
subgraph Key Creation
A[CreatePersistedKey] -->|allocates PendingCreation context| B[SetKeyProperty]
B --> C[FinalizeKey]
C -->|calls KMS CreateKeyPair,<br/>tags key with cng-ksp::name| D["Key exists in KMS<br/>(Persisted state)"]
end
flowchart LR
subgraph Key Lookup
E[OpenKey] -->|look up KMS UUID<br/>by tag cng-ksp::name| F[allocate CngKeyCtx]
end
flowchart LR
subgraph Key Operations
G[SignHash] -->|digested_data = pre-hashed input| H[KMS Sign]
I[Decrypt] --> J[KMS Decrypt]
K[ExportKey] -->|SPKI DER → BCRYPT blob| L[KMS export public key only]
M[DeleteKey] -->|revoke + destroy both key UUIDs| N[KMS Destroy]
end
Key naming and tagging
Each key is tagged in the KMS with two vendor tags (namespace Cosmian):
| Tag | Purpose |
|---|---|
cng-ksp | Marks the object as managed by this KSP |
cng-ksp::<name> | Allows lookup by the CNG key name string |
Authentication
The DLL reads ckms.toml using the same search order as the ckms CLI:
- Path in the
CKMS_CONFenvironment variable. ckms.tomlin the same directory ascosmian_cng.dll.%APPDATA%\.cosmian\ckms.toml.
The configuration file supports bearer-token OAuth 2.0, mTLS (PKCS#12 client certificate), or unauthenticated (for local dev/test only).
SECURITY_STATUS error mapping
| KSP error | SECURITY_STATUS returned |
|---|---|
| Handle invalid / null | NTE_INVALID_HANDLE (0x80090026) |
| Key not found in KMS | NTE_BAD_KEYSET (0x80090016) |
| Algorithm not in supported list | NTE_BAD_ALGID (0x80090008) |
| Export requested on non-exportable key | NTE_PERM (0x80090010) |
| Output buffer too small | NTE_BUFFER_TOO_SMALL (0x80090028) |
| Any KMS REST error | NTE_FAIL (0x8009002A) |
Architecture
flowchart LR
App["Windows Application<br/>(Intune SCEP, MMC, certutil)"] -->|NCrypt API calls| DLL["cosmian_cng.dll<br/><br/>NCRYPT_KEY_STORAGE_FUNCTION_TABLE<br/>GetKeyStorageInterface()"]
DLL -->|"CreateKeyPair / Sign / Decrypt<br/>Locate / Destroy"| KMS["Cosmian KMS<br/>(REST / KMIP 2.1)"]
style DLL fill:#f5f5f5,stroke:#333
style KMS fill:#e8f4e8,stroke:#2d7d2d
Private keys never touch the local machine. Only public key blobs are returned to Windows.
Supported algorithms
| Algorithm | Key sizes / curves | Operations |
|---|---|---|
| RSA | 2048, 3072, 4096 bits | Sign, Decrypt |
| ECDSA P-256 | NIST P-256 | Sign |
| ECDSA P-384 | NIST P-384 | Sign |
| ECDSA P-521 | NIST P-521 | Sign |
| ECDH P-256/384/521 | NIST curves | Key Agreement |
Installation
1. Install the Cosmian KMS CLI
The cosmian_cng.dll is bundled inside the Cosmian KMS CLI installer
alongside ckms.exe. Download and run the installer for your platform:
# Download the CLI installer (adjust the version number as needed)
Invoke-WebRequest `
-Uri "https://package.cosmian.com/kms/5.25.0/windows/x86_64/non-fips/static-openssl/cosmian-kms-cli-non-fips-static-openssl_5.25.0_x86_64.exe" `
-OutFile "$env:TEMP\cosmian-kms-cli.exe"
# Run the installer (accepts the default installation directory)
Start-Process -FilePath "$env:TEMP\cosmian-kms-cli.exe" -ArgumentList "/S" -Wait
The installer places both files in the default installation directory:
C:\Users\<username>\AppData\Local\Cosmian KMS CLI\ckms.exe
C:\Users\<username>\AppData\Local\Cosmian KMS CLI\cosmian_cng.dll
Ensure the installation directory is on your PATH (the installer does
this automatically):
$env:PATH += ";$env:LOCALAPPDATA\Cosmian KMS CLI"
2. Configure the KMS connection
Run the interactive configuration wizard to create ckms.toml:
ckms configure
The wizard prompts for the KMS server URL and authentication method (none,
bearer token, PEM client certificate, or PKCS#12 client certificate). It writes
the configuration to %APPDATA%\.cosmian\ckms.toml.
3. Verify the DLL
Before registering the KSP, confirm that the DLL loads correctly and can reach the KMS server:
ckms cng verify --dll "$env:LOCALAPPDATA\Cosmian KMS CLI\cosmian_cng.dll"
Expected output (with a running KMS):
=== Cosmian CNG KSP Verification ===
Loading DLL: C:\Users\<user>\AppData\Local\Cosmian KMS CLI\cosmian_cng.dll
[OK] OpenProvider
── RSA key pair + sign + export + lookup ──
[OK] RSA key pair + sign + export + lookup
...
─────────────────────────────────────────
All 15 verification step(s) PASSED.
If any step shows [FAIL] with NTE_FAIL (0x8009002A), the DLL cannot reach
the KMS server — check ckms.toml and network connectivity before proceeding.
4. Register the KSP (requires Administrator)
# From an elevated PowerShell prompt:
ckms cng register --dll "$env:LOCALAPPDATA\Cosmian KMS CLI\cosmian_cng.dll"
This performs the following steps:
-
Copies
cosmian_cng.dllto%SystemRoot%\System32(CNG resolves provider DLLs from that directory) -
Calls
BCryptRegisterProviderto create the proper registry structure:HKLM\SYSTEM\CurrentControlSet\Control\Cryptography\Providers\ Cosmian KMS Key Storage Provider\ UM\ Image REG_SZ "cosmian_cng.dll" 00010001\ (Default) REG_SZ "CRYPT_KEY_STORAGE_INTERFACE" Functions REG_MULTI_SZ "KEY_STORAGE" -
Calls
BCryptAddContextFunctionProviderto make the provider discoverable byNCryptOpenStorageProviderandcertutil -csplist
5. Verify registration
ckms cng status
# Expected: Cosmian KMS CNG KSP: REGISTERED
# Also verify Windows sees the provider:
certutil -csplist | Select-String "Cosmian"
# Expected output includes: "Cosmian KMS Key Storage Provider"
Using the KSP
Create a key pair via NCrypt API
The KSP is automatically available to any Windows application that calls
NCryptOpenStorageProvider with the provider name
"Cosmian KMS Key Storage Provider".
NCRYPT_PROV_HANDLE hProv;
NCryptOpenStorageProvider(
&hProv,
L"Cosmian KMS Key Storage Provider",
0
);
NCRYPT_KEY_HANDLE hKey;
NCryptCreatePersistedKey(hProv, &hKey, BCRYPT_RSA_ALGORITHM, L"my-key", 0, 0);
NCryptSetProperty(hKey, NCRYPT_LENGTH_PROPERTY, (PBYTE)&keyLength, sizeof(DWORD), 0);
NCryptFinalizeKey(hKey, 0);
// The private key is now stored in Cosmian KMS
// FinalizeKey returns only after the KMS confirms creation
Intune SCEP device certificate
Microsoft Intune uses the Windows CNG CSR pipeline. Once the KSP is registered, configure the Intune SCEP profile to use the Cosmian KMS Key Storage Provider as the key storage location. The private key backing the device certificate will be created and permanently stored in Cosmian KMS.
List all CNG KSP keys in the KMS
ckms cng list-keys
Unregister the KSP
# Elevated PowerShell:
ckms cng unregister
Logging
Log output is written to cosmian_cng.log in the same directory as the
DLL by default — no additional configuration is required. If the DLL directory
is not writable, the log file is created in %APPDATA%\.cosmian\cosmian_cng.log
instead. Logging to a file always happens without any configuration.
Set the COSMIAN_CNG_KSP_LOGGING_LEVEL environment variable to control
verbosity: trace, debug, info (default), warn, or error.
Key naming and tag convention
Each key created through the KSP is tagged in the KMS with:
cng-ksp— identifies all KSP-managed keys.cng-ksp::<key_name>— identifies the key by its CNG name (the string passed toNCryptCreatePersistedKey/NCryptOpenKey).
Use ckms cng list-keys or the standard ckms locate command to find keys:
ckms locate --tag "cng-ksp::my-key"
Security considerations
- Private keys are never stored locally; they exist only in Cosmian KMS.
- All key operations require an authenticated connection to the KMS.
- The
NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAGis off by default; private keys cannot be exported in plaintext. - Use mTLS or bearer-token authentication in
ckms.tomlfor production deployments. - Run
ckms cng registeras Administrator. The DLL path stored in the registry is read by the Windows LSASS process — only trusted, signed DLLs should be registered. - Consider restricting read access to
ckms.tomlso that unprivileged users cannot extract the KMS server URL or client certificate.
Microsoft Intune integration
Microsoft Intune is Microsoft's cloud-based Unified Endpoint Management (UEM) service. It lets IT administrators manage devices (Windows, macOS, iOS, Android) and enforce security policies — including deploying certificates — without on-premises infrastructure. When Intune provisions a certificate on a Windows endpoint, the private key is generated locally via a Key Storage Provider. By default Windows uses its built-in software KSP, which stores keys in the registry.
With the Cosmian KMS CNG KSP registered on the device, Intune can be configured to use it instead: the private key is created and permanently stored in Cosmian KMS rather than on the device. This gives the organisation centralised custody, FIPS 140-3 compliance, real-time revocation, and a full audit trail — all without any change to the Intune enrollment workflow itself.
SCEP certificate profile
-
In the Microsoft Intune admin center, create a SCEP certificate profile for Windows 10/11.
-
Set Key storage provider (KSP) to "Enroll to Custom KSP, otherwise fail" and enter the provider name exactly as:
Cosmian KMS Key Storage Provider -
Ensure the
ckms.tomlconfiguration file and the DLL are deployed to managed endpoints via an Intune Win32 app or PowerShell script before the certificate profile is applied. -
The Intune SCEP agent will call
NCryptCreatePersistedKeyon the Cosmian KSP, then send the resulting CSR (public key only) to the SCEP server. The private key never leaves Cosmian KMS.
PKCS certificate profile
Set Key storage provider (KSP) to "Enroll to Custom KSP, otherwise fail" and enter the same provider name. The Intune PKCS connector will use the Cosmian KSP to generate the key pair on the device.
Imported PFX certificate (PFXImport PowerShell module)
For importing existing PFX certificates via the IntunePfxImport PowerShell module, follow these steps on the Certificate Connector server:
-
Ensure the KMS server is running and reachable (e.g.
http://localhost:9998). -
Register the KSP (see Installation above):
ckms cng register --dll "$env:LOCALAPPDATA\Cosmian KMS CLI\cosmian_cng.dll" -
Verify Windows discovers the provider:
certutil -csplist | Select-String "Cosmian" # Expected: "Cosmian KMS Key Storage Provider" -
Import the IntunePfxImport module (from the IntunePfxImportUtilities release folder):
Import-Module .\IntunePfxImport.psd1 -
Create the encryption key pair in Cosmian KMS:
Add-IntuneKspKey ` -ProviderName "Cosmian KMS Key Storage Provider" ` -KeyName "PFXEncryptionKey" ` -MakeExportableThis calls
NCryptCreatePersistedKey→NCryptSetProperty(Export Policy)→NCryptFinalizeKeyon the Cosmian KSP. The RSA key pair is created and stored exclusively in Cosmian KMS. The-MakeExportableflag sets theNCRYPT_ALLOW_EXPORT_FLAGso the public key can be exported for use on other connector servers. -
Export the public key (if multiple connector servers share the key):
Export-IntunePublicKey ` -ProviderName "Cosmian KMS Key Storage Provider" ` -KeyName "PFXEncryptionKey" ` -FilePath "C:\temp\PFXEncryptionKey.pfx" -
Import PFX certificates to Intune using the key:
$userPFXObject = New-IntuneUserPfxCertificate ` -PathToPfxFile "C:\temp\userA.pfx" ` $SecureFilePassword ` "userA@contoso.com" ` "Cosmian KMS Key Storage Provider" ` "PFXEncryptionKey" ` "smimeEncryption" Import-IntuneUserPfxCertificate -CertificateList $userPFXObject
Remote key revocation for lost devices
When a device is lost or decommissioned:
# From the KMS administrator workstation:
ckms locate --tag "cng-ksp::intune-device-<serial>"
ckms revoke --id <uuid> "Device decommissioned"
ckms destroy --id <uuid>
Once the key is destroyed in the KMS, any subsequent sign or decrypt attempt
from the device returns NTE_FAIL, effectively revoking the private key without
requiring a certificate revocation list (CRL) propagation delay.
Integration testing
The CNG KSP is tested at three levels — all runnable without Azure credentials or an Intune tenant.
Prerequisites
| Requirement | Why |
|---|---|
| Windows 10/11 or Server 2019+ | The DLL uses the Windows CNG API (NCrypt*), which is Windows-only. |
| Rust toolchain (MSVC target) | cargo build produces the DLL, server binary, and verification tool. |
| Administrator privileges | Required to write the KSP registry key under HKLM. |
vcpkg with openssl_x64-windows-static | Set OPENSSL_DIR or VCPKG_INSTALLATION_ROOT. |
No Azure account, Intune license, or SCEP infrastructure is needed — all tests run against a local Cosmian KMS server with a SQLite backend.
Test layers
| Layer | What it tests | Runner | Location |
|---|---|---|---|
| Rust lib tests | Backend functions (backend::create_rsa_key_pair, sign_hash, list_cng_keys, …) via an in-process KMS | cargo test --lib -p cosmian_cng | crate/clients/cng/src/tests.rs |
| DLL surface tests | Loads cosmian_cng.dll at runtime, calls GetKeyStorageInterface, exercises every NCrypt* function pointer against a live KMS | ckms cng verify --dll <path> | crate/clients/clap/src/actions/cng_verify.rs |
| CLI commands | ckms cng register, status, list-keys, unregister | PowerShell assertions | .mise/scripts/windows/test_cng_ksp.ps1 |
| Intune PFX Import | Add-IntuneKspKey + Export-IntunePublicKey via the IntunePfxImportUtilities module against the registered KSP | PowerShell (requires Admin + module) | .mise/scripts/windows/test_cng_ksp.ps1 |
Running the full test suite
From an elevated PowerShell prompt at the repository root:
.\.github\scripts\windows\test_cng_ksp.ps1
The script performs the following steps:
sequenceDiagram
participant PS as PowerShell script
participant Build as Cargo build
participant KMS as Local KMS server
participant Reg as Windows Registry
participant Verify as cng_verify.exe
participant Tests as cargo test
participant Intune as IntunePfxImport module
PS->>Build: 1. Build KMS server, cosmian_cng.dll, cng_verify, ckms
Build-->>PS: Binaries ready
PS->>KMS: 2. Start KMS (SQLite, port 9998)
PS->>PS: 3. Write ckms.toml (server_url = localhost:9998)
PS->>KMS: 4. GET /version (smoke-test)
KMS-->>PS: 200 OK
PS->>Reg: 5. ckms cng register (write HKLM KSP key)
Reg-->>PS: Registry key created
PS->>Verify: 6. Run cng_verify.exe (NCrypt surface tests)
Verify->>KMS: NCrypt* calls via cosmian_cng.dll
KMS-->>Verify: Key operations
Verify-->>PS: All tests passed
PS->>Tests: 7. cargo test --lib (in-process backend tests)
Tests->>KMS: KMIP operations
Tests-->>PS: Tests passed
PS->>KMS: 8. ckms cng list-keys / ckms cng status
KMS-->>PS: Key list and status
PS->>Intune: 8b. Add-IntuneKspKey + Export-IntunePublicKey
Intune->>KMS: NCryptCreatePersistedKey → NCryptFinalizeKey → NCryptExportKey
KMS-->>Intune: Key created + public blob exported
Intune-->>PS: Intune PFX workflow passed
PS->>PS: 9. Parse KMS logs for ERROR / PANIC
PS->>Reg: 10. ckms cng unregister (remove HKLM KSP key)
PS->>KMS: Stop KMS server
Test coverage
The cng_verify tool exercises the following NCrypt operations against a live KMS:
| Test | Operations exercised |
|---|---|
| RSA key pair + sign + export + lookup | CreatePersistedKey → SetKeyProperty → FinalizeKey → ExportKey → OpenKey → SignHash (PKCS1v15) → DeleteKey |
| RSA encrypt / decrypt (OAEP) | Encrypt → Decrypt (round-trip validation) |
| RSA-PSS sign | SignHash with PSS padding + salt |
| RSA signature verify | SignHash → VerifySignature (valid + invalid hash) |
| EC P-256 key pair + sign + export | CreatePersistedKey → FinalizeKey → ExportKey → SignHash (ECDSA) → DeleteKey |
| ECDSA signature verify (P-256) | SignHash → VerifySignature |
| EC P-384 key pair + sign | CreatePersistedKey → FinalizeKey → ExportKey → SignHash (SHA-384) |
| EC P-521 key pair + export | CreatePersistedKey → FinalizeKey → ExportKey |
| DeleteKey + verify gone | DeleteKey → OpenKey (expect NTE_BAD_KEYSET) |
Environment variables
| Variable | Default | Purpose |
|---|---|---|
CKMS_CONF | <target_dir>/ckms.toml | Path to the KMS client configuration file |
OPENSSL_DIR | Auto-detected from vcpkg | OpenSSL static library directory |
VCPKG_INSTALLATION_ROOT | — | Fallback for OPENSSL_DIR |
CNG_TEST_RELEASE | 0 | Set to 1 to build and test in release mode |
RUST_LOG | cosmian_kms_server=info,cosmian_cng=debug | Log verbosity for KMS server and DLL |
COSMIAN_CNG_KSP_LOGGING_LEVEL | info | DLL-specific logging (trace/debug/info/warn/error) |
INTUNE_PFX_MODULE_PATH | — | Path to IntunePfxImport.psd1; enables the Intune PFX Import test step |
Testing the Intune enrollment flow
The automated tests above validate the CNG KSP DLL itself — the same code
path that Intune SCEP uses when it calls NCryptCreatePersistedKey and
NCryptSignHash. To test the full Intune → endpoint → KMS flow you need:
| Requirement | Purpose |
|---|---|
| Microsoft Intune tenant (Azure AD / Entra ID) | Manages the SCEP certificate profile |
| SCEP server (NDES or third-party) | Signs the CSR generated by the endpoint |
| Intune-enrolled Windows device | Receives the SCEP profile and triggers key creation |
| Cosmian KMS instance reachable from the device | Stores the private key |
This is typically validated manually or in a dedicated staging environment, not in CI.
Troubleshooting
| Problem | Likely cause | Solution |
|---|---|---|
NTE_FAIL on OpenKey or CreatePersistedKey | ckms.toml missing or KMS unreachable | Verify ckms.toml is present and server_url is reachable (curl https://<kms>/kmip/2_1). |
NTE_BAD_KEYSET on OpenKey | Key name not found in the KMS | Run ckms cng list-keys; verify the name and that the cng-ksp::<name> tag exists. |
NTE_PERM on ExportKey | Export policy disabled (by design) | Private key export is intentionally blocked. Use ExportKey only for public key blobs. |
NTE_BAD_ALGID | Algorithm string not recognised | Use RSA, ECDSA_P256, ECDSA_P384, ECDSA_P521, ECDH_P256, ECDH_P384, or ECDH_P521. |
RegCreateKeyExW returns 0x80070005 (Access Denied) | Not running as Administrator | Run ckms cng register from an elevated PowerShell prompt. |
KSP not listed in certutil -csplist | Registry key missing or CryptSvc cached old list | Re-run ckms cng register and restart the CryptSvc service (Restart-Service CryptSvc). |
NTE_INVALID_HANDLE | Stale handle or DLL unloaded mid-operation | Ensure the DLL is not forcibly unloaded during an active key operation. |
| Intune SCEP enrollment fails with "Custom KSP not found" | DLL not deployed before profile applies | Deploy the Win32 app containing the DLL and ckms.toml before the certificate profile, using an Intune assignment filter or dependency. |
| Log file not created | DLL directory not writable | Set COSMIAN_CNG_KSP_LOGGING_LEVEL and check stderr, or grant write access to the DLL directory. |
Glossary
| Term | Full name | Definition |
|---|---|---|
| BCRYPT | Base Cryptography API: Next Generation | The symmetric/hash/key-derivation half of the Windows CNG API (BCrypt* functions), as opposed to the asymmetric/key-storage half (NCrypt*). |
| BYOK | Bring Your Own Key | A cloud-provider feature that lets customers supply (and control) the encryption key used by a cloud service, rather than having the provider generate it. |
| CA | Certificate Authority | A trusted entity that issues and signs digital certificates, binding a public key to an identity. |
| CAPI | Cryptography API | The original Windows cryptographic subsystem (pre-Vista), replaced by CNG. Also written CryptoAPI. |
| CNG | Cryptography API: Next Generation | The Windows cryptographic framework introduced in Vista / Server 2008. It defines pluggable Key Storage Providers and Algorithm Providers via well-known function tables, replacing the older CAPI/CryptoAPI. |
| CRL | Certificate Revocation List | A signed list published by a CA of certificates that have been revoked before their expiry date. |
| CSR | Certificate Signing Request | A PKCS#10 message containing a public key and subject information, sent to a CA to obtain a signed certificate. |
| DLL | Dynamic-Link Library | A Windows shared library loaded at runtime, providing functions and data to calling processes without static linking. |
| ECDH | Elliptic-Curve Diffie–Hellman | A key-agreement protocol that allows two parties to establish a shared secret over an insecure channel using elliptic-curve arithmetic. |
| ECDSA | Elliptic Curve Digital Signature Algorithm | A digital signature scheme based on elliptic-curve cryptography, offering equivalent security to RSA with significantly smaller key sizes. |
| eIDAS | Electronic Identification, Authentication and Trust Services | EU regulation establishing a legal framework for electronic signatures, seals, timestamps, and authentication across EU member states. |
| FIPS 140-3 | Federal Information Processing Standard Publication 140-3 | A US government standard (NIST) specifying security requirements for cryptographic modules. Level 1–4 define increasing physical and logical security. |
| HKLM | HKEY_LOCAL_MACHINE | The Windows registry hive containing system-wide configuration settings that apply to all users on the machine. |
| HSM | Hardware Security Module | A tamper-resistant physical device that generates, stores, and protects cryptographic keys and performs cryptographic operations. |
| HTTPS | Hypertext Transfer Protocol Secure | HTTP layered over TLS, providing encrypted and authenticated communication between client and server. |
| KMS | Key Management System / Key Management Service | A centralised service that manages cryptographic keys throughout their lifecycle (creation, distribution, rotation, revocation, destruction). In this document, refers to Cosmian KMS. |
| KMIP | Key Management Interoperability Protocol | An OASIS standard (current version 2.1) defining a protocol for communication between clients and key management servers. |
| KSP | Key Storage Provider | A pluggable Windows CNG component (a DLL implementing NCRYPT_KEY_STORAGE_FUNCTION_TABLE) that stores private keys and performs asymmetric key operations on behalf of Windows and applications. |
| LSASS | Local Security Authority Subsystem Service | The Windows process responsible for enforcing security policy, handling authentication, and loading CNG/CAPI providers. |
| MDM | Mobile Device Management | A class of software and protocols that allow organisations to remotely configure, monitor, and enforce policies on employee devices. |
| MMC | Microsoft Management Console | A Windows host application for administrative snap-in tools, including the Certificates snap-in (certmgr.msc). |
| MSVC | Microsoft Visual C++ | Microsoft's C/C++ compiler and runtime toolchain, required to build Windows native binaries and DLLs (including Rust code targeting x86_64-pc-windows-msvc). |
| mTLS | Mutual TLS | A variant of TLS in which both the client and the server present X.509 certificates to authenticate each other. |
| NCrypt | N-Crypt (CNG asymmetric API) | The asymmetric-key and key-storage half of the Windows CNG API. NCrypt* functions delegate to the registered KSP DLL for private key operations. |
| NDES | Network Device Enrollment Service | A Microsoft Windows Server role that implements the SCEP protocol, acting as a proxy between Intune/MDM and an enterprise CA. |
| NIS2 | Network and Information Systems Directive 2 | EU cybersecurity directive (2022/2555) that expands the scope of the original NIS directive, imposing stricter security requirements and incident reporting obligations. |
| NIST | National Institute of Standards and Technology | US federal agency that publishes cryptographic standards (AES, SHA, ECDSA, FIPS 140, etc.). |
| OAEP | Optimal Asymmetric Encryption Padding | A padding scheme (RFC 8017) used with RSA encryption that provides semantic security and resistance to chosen-ciphertext attacks. |
| OAuth 2.0 | Open Authorization 2.0 | An open standard for token-based delegated authorisation, widely used for API access. Bearer tokens issued by an identity provider are used to authenticate calls to the KMS. |
| PKCS | Public Key Cryptography Standards | A family of cryptographic standards published by RSA Security / IETF. Commonly referenced standards include PKCS#1 (RSA), PKCS#7/CMS (signed data), PKCS#10 (CSR), PKCS#11 (token interface), and PKCS#12 (PFX key store). |
| PKCS#12 | Public Key Cryptography Standard #12 | A binary format (.pfx / .p12) for storing a private key together with its certificate chain, protected by a password. |
| PKI | Public Key Infrastructure | The set of roles, policies, hardware, software, and procedures needed to create, manage, distribute, use, store, and revoke digital certificates. |
| PSS | Probabilistic Signature Scheme | A padding scheme (RFC 8017 / RSASSA-PSS) for RSA digital signatures that adds randomness, providing provable security without requiring a full-domain hash. |
| RSA | Rivest–Shamir–Adleman | A widely used public-key cryptosystem based on the difficulty of factoring large integers, supporting both encryption and digital signatures. |
| SCEP | Simple Certificate Enrollment Protocol | An IETF protocol (RFC 8894) that automates the issuance of X.509 certificates, typically used by MDM systems like Microsoft Intune to enroll device certificates. |
| S/MIME | Secure/Multipurpose Internet Mail Extensions | A standard for public-key encryption and digital signing of email messages, using X.509 certificates. |
| SPKI | Subject Public Key Info | The ASN.1 structure (from X.509 / RFC 5480) that encodes a public key together with its algorithm identifier, used in CSRs and DER-format public key exports. |
| TLS | Transport Layer Security | The cryptographic protocol that secures communications over networks, successor to SSL. Used for all HTTPS connections between the KSP DLL and the KMS server. |
| TPM | Trusted Platform Module | A hardware chip embedded in many PCs that provides secure key generation and storage tied to the physical machine. The CNG KSP is an alternative to TPM-backed key storage, offering remote management capabilities. |
| UEM | Unified Endpoint Management | A category of IT management solutions that provide a single platform for managing all endpoint types (PCs, mobiles, IoT). Microsoft Intune is a UEM service. |
| UUID | Universally Unique Identifier | A 128-bit identifier (RFC 4122) used by Cosmian KMS to uniquely identify every managed key object. |
| vcpkg | Visual C++ Package Manager | Microsoft's open-source C/C++ package manager, used in this project to obtain pre-built OpenSSL static libraries for Windows builds. |
To import a Customer Managed Encryption Key in the Google KMS, follow the instructions on Google documentation related to importing a manually wrapped key.
Prepare the symmetric key and wrapping key in Google Cloud KMS
Using the Google Console, first create a key in an existing Cloud KMS key ring.

Click Continue and select Imported Key

Then click Create
In the Select Import Job dropdown, select Create Import Job

Select 4096 bit RSA -OAEP Padding - SHA256 digest + 256 bit AES-KWP as import method
then click Create
Then click Download wrapping key

The key will be downloaded as a PKCS#8 PEM named ImportWith4096RsaAesKeyWrapSha256.pem
Create a symmetric key in Eviden KMS
This is the symmetric key that will be wrapped by the Google wrapping key and imported in the Google KMS.
ckms sym keys create --number-of-bits 256 CMEK_Sym_Key
The symmetric key was successfully generated.
Unique identifier: CMEK_Sym_Key
Import the wrapping key in Eviden KMS
ckms rsa keys import --key-format pem --key-usage encrypt --key-usage wrap-key \
ImportWith4096RsaAesKeyWrapSha256.pem CMEK_Wrapping_Key
The PublicKey in file ImportWith4096RsaAesKeyWrapSha256.pem was imported with id: CMEK_Wrapping_Key
Unique identifier: CMEK_Wrapping_Key
Export the symmetric key wrapped by the wrapping key from Eviden KMS
ckms sym keys export --key-id CMEK_Sym_Key --wrap-key-id CMEK_Wrapping_Key \
--key-format raw --wrapping-algorithm rsa-aes-key-wrap wrapped_key.bin
The key CMEK_Sym_Key of type SymmetricKey was exported to "wrapped_key.bin"
Unique identifier: CMEK_Sym_Key
Note 1: The rsa-aes-key-wrap wrapping algorithm uses the SHA256 digest.
Note 2: the wrapped key should be 552 bytes (4416 bits) long:
- 4096 bits (RSA key length) +
- 256 bits (Symmetric key length) +
- 64 bits of AES KWP overhead.
Import the wrapped key in Google Cloud KMS

The key should now be available in the Google Cloud KMS.

Automated testing
The entire Eviden KMS side of this workflow (steps 2–4) is covered by the
script .mise/scripts/test_gcp_cmek.sh. It uses the test wrapping key at
test_data/google_cmek/Import_RSA_AES_WRAP.pem and can be executed via:
mise run test:gcp_cmek --variant non-fips
To use Customer Supplied Encryption Keys, follow the general instructions on using RSA wrapping keys.
Generate a symmetric key in Eviden KMS
This is the symmetric key that will be used as the CSEK.
ckms sym keys create --number-of-bits 256 CSEK_Sym_Key
The symmetric key was successfully generated.
Unique identifier: CSEK_Sym_Key
Download the Google CSEK Certificate and extract the RSA wrapping key
Download the certificate
curl https://cloud-certs.storage.googleapis.com/google-cloud-csek-ingress.pem > test_data/cse/google-cloud-csek-ingress.pem
Import the certificates in Eviden KMS
Name it google_csek on import.
ckms certificates import --format pem test_data/cse/google-cloud-csek-ingress.pem google_csek
The certificate in the PEM file was successfully imported!
Unique identifier: google_csek
Export the wrapped CSEK Symmetric Key
The key must be wrapped using CKM_RSA_PKCS_OAEP with a SHA1 digest.
The export function will automatically recover the wrapping public key from the certificate and perform the key wrapping.
ckms rsa keys export --key-id CSEK_Sym_Key --wrap-key-id google_csek \
--wrapping-algorithm rsa-oaep-sha1 --key-format raw wrapped_key.bin
The key CSEK_Sym_Key of type SymmetricKey was exported to "wrapped_key.bin"
Unique identifier: CSEK_Sym_Key
Note 1: Make sure you use rsa-oaep-sha1 to force the SHA1 digest.
Note 2: The wrapped key should be 2048 bits (256 bytes) long.
Convert the wrapped CSEK Symmetric Key to base64
cat wrapped_key.bin | base64
BtE+r06qy4isyfMR29n5uGSPj1qbOQTA42nxVJ...Hw==
Getting started
The Eviden Key Management Server is compatible with Google Workspace client-side encryption. Using this feature, your users can encrypt files and documents, in their browsers, before sending them to Google servers. The ephemeral encryption keys are protected by "key wrapping keys", stored in the KMS and unavailable to Google. Only users that have the right to unwrap the ephemeral encryption keys inside the KMS, can decrypt the files. An overview is provided in Google's About client-side encryption page.
To enable client-side encryption (CSE) in Google Workspace, connect as an admin to the admin console and go to the Google Workspace client-side encryption page.
Google has extensive documentation on how to enable CSE in Google Workspace. The Use client-side encryption for users' data page is a good starting point. It may be slightly overwhelming, and this documentation adds some details to help you get started.
Prerequisites
You will need:
- A Google Workspace account
- A Certificate Authority (CA) compliant with Gmail to generate the certificates for the users
- An Identity Provider (IdP) (in this tutorial the Google Identity Provider)
- The Eviden Key Management Server behind a
Nginxserver:- exposing a valid TLS certificate
- and serving the
.well-knownfile used by the Identity Provider
- The KMS CLI
- to generate the Google CSE key in the Eviden KMS with correct access rights
- to generate the Gmail users keys
Choosing the Certificate Authority
First you need an intermediate CA (Certificate Authority) that is trusted by Google and compliant with Gmail X509 expectations (read the expected X509 extensions).
This CA will issue your users certificates:
- either your CA is one of the Google recommended CA, follow this page to make sure it is (note that Actalis can provide CA certificates for free). In that case, your users S/MIME certificates will be issued directly from your CA and you will need to import them one by one using KMS CLI
- either this is a custom CA:
- that you already have (remember that this custom CA must have the expected Google X509 extensions). You will have to upload the full CA chain in admin.google.com->Apps/Google Workspace/Settings for Gmail/User Settings/S/MIME (and wait for provisioning to be fully done, few hours expected).
- that you do not have, in that case read this page to generate your own CA and upload the full CA chain in admin.google.com.
Actalis CA
In order to import the Actalis CA in admin.google.com->Apps/Google Workspace/Settings for Gmail/User Settings/S/MIME, you have to build the full chain of certificates from an existing PKCS#12 certificate.
openssl pkcs12 -in certificate_s_mime.p12 -cacerts -nokeys -out ca.pem -passin pass:'YOUR_PASSWORD'
openssl pkcs12 -in certificate_s_mime.p12 -clcerts -nokeys -out certificate.pem -passin pass:'YOUR_PASSWORD'
cp certificate.pem fullchain.pem
cat ca.pem >> fullchain.pem
cat fullchain.pem
Choosing and configuring the Identity Provider
The first thing that will need to be done is to configure the Identity Provider. This is the service that the Eviden Key Management Server will use to authenticate users before they can encrypt files or access encrypted files.
The Identity Provider (IdP) is either a third party IdP or Google identity.
Using Google Identity is not recommended since Google as the authority could issue tokens to impersonate users and recover their keys. However, since configuring an Identity Provider is hard and Google Identity is the easiest to configure, we will use it in this tutorial.

The initial page should look like this. What matters here is the link shown at the tip of the red-arrow.
This is the URL at which Google client-side encryption expects the .well-known file to be served.
Assuming your domain is example.com, the URL will likely be https://cse.example.com/.well-known/cse-configuration.
To configure a .well-known file, you need to:
-
Create the
.well-knownfile with the proper content -
Set up a server that serves the file at the URL shown in the image above
Instructions are provided in the Configuring the .well-known file section
Once this is complete, the screen on refresh should turn to this:

Configuring the Key Management Server
The KMS must be behind a valid TLS certificate when started.
Assuming it is running at https://cse.example.com (kms-public-url parameter from server configuration), you should add the External Key Service with KACLS URL https://cse.example.com/google_cse in the Client-Side Encryption page of the Google Workspace admin console.
To enable Client Side Encryption on the Eviden KMS server, it must be started with the --kms-public-url option, and the --google-cse-enable option.
This URL option is at which the KMS will serve the Key Access Control Lists (KACLs) for the Google CSE service.
The KACLs are used by the Google CSE service to determine which users have access to which keys.
The KACLs are served by the KMS at the URL https://cse.example.com/google_cse in the example above.
The Key Management Server must be configured to use the same Identity Provider as the one configured in the previous step. When using Google Identity, the server should be configured with the following options set in the corresponding Google documentation.
Assuming Google is the Identity Provider, the KMS should be started with the following options:
--jwt-issuer-uri=https://accounts.google.com
--jwks-uri=https://www.googleapis.com/oauth2/v3/certs
--kms-public-url=https://cse.example.com
--google-cse-enable
For example, if you are using the docker image, you can run the following command:
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest \
--jwt-issuer-uri=https://accounts.google.com \
--jwks-uri=https://www.googleapis.com/oauth2/v3/certs \
--kms-public-url=https://cse.example.com \
--google-cse-enable
# Server configuration
kms_public_url = "http://localhost:9998"
# JWT authentication with Google
[idp_auth]
# issuer,jwks[,aud1[,aud2...]]; audiences optional (any-of when multiple)
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"]
# Google CSE configuration
[google_cse_config]
google_cse_enable = true

Then test the connection; it should show:

Finalize the configuration. The Client Side Encryption page should now show the service to be active and you will now have to decide whether to assign this service to all users or to a subset of users.

Creating google_cse key
Once your CSE Eviden KMS is up and running, you need to import the AES wrapping key, which will be responsible for wrapping the keys managed by Google.
This key MUST be created under the google_cse ID.
Using the KMS CLI, ensure that it is properly configured and that authentication is handled correctly.
Concerning the KMS CLI, you will have to log in the first time you use it.
This is done by running ckms login.
# create it
ckms sym keys create -t google_cse google_cse
# or import an existing key
ckms sym keys import -t google_cse PATH_TO_YOUR_KEY google_cse
Next, you'll need to assign access rights to each user who requires CSE functionality, whether they are part of your organization or a guest. You can also grant wildcard access ('*') to allow all users to use this key in CSE endpoints.
ckms access-rights grant USER_ID google_cse get encrypt decrypt
# or give access to everyone
ckms access-rights grant '*' google_cse get encrypt decrypt
Handling Guest identity providers
As an administrator, you can allow external users to access your encrypted content via Google Workspace Client-Side Encryption (CSE), including sharing encrypted documents or hosting encrypted Google Meet sessions.
For more information on this configuration, refer to Google documentation.
Eviden KMS supports this feature, and to enable it:
- Add the identity provider's information in the server-side Eviden KMS configuration
- Ensure that external users can access the Google CSE symmetric key
User experience
Learn more details about CSE user experience over all supported applications.
Configuring the .well-known file
General configuration instructions for Google client-side encryption is available at this url in paragraph (Option 1) To connect to your IdP using a .well-known file
Using Google as an Identity Provider
To use Google as an Identity Provider, you first need to create a dedicated client ID in the Google Cloud Console. Detailed instructions are available on the page referenced above in the section entitled Create-a-client-id-for-google-identity.
The general idea is to create a project, then in APIs & Services > Credentials, create a client ID for a web application.
This Client ID will be used in the .well-known file.
Once created the Client ID should look like this

Do not forget to add http://localhost:17899/authorization in the Authorized redirect URIs list. It will allow the KMS CLI to authenticate with Google.
The list of URLs for Authorized origins and Authorized redirect are available in the Google documentation above, in paragraph Create a client ID for Google identity.
Generating the .well-known file
The format of the .well-known file is specified by RFC 8259
{
"name": "Google identity for workspace client-side encryption",
"client_id": "996739510374-au9fdbgp72dacrsag267ckg32jf3d3e2.apps.googleusercontent.com",
"discovery_uri": "https://accounts.google.com/.well-known/openid-configuration",
"grant_type": "implicit",
"applications": {
"drivefs": {
"client_id": "947318989803-k88lapdik9bledfml8rr69ic6d3rdv57.apps.googleusercontent.com"
},
"drive-android": {
"client_id": "313892590415-6lbccuf47cou4q45vanraqp3fv5jt9do.apps.googleusercontent.com"
},
"drive-ios": {
"client_id": "313892590415-d3h1l7kl4htab916r6jevqdtu8bfmh9m.apps.googleusercontent.com"
},
"calendar-android": {
"client_id": "313892590415-q84luo8fon5on5vl8a6rppo1qvcd3qvn.apps.googleusercontent.com"
},
"calendar-ios": {
"client_id": "313892590415-283b3nilr8561tedgu1n4dcm9hd6g3hr.apps.googleusercontent.com"
},
"gmail-android": {
"client_id": "313892590415-samhd32i4piankgs42o9sit5e9dug452.apps.googleusercontent.com"
},
"gmail-ios": {
"client_id": "313892590415-ijvjpbnsh0gauuunjgsdn64ngg37k6rc.apps.googleusercontent.com"
},
"meet-android": {
"client_id": "313892590415-i06v47su4k03ns7ot38akv7s9ari5oa5.apps.googleusercontent.com"
},
"meet-ios": {
"client_id": "313892590415-32ha2bvs0tr1b12s089i33o58hjvqt55.apps.googleusercontent.com"
}
}
}
client_id is the OAuth 2.0 client ID of the Google Workspace domain that is created using the Google Cloud Console
Configuring a static web server to serve the .well-known file
The URL at which Google client-side encryption expects the .well-known file is on the link pointed by the red arrow below.

Assuming your organization is on the domain acme.com (which should match that of your email address domain), the URL would be: https://cse.acme.com/.well-known/cse-configuration
1. Configure a server running Ubuntu 23.04
The server should be reachable using an external IP; configure your DNS so that a A record with value cse.acme.com points to that external IP address of the server.
Make sure ports 80 and 443 are open to external traffic on this machine. Access to port 80 can be closed at the end of this procedure.
2. Install nginx on the server
sudo apt update
sudo apt install nginx
3. Transfer your .well-known file
sudo mkdir /var/www/html/.well-known
sudo touch /var/www/html/.well-known/cse-configuration
sudo scp 'path_to_your_well_known_file' user@IP:/var/www/html/.well-known/cse-configuration"
The file will put your created .well-known file to you web server in order to expose it.
4. Configure nginx to serve the .well-known file
Since, the .well-known file is served from a different domain than the one used by Google client-side encryption,
CORS calls need to be enabled on NGINX to allow the browser to fetch the .well-known file.
Edit the file /etc/nginx/sites-available/default and add the following location:
location /.well-known/ {
root /var/www/html;
# Allow CORS calls: see https://support.google.com/a/answer/10743588?hl=en
add_header 'Access-Control-Allow-Origin' '*';
}
Then restart the nginx service
sudo systemctl restart nginx
Finally, verify that nginx is correctly serving the file by running
➜ curl http://localhost/.well-known/cse-configuration
5. Enable HTTPS with certbot and Lets's Encrypt
Install certbot on the machine using snap (the snap daemon should already be installed and activated on Ubuntu 23.04)
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
General instructions on installing certbot are available at this URL.
Get a certificate and configure nginx
sudo certbot --nginx
The command will ask you to provide an email address and a domain name. The domain name should be cse.acme.com (or whatever domain you chose in step 1).
That's it, the empty .well-known file should now be served using HTTPS. From another machine, verify that it is now available on the public address
➜ curl https://cse.acme.com/.well-known/cse-configuration
{}
Port 80 can now be closed on the machine (or nginx configuration can be updated to redirect HTTP requests to HTTPS)
6. Enable CORS calls
The .well-known file is served from a different domain than the one used by Google client-side encryption. CORS calls need to be enabled on the server to allow the browser to fetch the .well-known file.
Edit the file /etc/nginx/sites-available/default and add the following at the top of the file (before the server block):
# Allow CORS calls: see https://apps.google.com/supportwidget/articlehome?hl=en&article_url=https%3A%2F%2Fsupport.google.com%2Fa%2Fanswer%2F10743588%3Fhl%3Den&assistant_id=generic-unu&product_context=10743588&product_name=UnuFlow&trigger_context=a
add_header 'Access-Control-Allow-Origin' '*';
Then restart the nginx service
sudo systemctl restart nginx
7. Optional: download the .well-known file as a proper JSON
The Client-side encryption service does not require this setting to work properly. However, it is useful to be able to download the .well-known file as a proper JSON object when viewing it in a browser.
To do so, the content-type header of the response must be set to application/json. Edit the file /etc/nginx/sites-available/default and add the following inside the server block that serves the HTTPS requests:
location /.well-known/ {
default_type application/json;
}
Then restart the nginx service
sudo systemctl restart nginx
Follow the Google documentation to enable S/MIME for client-side encryption in your organization and create a service account to interact with the Gmail API.
Configure KMS CLIent (CLI)
The cosmian command line interface (CLI) simplifies the setup of S/MIME keys and certificates for users.
After completing the setup, update your KMS CLI with the necessary information for the service account you created for the Gmail API.
Choosing the Certificate Authority
First you need an intermediate CA (Certificate Authority) that is trusted by Google and compliant with Gmail X509 expectations (read the expected X509 extensions).
This CA will issue your users certificates:
-
either your intermediate CA is one of the Google recommended CA, follow this page to make sure it is (note that Actalis can provide CA certificates for free). In that case:
-
at first, you need to import the issuer intermediate CA certificate into Eviden KMS since Google already trusts the root CA.
ckms certificates import -f pkcs12 issuer_ca_certificate.p12 -p \ PASSWORD issuer_ca_certificate -
then, you need to import your users S/MIME certificates one by one using KMS CLI.
-
-
either your intermediate CA is an internal or custom CA:
- that you already have (remember that this custom CA must have the expected Google X509 extensions).
You will have to upload the full CA chain in
admin.google.com->Apps/Google Workspace/Settingsfor Gmail/User Settings/S/MIME (and wait for provisioning to be fully done, few hours expected).
!!! warning Google Root CA The Google Root CA is actually the following chain (root CA + intermediate CA + any leaf public certificates). Allow a few hours for Google to complete the provisioning.
Build your Google Root CA following those steps: [Exporting and viewing](../../smime.md#exporting-and-viewing) and do not forget to export the [Google expected root CA](../../smime.md#exporting-for-google-cse-smime) - that you do not have, in that case follow [those instructions to generate your own CA chain](../../smime.md#creating-an-smime-certificate-authority-with-a-root-and-intermediate-ca) and upload the Google Root CA in admin.google.com. - that you already have (remember that this custom CA must have the expected Google X509 extensions).
You will have to upload the full CA chain in
Managing administrator access rights
If multiple administrators will be generating key-pairs for users, ensure that each administrator has the appropriate access rights to the imported certificate chain elements:
- the issuer certificate ID (given when importing the Certificate Authority)
- the issuer private key ID
- the issuer public key ID
In order to get the issuer private key ID and issuer public key ID, run the following command:
ckms attributes get -i issuer_ca_certificate
You'll use the ID of the issuer's private key (imported from the certificate chain) to later sign users' public keys and create their certificates.
Create user key-pair
Gmail uses key-pairs (an RSA private key wrapped with its associated certificate) and identities (the ID of an uploaded key-pair, associated with a user) to sign and encrypt emails using S/MIME.
These objects are uploaded to Google via the Gmail API.
You can create a key-pair (RSA private key and user certificate chain) and upload it to the Gmail API using the following command:
ckms google key-pairs create --cse-key-id CSE_KEY_ID \
--subject-name "C=FR, ST=IdF, L=Paris, O=ORGANIZATION, OU=DEPARTMENT, CN=user@organization.com, emailAddress=user@organization.com" \
-i ISSUER_PRIVATE_KEY_ID --leaf-certificate-extensions user.ext user@your_organization.com
If you already have an existing RSA key-pair for the user, you can specify it in the command.
Using an existing leaf certificate
Instead of generating a new leaf certificate, you can use an existing one by specifying either:
--leaf-certificate-id CERT_ID: Use a certificate already stored in KMS--leaf-certificate-pkcs12-file /path/to/cert.p12: Use a local certificate file
When using an existing leaf certificate, the --leaf-certificate-extensions parameter is not required.
!!! warning X509 flags extensions Remember that existing X509 certificate must comply the Google CSE requirements. X509 flags are expected by Google Gmail CSE for S/MIME.
Example with an existing PKCS12 certificate:
ckms google key-pairs create --cse-key-id CSE_KEY_ID \
--subject-name "C=FR, ST=IdF, L=Paris, O=ORGANIZATION, OU=DEPARTMENT, CN=user@organization.com, emailAddress=user@organization.com" \
--leaf-certificate-pkcs12-file /path/to/cert.p12 --leaf-certificate-pkcs12-password secret user@your_organization.com
Once created, the ID of the key pair and the certificate will be displayed.
Note: It may take up to 24 hours for Google to propagate the Client-Side Encryption (CSE) activation for a user within the Gmail API, allowing you to upload the S/MIME elements.
Insert user identity
After creating the key-pair, you must associate it with the user's identity. To do so, run the following command:
ckms google identities insert \
--user-id user@your_organization.com CREATED_KEYPAIR_ID
You can manage key-pairs (get, list, enable, disable, obliterate) and identities (get, list, delete, patch) using the other available commands in the ckms commands documentation.
Note: It may take a few hours for Google to propagate the uploaded elements, after which users can begin using S/MIME for secure email exchanges.
User experience
To send a client-side encrypted email within your organization, a user needs to turn on the additional encryption option in the message window (lock -> Turn on additional encryption). Only users with CSE activated can encrypt and decrypt encrypted emails.
To send a client-side encrypted email outside your organization, a user needs to send a message to the recipient with their digital signature, without CSE turned on. The recipient then needs to reply to the message with their digital signature. Then the sender can choose to add CSE to email sent to the external recipient.
Encrypted emails will be automatically decrypted from Gmail interface.
Learn more about CSE user experience
Migrating existing Google Drive encrypted content to a new key service
This guide explains how to migrate encrypted content in Google Drive to a new key management service (KMS), specifically using Eviden KMS.
For a complete overview of Google's migration flow and all available options, refer to Google's official technical documentation.
Eviden KMS migration support and configuration
Eviden KMS supports the Google Client-Side Encryption (CSE) migration process by implementing the required endpoints, including:
-
POST <KMS_PUBLIC_URL>/google_cse/rewrap -
POST <KMS_PUBLIC_URL>/google_cse/privilegedunwrap
These endpoints allow Eviden KMS to serve as either the source or target key service during a migration.
JWT Authentication for Migration
Google's migration flow requires both key services (KACLS) to authenticate with each other via signed JWTs. To support this:
Eviden KMS generates a dedicated RSA key pair at startup (if not already present in the database).
- The private key is stored under the ID:
google_cse_rsa - The public key is stored under the ID:
google_cse_rsa_pk
Note: the JWT tokens MUST have their audience set to kacls-migration.
Key Persistence Across Restarts & Multiple Instances
To ensure consistent JWT signatures and seamless privileged unwrap operations across multiple instances or restarts, you can manually provide a persistent RSA private key using the --google-cse-migration-key CLI option.
This key must be in PEM-encoded PKCS#8 format.
Public Key Exposure
To allow other KACLS to verify JWT signatures, Eviden KMS exposes its public RSA key at:
GET <KMS_PUBLIC_URL>/google_cse/certs
This endpoint serves a JWKS (JSON Web Key Set) containing the public signing key.
Migrating existing emails to Gmail CSE
This documentation focuses on migrating email messages from a PST or Mbox archive to Gmail CSE. An overview of all migration options is provided in this blog article and covers other options such as migrating from Virtru or Microsoft Exchange.
A more general view of all the migration options to and from Gmail can be found at this link
Install the migration utility
Download the migration utility from the first link above.
Make sure you look at the included readme file for the scopes that must be associated with the service account (see below).
Create a service account credential with domain-wide access
Head to the GCP console and follow the Google Documentation on creating a Service Account
Create a service account

Create a key in JSON format

The key will be saved to your computer. The key will be provided to the migration utility.
Grant the GMail API domain-wide access
Open the Google Workspace Admin and follow
the instructions
in the paragraph Set up domain-wide delegation for a client

Create a new API client, the client ID is available in the Details of the service account
on the Google Cloud Console.
The OAuth scopes required are:
-
https://www.googleapis.com/auth/gmail.readonlyfor a dry run -
https://www.googleapis.com/auth/gmail.modifywhen performing the actual migration
For more details on Google OAuth scopes, check this reference
Migrate example usage
Perform a dry-run over two input files to verify that they can be parsed and that their messages can be encrypted in preparation for migration:
For Windows:
gmail-cse-migrate.exe -input user1.pst -input user2.pst -api-credential c:\my_svc_acct.json -dryrun -logfile log.txt
If it looks good, then run the command again in migration mode:
gmail-cse-migrate.exe -input user1.pst -input user2.pst -api-credential c:\my_svc_acct.json -logfile log.txt
For macOS:
/gmail-cse-migrate \
-api-credential=./gmail-migration-service-account-key.json \
-input=user1.mbox \
-logfile=./log.txt -dryrun
Version: gmail_cse_migrate-24.11.0.2 (darwin)
Download URI:
https://dl.google.com/clientsideencryption/gmail-cse-migrate/macos/latest/gmail-cse-migrate.dmg
COMPLETED
Inspected: 1 file in 0 directories
Found: 163 messages in 1 .mbox file
Failures: 6 messages in .mbox files failed to parse
MIGRATION
Processed: 127 messages
Skipped: 127 messages were not uploaded due to dryrun
Skipped: 36 already encrypted messages were not migrated
PARTIAL SUCCESS
LOG FILE WRITTEN TO
./log.txt
Export Data from GMail
If you need to export data from Gmail, the easiest is to use TakeOut, which you can find here
To export data for a single user, follow this documentation
To export the whole organization data, follow this documentation
Manual Setup for MongoDB Client-Side Field Level Encryption (CSFLE) with KMIP
This guide walks through the manual setup process for enabling Client-Side Field Level Encryption in MongoDB using a KMIP-compatible Key Management System (KMS).
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.0 over TCP/TLS with mutual certificate authentication |
| Port | 5696 (IANA-registered KMIP port) |
| Key type | AES-256 symmetric key |
| MongoDB version | MongoDB Enterprise 6.0 and above |
| Eviden KMS feature | Requires non-FIPS build |
Prerequisites
Packages
- MongoDB Enterprise ≥
6.0 - Python ≥
3.8 - Python packages:
pymongodnspython
- MongoDB Crypt Shared Library:
- Download from the MongoDB Enterprise downloads section (e.g.,
mongo_crypt_v1.so) - Install to:
/opt/mongo_crypt_shared/mongo_crypt_v1.so
- Download from the MongoDB Enterprise downloads section (e.g.,
- Eviden KMS:
- Eviden KMS endpoint:
your-cosmian_kms-server:port - TLS certs:
- Client cert:
/opt/kms-certs/client.pem - CA cert:
/opt/kms-certs/ca.pem
- Client cert:
- Eviden KMS endpoint:
- Key Vault Namespace:
- Database:
encryption - Collection:
__keyVault
- Database:
- Schema Target Collection (example):
- Database:
medical - Collection:
patients
- Database:
- Alternative Key Name (for the DEK):
yourSecretKeyAlias
Step-by-Step Guide
⚠️ This tutorial was done in a DB test environment with an external Eviden KMS.
1. Define environment variable
Ensure that the path to the crypt shared library is defined:
export CRYPT_SHARED_LIB_PATH=/opt/mongo_crypt_shared/mongo_crypt_v1.so
2. Clean up existing DEKs (optional)
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017")
client["encryption"]["__keyVault"].delete_many({"keyAltNames": ["yourSecretKeyAlias"]})
3. Generate a new DEK manually
from pymongo.encryption import ClientEncryption
from pymongo import MongoClient
from bson.codec_options import CodecOptions
kms_providers = {
"kmip": {
"endpoint": "your-cosmian_kms-server:port"
}
}
tls_options = {
"kmip": {
"tlsCertificateKeyFile": "/opt/kms-certs/client.pem",
"tlsCAFile": "/opt/kms-certs/ca.pem"
}
}
client = MongoClient("mongodb://localhost:27017")
client_encryption = ClientEncryption(
kms_providers=kms_providers,
key_vault_namespace="encryption.__keyVault",
key_vault_client=client,
codec_options=CodecOptions(),
kms_tls_options=tls_options
)
data_key_id = client_encryption.create_data_key("kmip", key_alt_names=["yourSecretKeyAlias"])
print(f"Created DEK with ID: {data_key_id}")
4. Define your encryption schema
schema_map = {
"medical.patients": {
"bsonType": "object",
"properties": {
"ssn": {
"encrypt": {
"keyId": [data_key_id],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
}
}
}
5. Create the encrypted MongoClient
from pymongo.encryption_options import AutoEncryptionOpts
auto_encryption_opts = AutoEncryptionOpts(
kms_providers=kms_providers,
key_vault_namespace="encryption.__keyVault",
schema_map=schema_map,
kms_tls_options=tls_options,
crypt_shared_lib_path=CRYPT_SHARED_LIB_PATH
)
secure_client = MongoClient("mongodb://localhost:27017", auto_encryption_opts=auto_encryption_opts)
6. Insert encrypted data
db = secure_client["medical"]
collection = db["patients"]
collection.drop()
collection.insert_one({
"nom": "Doe",
"ssn": "123-45-6789"
})
print("Encrypted document inserted.")
Notes
- Replace
your-cosmian_kms-server:portwith your KMIP endpoint (e.g.cosmian-kms.example.com:5696). - Replace certificate paths if different.
- The
ssnfield will be transparently encrypted on insert, and decrypted on read. - This setup requires MongoDB Enterprise, as CSFLE is not supported in the Community Edition.
Reading Encrypted Data with MongoDB CSFLE (Client-Side Field Level Encryption)
Step-by-Step Guide
This guide walks you through reading encrypted documents stored in MongoDB using automatic decryption with the CSFLE feature.
1. Set the Shared Crypt Library Path
Make sure the environment variable is set to the location of your shared crypt library:
export CRYPT_SHARED_LIB_PATH=/opt/mongo_crypt_shared/mongo_crypt_v1.so
2. (Optional) Read Raw Encrypted Documents
You can view the encrypted form of the documents using a regular (non-CSFLE-enabled) MongoDB client:
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017")
print("🔒 Raw encrypted documents:")
for doc in client.medical.patients.find():
print(doc)
3. Define KMS Provider Configuration
kms_providers = {
"kmip": {
"endpoint": "your-cosmian_kms-server:port"
}
}
tls_options = {
"kmip": {
"tlsCertificateKeyFile": "/opt/kms-certs/client.pem",
"tlsCAFile": "/opt/kms-certs/ca.pem"
}
}
4. Configure AutoEncryptionOpts
This will enable automatic decryption using the shared library:
import os
from pymongo.encryption_options import AutoEncryptionOpts
CRYPT_SHARED_LIB_PATH = os.getenv("CRYPT_SHARED_LIB_PATH", "/opt/mongo_crypt_shared/mongo_crypt_v1.so")
auto_encryption_opts = AutoEncryptionOpts(
kms_providers=kms_providers,
key_vault_namespace="encryption.__keyVault",
kms_tls_options=tls_options,
crypt_shared_lib_path=CRYPT_SHARED_LIB_PATH
)
5. Create a Secure Client with CSFLE Enabled
from pymongo import MongoClient
secure_client = MongoClient(
"mongodb://localhost:27017",
auto_encryption_opts=auto_encryption_opts
)
6. Read Decrypted Documents
secure_db = secure_client["medical"]
secure_coll = secure_db["patients"]
print("🔓 Automatically decrypted documents:")
for doc in secure_coll.find():
print(doc)
Result
Encrypted fields will be automatically decrypted in the returned documents, provided the proper key is stored in your key vault and accessible via the configured Eviden KMS.
Additional Notes
- Make sure the key vault namespace (
encryption.__keyVault) matches the namespace used during encryption. - This method works only with MongoDB Enterprise or MongoDB Atlas with CSFLE support.
MySQL Enterprise 8.4 + Eviden KMS Integration
Executive Summary
This document provides a comprehensive guide for integrating MySQL Enterprise with Eviden Key Management System (KMS) using the keyring_okv plugin for Transparent Data Encryption (TDE). This lab demonstrates secure key management and data encryption at rest in a controlled environment.
Version Requirements
Minimum Versions for TDE with keyring_okv
| Component | Minimum Version | Notes |
|---|---|---|
| MySQL Enterprise | 8.0+ | keyring_okv plugin available in Enterprise Edition |
| Eviden KMS | 5.14+ | Full KMIP 1.1 compatibility |
| KMIP Protocol | 1.1 | Standard protocol version supported by keyring_okv |
| OpenSSL | 3.0+ | For TLS 1.3 and mTLS certificate support |
Note: This lab uses MySQL 8.4.7 and Eviden KMS 5.14+ which are the stable, production-ready versions recommended for new deployments.
Technical Specifications
System Requirements
| Component | Version | Specification |
|---|---|---|
| MySQL Enterprise Server | 8.4.7-commercial | Generic Linux x86_64 binary (glibc 2.28) |
| Eviden KMS | 5.14+ | KMIP 1.1 server with socket support |
| Operating System | Ubuntu 24.04 LTS (Noble) | Debian 10+, RHEL 8+, or any modern Linux (x86_64) |
| OpenSSL | 3.6.2 (+ 3.1.2 FIPS provider) | For TLS/mTLS communication |
| Network | Dedicated subnet | Low-latency, isolated lab network |
Network Architecture
flowchart LR
subgraph network["Isolated Lab Network"]
kms["Eviden KMS v5.14+<br/>HTTP: 9998 (HTTPS)<br/>KMIP: 5696 (TLS)<br/>DB: SQLite"]
mysql["MySQL Enterprise v8.4.7<br/>Port 3306 (MySQL)<br/>KMIP via TLS<br/>keyring_okv plugin"]
kms <-->|"KMIP 1.1 over TLS 1.3"| mysql
end
Key Management Flow
flowchart TB
innodb["MySQL InnoDB"]
tek["Generates encryption key (TEK)"]
okv["keyring_okv plugin (MySQL 8.0+)"]
kms["Eviden KMS v5.14+<br/>(Port 5696)"]
db["SQLite Database (persistent)"]
innodb --> tek
tek --> okv
okv -->|"Connects via KMIP (TLS)"| kms
kms -->|"Stores / retrieves master key"| db
Architecture Overview
Component Roles
Eviden KMS (v5.14+):
- Acts as external Key Management System
- Manages encryption keys for MySQL
- Provides KMIP 1.1 protocol support
- Stores keys in persistent SQLite database
- Enforces mutual TLS (mTLS) authentication with client certificates
- Independent of MySQL lifecycle
MySQL Enterprise (v8.0.13+, ideally 8.4+):
- Runs
keyring_okvplugin as KMIP client - Generates and manages Transparent Data Encryption (TDE) keys
- Encrypts table data at rest using master key from KMS
- Communicates with KMS via secure KMIP protocol
- Does NOT store master keys locally (security by design)
- Maintains in-memory cache during uptime for performance
Security Model
- Authentication: Mutual TLS (mTLS) with X.509 certificates
- Encryption: AES-256 for data, TLS 1.3 for transport
- Key Storage: Centralized in Eviden KMS (never persisted on MySQL filesystem)
- Key Access: Only via authenticated KMIP protocol over TLS
- Cache Invalidation: Automatic on KMS unavailability
Prerequisites
Hardware Requirements
- Eviden KMS Server: 1 vCPU, 2 GB RAM, 10 GB storage
- MySQL Enterprise Server: 2 vCPU, 4 GB RAM, 20 GB storage
- Network: Low-latency connection (<10 ms ping recommended)
Software Requirements
On Eviden KMS Host (v5.14+):
- Ubuntu 20.04+, | RHEL 8+ | or equivalent
- Ope | x86_64 architecturenSSL 3.0+
- Rust toolchain (if building from source)
On MySQL Enterprise Host (v8.0.13+, v8.4.7+ recommended):
- Ubuntu 24.04 LTS
- libaio1t64 (or libaio compatibility layer)
- libncurses-dev or libncurses6
- xz-utils
- OpenSSL 3.0+
Certificates and Keys (PKI)
For mutual TLS authentication:
- CA certificate (
ca.crt) - CA private key (
ca.key) - for signing - Server certificate with key (
kms.p12or separate files) - Client certificate for MySQL (
mysql-client.crt) - Client private key for MySQL (
mysql-client.key)
Installation and Configuration
Step 1: Prepare Eviden KMS (v5.14+)
1.1 Deploy Eviden KMS Server
Choose your Linux distribution and refer to installation guide
Verify the installed version and configuration file location:
cosmian_kms --version
cat /etc/cosmian/kms.toml
1.2 Configure KMS TOML File
Edit kms.toml:
default_username = "admin"
force_default_username = true
[logging]
otlp = "" # Disabled for lab
enable_metering = false
rust_log = "info,cosmian_kms=debug"
## rolling_log_dir = "path_to_logging_directory"
## rolling_log_dir = "path_to_logging_directory"
[tls]
tls_p12_file = "scripts/certifs/kms.p12"
tls_p12_password = "YOURTLSPASSWORD"
clients_ca_cert_file = "scripts/certifs/ca.crt"
[socket_server]
socket_server_start = true
socket_server_port = 5696
socket_server_hostname = "0.0.0.0"
[http]
port = 9998
hostname = "0.0.0.0"
[ui_config]
ui_index_html_folder = "/usr/local/cosmian/ui/dist"
kms_public_url = "https://localhost:9998"
[db]
database-type="mysql"
database-url="mysql://kms_user:kms_password@mysql-server:3306/kms"
Key Configuration Notes:
clients_ca_cert_fileis required for mTLS validationsocket_server_port5696 is standard KMIP port- Ensure database path is on persistent storage
1.3 Start Eviden KMS (v5.14+)
export COSMIAN_KMS_CONF=/path/to/kms.toml
RUST_LOG=INFO ./cosmian_kms > /tmp/kms.log 2>&1 &
# Verify listening ports
ss -lntp | grep cosmian_kms
# Expected output:
# LISTEN ... :5696 ... cosmian_kms (KMIP socket)
# LISTEN ... :9998 ... cosmian_kms (HTTP API)
Step 2: Prepare MySQL Enterprise Host (v8.0.13+, v8.4.7+ recommended)
2.1 Install Prerequisites
# On MySQL host
sudo apt update
sudo apt install -y libaio1t64 libncurses-dev xz-utils openssl
# Create libaio compatibility symlink for Ubuntu 24.04
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 \
/usr/lib/x86_64-linux-gnu/libaio.so.1
2.2 Extract MySQL Enterprise Binary (v8.0.13+)
cd /usr/local
# For MySQL 8.4.7:
sudo tar xvf /tmp/mysql-commercial-8.4.7-linux-glibc2.28-x86_64.tar.xz
# Or for MySQL 8.0.x (8.0.13+):
# sudo tar xvf /tmp/mysql-commercial-8.0.xx-linux-glibc2.28-x86_64.tar.xz
sudo ln -sf mysql-commercial-8.4.7-linux-glibc2.28-x86_64 mysql
sudo chown -R mysql:mysql /usr/local/mysql*
2.3 Create MySQL System User and Directories
sudo groupadd mysql 2>/dev/null || true
sudo useradd -r -g mysql -s /bin/false mysql 2>/dev/null || true
sudo mkdir -p /var/lib/mysql-data /var/log/mysql /var/run/mysqld
sudo chown -R mysql:mysql /var/lib/mysql-data /var/log/mysql /var/run/mysqld
2.4 Initialize MySQL Data Directory
cd /usr/local/mysql
sudo -u mysql ./bin/mysqld \
--initialize \
--user=mysql \
--datadir=/var/lib/mysql-data \
--log-error=/var/log/mysql/mysqld.log
# Capture temporary root password
grep "temporary password" /var/log/mysql/mysqld.log
# Save this password for next step
Step 3: Configure KMIP Client Certificates
3.1 Generate MySQL Client Certificate
# On a machine with CA key access
cd /path/to/pki
# Generate MySQL client private key
openssl genrsa -out mysql-client.key 4096
# Create Certificate Signing Request
openssl req -new \
-key mysql-client.key \
-out mysql-client.csr \
-subj "/CN=mysql-kmip-client/O=Lab/C=FR"
# Sign with CA
openssl x509 -req \
-in mysql-client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out mysql-client.crt \
-days 365 \
-sha256
# Resulting files:
# - mysql-client.crt (client certificate)
# - mysql-client.key (client private key)
# - ca.crt (CA certificate - already existing)
3.2 Copy Certificates to MySQL Host
# From PKI machine to MySQL host
scp mysql-client.crt mysql-client.key ca.crt \
user@mysql-host:/tmp/
# On MySQL host
sudo mkdir -p /usr/local/mysql/mysql-keyring-okv/ssl
sudo cp /tmp/mysql-client.crt /usr/local/mysql/mysql-keyring-okv/ssl/cert.pem
sudo cp /tmp/mysql-client.key /usr/local/mysql/mysql-keyring-okv/ssl/key.pem
sudo cp /tmp/ca.crt /usr/local/mysql/mysql-keyring-okv/ssl/CA.pem
# Set proper permissions
sudo chown -R mysql:mysql /usr/local/mysql/mysql-keyring-okv/ssl
sudo chmod 600 /usr/local/mysql/mysql-keyring-okv/ssl/key.pem
sudo chmod 644 /usr/local/mysql/mysql-keyring-okv/ssl/cert.pem
sudo chmod 644 /usr/local/mysql/mysql-keyring-okv/ssl/CA.pem
Step 4: Configure keyring_okv Plugin (MySQL 8.0+)
4.1 Create okvclient.ora Configuration File
# On MySQL host
sudo tee /usr/local/mysql/mysql-keyring-okv/okvclient.ora > /dev/null <<'EOF'
SERVER=<kms-host>:5696
SSL_DIR=/usr/local/mysql/mysql-keyring-okv/ssl
SSL_CERT=cert.pem
SSL_KEY=key.pem
SSL_CA=CA.pem
EOF
sudo chown mysql:mysql /usr/local/mysql/mysql-keyring-okv/okvclient.ora
sudo chmod 600 /usr/local/mysql/mysql-keyring-okv/okvclient.ora
Configuration Notes:
- Replace
<kms-host>with actual KMS hostname/IP - Port 5696 is standard KMIP port
- SSL_DIR must point to directory containing cert, key, and CA
4.2 Create MySQL Configuration File (v8.0+)
# Create /etc/my.cnf
sudo tee /etc/my.cnf > /dev/null <<'EOF'
[mysqld]
user=mysql
basedir=/usr/local/mysql
datadir=/var/lib/mysql-data
socket=/var/run/mysqld/mysqld.sock
log-error=/var/log/mysql/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
port=3306
# KMIP Keyring Plugin (MUST load early, before InnoDB)
# Available in MySQL 8.0 Enterprise Edition
early-plugin-load=keyring_okv.so
keyring_okv_conf_dir=/usr/local/mysql/mysql-keyring-okv
# Optional: Enable TDE by default for new tables (MySQL 8.0.16+)
default_table_encryption=ON
EOF
Critical Configuration Points:
early-plugin-loadmust be set before InnoDB initializationkeyring_okv_conf_dirmust point to directory withokvclient.ora- Plugin must be loaded before any encrypted tables are accessed
- Requires MySQL 8.0 Enterprise Edition
default_table_encryptionrequires MySQL 8.0.16+
4.3 Set MySQL Root Password
# Start MySQL
sudo -u mysql /usr/local/mysql/bin/mysqld \
--datadir=/var/lib/mysql-data \
--log-error=/var/log/mysql/mysqld.log \
--socket=/var/run/mysqld/mysqld.sock &
sleep 5
# Connect with temporary password (from step 2.4)
/usr/local/mysql/bin/mysql -u root -p \
--socket=/var/run/mysqld/mysqld.sock
# Enter temporary password when prompted
# Inside MySQL:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewSecurePassword123!';
FLUSH PRIVILEGES;
EXIT;
# Stop MySQL
sudo systemctl stop mysqld
sleep 3
Step 5: Start MySQL with KMS Integration
# Clean up any residual lock files
sudo rm -f /var/lib/mysql-data/*.lock
sudo rm -f /var/run/mysqld/mysqld.lock
# Start MySQL with configuration file
sudo -u mysql /usr/local/mysql/bin/mysqld \
--defaults-file=/etc/my.cnf &
sleep 5
# Verify running
ps aux | grep mysqld | grep -v grep
Capabilities and Features
Transparent Data Encryption (TDE)
Master Key Rotation
-- Rotate the master encryption key (generates new key in KMS)
ALTER INSTANCE ROTATE INNODB MASTER KEY;
Note: Rotation takes ~0.5 seconds; existing data remains accessible
Create Encrypted Tables
CREATE TABLE sensitive_data (
id INT PRIMARY KEY,
credit_card VARCHAR(20),
ssn VARCHAR(11)
) ENCRYPTION='Y';
Encrypt Existing Tables
-- Enable encryption on an unencrypted table
ALTER TABLE existing_table ENCRYPTION='Y';
Per-Tablespace Encryption (MySQL 8.0.13+)
-- Create a general tablespace with encryption (MySQL 8.0.13+)
-- All tables created in this tablespace will be encrypted
CREATE TABLESPACE ts_encrypted ADD DATAFILE 'ts_encrypted.ibd' ENCRYPTION='Y';
-- Create a table in the encrypted tablespace
CREATE TABLE secure_table (id INT PRIMARY KEY) TABLESPACE=ts_encrypted;
-- secure_table is automatically encrypted (inherits from tablespace)
-- OR encrypt an existing tablespace (MySQL 8.0.13+)
-- This affects all tables within the tablespace
ALTER TABLESPACE ts_existing ENCRYPTION='Y';
Key Management Verification
-- Check keyring plugin status
SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME = 'keyring_okv';
-- Verify encryption on table
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES
WHERE NAME = 'database/table_name';
-- Verify table definition
SHOW CREATE TABLE table_name\G
Data At Rest Verification
# Verify data is encrypted in file (no plaintext strings)
strings /var/lib/mysql-data/database/table_name.ibd | \
grep -i "sensitive_keyword" || \
echo "✓ No plaintext data found (encryption OK)"
Key Storage Architecture
- Master Key: Stored only in Eviden KMS database
- Tablespace Keys (TEK): Encrypted with master key, stored in InnoDB
- Cache: Kept in MySQL memory during runtime for performance
- Persistence: Survives MySQL restart (key retrieved from KMS)
- Security Boundary: Cache invalidated if KMS unreachable at startup
Limitations
- Single Master Key: One master encryption key per MySQL instance
- Network Dependency: KMS unavailability blocks new MySQL starts
- Cache Behavior: Data accessible from cache until MySQL restart
- No Local Fallback: Encrypted data inaccessible without KMS access at startup
- Version Requirements: Requires MySQL Enterprise 8.0+ with keyring_okv support
Testing and Validation
Test 1: Verify Plugin is Active
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock <<'EOF'
SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME = 'keyring_okv';
EOF
Expected Output:
| keyring_okv | ACTIVE |
Pass Criteria: Plugin status is ACTIVE
Test 2: Create Encrypted Table and Verify Encryption
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock <<'EOF'
-- Create encrypted table
CREATE TABLE mysql.test_tde (
id INT PRIMARY KEY,
secret VARCHAR(255)
) ENCRYPTION='Y';
-- Insert test data
INSERT INTO mysql.test_tde (id, secret) VALUES
(1, 'Sensitive-Data-001'),
(2, 'Sensitive-Data-002');
-- Retrieve data
SELECT * FROM mysql.test_tde;
-- Verify encryption setting
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES
WHERE NAME = 'mysql/test_tde';
EOF
Expected Output:
| ENCRYPTION: Y |
| STATE: normal |
Pass Criteria:
- Table created successfully
- Data inserted and retrieved
- ENCRYPTION field shows 'Y'
Test 3: Verify Data Encryption at Rest
# Verify no plaintext in datafile
strings /var/lib/mysql-data/mysql/test_tde.ibd | \
grep -i "Sensitive-Data" || \
echo "✓ No plaintext detected (encryption confirmed)"
Pass Criteria: No plaintext keywords found in binary file
Test 4: Convert Unencrypted Table to Encrypted
# Create a non-encrypted table with data
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock <<'EOF'
CREATE TABLE mysql.test_unencrypted (
id INT PRIMARY KEY,
secret VARCHAR(255)
) ENCRYPTION='N';
-- Insert test data
INSERT INTO mysql.test_unencrypted (id, secret) VALUES
(1, 'Plaintext-Data-001'),
(2, 'Plaintext-Data-002'),
(3, 'Plaintext-Data-003');
-- Verify plaintext is visible in file (for reference)
SELECT * FROM mysql.test_unencrypted;
EOF
# Verify plaintext exists before encryption
strings /var/lib/mysql-data/mysql/test_unencrypted.ibd | \
grep -i "Plaintext-Data" && echo "✓ Plaintext found (expected)"
# Now convert to encrypted
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock <<'EOF'
-- Convert table to encrypted (uses ALGORITHM=COPY internally)
ALTER TABLE mysql.test_unencrypted ENCRYPTION='Y';
-- Verify encryption is now active
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES
WHERE NAME = 'mysql/test_unencrypted';
-- Verify data is still accessible
SELECT * FROM mysql.test_unencrypted;
EOF
# Verify plaintext is now gone
strings /var/lib/mysql-data/mysql/test_unencrypted.ibd | \
grep -i "Plaintext-Data" || \
echo "✓ No plaintext found (encryption successful)"
# Restart MySQL to verify persistence
sudo systemctl stop mysqld
sleep 3
sudo -u mysql /usr/local/mysql/bin/mysqld \
--defaults-file=/etc/my.cnf &
sleep 5
# Verify data survives restart
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock \
-e "SELECT * FROM mysql.test_unencrypted;"
Pass Criteria:
- Table encryption conversion succeeds
- Data remains accessible before and after conversion
- Plaintext data encrypted at rest
- Data persists after MySQL restart
Test 5: Master Key Rotation
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock <<'EOF'
-- Rotate the master key
ALTER INSTANCE ROTATE INNODB MASTER KEY;
-- Verify table still accessible after rotation
SELECT COUNT(*) FROM mysql.test_tde;
-- Confirm data integrity
SELECT * FROM mysql.test_tde;
EOF
Expected Output:
Query OK, 0 rows affected (0.58 sec)
Pass Criteria:
- Key rotation succeeds
- Data remains accessible and intact
Test 6: Data Persistence After MySQL Restart
# Insert marker data
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock <<'EOF'
INSERT INTO mysql.test_tde (id, secret) VALUES (999, 'Persistence-Check');
SELECT COUNT(*) as row_count FROM mysql.test_tde;
EOF
# Restart MySQL
sudo systemctl stop mysqld
sleep 3
sudo -u mysql /usr/local/mysql/bin/mysqld \
--defaults-file=/etc/my.cnf &
sleep 5
# Verify data survived
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock <<'EOF'
SELECT * FROM mysql.test_tde WHERE id = 999;
SELECT COUNT(*) as rows_after_restart FROM mysql.test_tde;
EOF
Expected Output:
| id | secret |
|-----|--------------------|
| 999 | Persistence-Check |
rows_after_restart: (same as before restart)
Pass Criteria:
- Data persists after MySQL restart
- Master key successfully retrieved from KMS
- Row count unchanged
Test 7: TLS Communication Verification
# Test direct TLS connection to KMS KMIP endpoint
timeout 5 openssl s_client -connect <kms-host>:5696 \
-cert /usr/local/mysql/mysql-keyring-okv/ssl/cert.pem \
-key /usr/local/mysql/mysql-keyring-okv/ssl/key.pem \
-CAfile /usr/local/mysql/mysql-keyring-okv/ssl/CA.pem \
< /dev/null 2>&1 | grep "Verify return code"
Expected Output:
Verify return code: 0 (ok)
Pass Criteria: TLS handshake succeeds with valid certificates
Advanced Resilience Testing
Resilience Test 1: KMS Unavailability with MySQL Running
Scenario: Brief KMS outage while MySQL is operational
# Step 1: Verify data accessible (KMS running)
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock \
-e "SELECT COUNT(*) FROM mysql.test_tde;"
# Step 2: Stop KMS
systemctl stop cosmian_kms
# Step 3: Verify data still accessible (from cache)
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock \
-e "SELECT COUNT(*) FROM mysql.test_tde;"
# ✓ Data accessible (master key in MySQL memory cache)
# Step 4: Restart KMS
systemctl start cosmian_kms
# Step 5: Verify access continues
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock \
-e "SELECT * FROM mysql.test_tde LIMIT 1;"
Results:
✓ Data accessible while KMS down (cache hit)
✓ Data accessible after KMS restart
✓ No service interruption during brief outage
Resilience Test 2: KMS Unavailability with MySQL Restart
Scenario: KMS down when MySQL starts (critical test)
# Step 1: Verify KMS is stopped
ps aux | grep cosmian_kms | grep -v grep
# (should return nothing)
# Step 2: Restart MySQL (KMS OFFLINE)
sudo systemctl stop mysqld
sleep 3
sudo -u mysql /usr/local/mysql/bin/mysqld \
--defaults-file=/etc/my.cnf &
sleep 5
# Step 3: Try to access encrypted data
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock \
-e "SELECT * FROM mysql.test_tde;" 2>&1
Expected Error:
ERROR 3185 (HY000): Can't find master key from keyring,
please check in the server log if a keyring is loaded and initialized successfully.
Result:
✓ Security working correctly
✓ Encrypted data inaccessible without KMS
✓ MySQL started but cannot decrypt
Resilience Test 3: Recovery After KMS Outage + Restart
Scenario: Full recovery workflow after KMS was offline
# Step 1: KMS is still down, MySQL started with error above
# Step 2: Start KMS (v5.14+)
systemctl start cosmian_kms
# Step 3: MySQL still cannot access (cache was invalidated)
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock \
-e "SELECT * FROM mysql.test_tde;" 2>&1
# Still ERROR 3185
# Step 4: Restart MySQL to reconnect to KMS
sudo systemctl stop mysqld
sleep 3
sudo -u mysql /usr/local/mysql/bin/mysqld \
--defaults-file=/etc/my.cnf &
sleep 5
# Step 5: Data now accessible
/usr/local/mysql/bin/mysql -u root -pYourPassword \
--socket=/var/run/mysqld/mysqld.sock \
-e "SELECT * FROM mysql.test_tde;"
Results:
✓ KMS restart does NOT automatically recover cached state
✓ MySQL restart required to re-establish KMS connection
✓ Data fully recoverable with proper startup order
Lessons Learned:
- Keep KMS and MySQL in sync (start/stop in order)
- Monitor KMS availability separately
- Set up automated alerts for KMS downtime
TDE Benchmark Report (1,000,000 rows)
Execution Times
| Operation | Encrypted Table (TDE) | Non-Encrypted Table | TDE Overhead |
|---|---|---|---|
| Bulk INSERT | 12.11 s | 11.05 s | +9% |
| Full scan SELECT (cold cache) | 2.06 s | 1.41 s | +47% |
| Full scan SELECT (warm cache) | 2.26 s | 1.46 s | +55% |
| Lookup SELECT (PK, warm) | 0.018 s | 0.015 s | ≈ 0% |
Performance by Workload Type
| Workload Type | TDE Impact | Comments |
|---|---|---|
| OLTP (INSERT / PK lookup) | 🟢 Low | Overhead negligible in production |
| Sequential scan | 🟠 Moderate | Crypto cost visible, especially with warm cache |
| Analytical (aggregations) | 🔴 Higher | CPU-bound, plan for extra CPU resources |
Troubleshooting
Issue: "Can't find master key from keyring"
Symptom:
ERROR 3185 (HY000): Can't find master key from keyring,
please check in the server log if a keyring is loaded and initialized successfully.
Root Causes:
- Eviden KMS (v5.14+) is not running or unreachable
- Network connectivity issue between MySQL and KMS
- Certificate authentication failed
- Plugin failed to initialize
Solutions:
-
Verify Eviden KMS (v5.14+) is running:
ps aux | grep cosmian_kms | grep -v grep ss -lntp | grep 5696 -
Check network connectivity:
nc -zv <kms-host> 5696 ping <kms-host> -
Verify certificate validity:
openssl x509 -in /usr/local/mysql/mysql-keyring-okv/ssl/cert.pem -text -noout # Check NotBefore and NotAfter dates -
Check MySQL error log:
tail -n 100 /var/log/mysql/mysqld.log | grep -i "keyring\|error\|tls" -
Verify okvclient.ora configuration:
cat /usr/local/mysql/mysql-keyring-okv/okvclient.ora -
Verify MySQL Enterprise version has keyring_okv support:
/usr/local/mysql/bin/mysql --version # Must be MySQL 8.0 Enterprise Edition or higher
Issue: "Encryption information can't be decrypted"
Symptom:
ERROR 12226: Encryption information in datafile: ./mysql/test_tde.ibd
can't be decrypted
Causes:
- Table was created with a key that's no longer accessible
- Datafile corruption
- KMS unavailable during startup
Solutions:
-
If test/development data:
# Remove problematic datafile sudo mv /var/lib/mysql-data/mysql/test_tde.ibd \ /var/lib/mysql-data/mysql/test_tde.ibd.backup # Restart MySQL sudo systemctl stop mysqld sleep 3 sudo -u mysql /usr/local/mysql/bin/mysqld \ --defaults-file=/etc/my.cnf & # Drop table and recreate /usr/local/mysql/bin/mysql -u root -pYourPassword \ --socket=/var/run/mysqld/mysqld.sock \ -e "DROP TABLE mysql.test_tde;" -
If production data, investigate:
- Check KMS (v5.14+) availability during startup
- Verify master key is accessible
- Check certificate validity
- Review MySQL error logs
Issue: Certificate Expiry
Symptom:
SSL: CERTIFICATE_VERIFY_FAILED
Solution:
# Check certificate expiry
openssl x509 -in /usr/local/mysql/mysql-keyring-okv/ssl/cert.pem \
-noout -dates
# Generate new certificate before expiry
openssl genrsa -out mysql-client.key.new 4096
openssl req -new \
-key mysql-client.key.new \
-out mysql-client.csr.new \
-subj "/CN=mysql-kmip-client/O=Lab/C=FR"
openssl x509 -req \
-in mysql-client.csr.new \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out mysql-client.crt.new \
-days 365 \
-sha256
# Replace certificates (during maintenance window)
sudo cp mysql-client.crt.new \
/usr/local/mysql/mysql-keyring-okv/ssl/cert.pem
sudo cp mysql-client.key.new \
/usr/local/mysql/mysql-keyring-okv/ssl/key.pem
sudo chown mysql:mysql /usr/local/mysql/mysql-keyring-okv/ssl/cert.pem
sudo chown mysql:mysql /usr/local/mysql/mysql-keyring-okv/ssl/key.pem
sudo chmod 600 /usr/local/mysql/mysql-keyring-okv/ssl/key.pem
# Restart MySQL to use new certificates
sudo systemctl stop mysqld
sleep 3
sudo -u mysql /usr/local/mysql/bin/mysqld \
--defaults-file=/etc/my.cnf &
References
Official Documentation
- MySQL Enterprise Edition
- MySQL keyring_okv KMIP Plugin
- MySQL Transparent Data Encryption
- MySQL 8.0 Release Notes
- Eviden KMS Documentation
- KMIP Specification
Key Files and Paths
| Component | Path |
|---|---|
| MySQL Binary | /usr/local/mysql/bin/mysqld |
| MySQL Config | /etc/my.cnf |
| Data Directory | /var/lib/mysql-data/ |
| Error Log | /var/log/mysql/mysqld.log |
| Socket File | /var/run/mysqld/mysqld.sock |
| KMIP Config | /usr/local/mysql/mysql-keyring-okv/okvclient.ora |
| SSL Certificates | /usr/local/mysql/mysql-keyring-okv/ssl/ |
| Eviden Config | /path/to/kms.toml |
| Eviden DB | /path/to/cosmian-kms/sqlite-data/kms.db |
Default Credentials (Lab Only)
| User | Password | Scope |
|---|---|---|
| root (MySQL) | Set during installation | Local MySQL |
| admin (Eviden) | Configured in kms.toml | KMS REST API |
SECURITY NOTE: Change all default credentials before production use.
Contact and Support
For issues related to:
- MySQL Enterprise: Oracle MySQL Support
- Eviden KMS: Eviden GitHub Issues
Using pg_tde with Eviden KMS and PostgreSQL 17 (Percona)
This guide demonstrates how to configure PostgreSQL 17 with Percona's pg_tde extension to use Eviden KMS for transparent data encryption (TDE).
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.4 over TCP/TLS with mutual certificate authentication |
| Port | 5696 (IANA-registered KMIP port) |
| Key type | AES-128 symmetric key |
| PostgreSQL version | Percona Server for PostgreSQL 17.x and above |
| Eviden KMS feature | Works with both FIPS and non-FIPS builds |
Prerequisites
Before starting, ensure you have:
- PostgreSQL 17 Percona Server for PostgreSQL 17.x or later
pg_tdeextension installed- Access to a running Eviden KMS server
- Appropriate SSL certificates for KMIP communication TLS 1.2+
Before You Start: Understanding pg_tde Architecture
Global Architecture Overview
flowchart TB
app["Application / SQL Queries<br/>(SELECT, INSERT, UPDATE, DELETE)"]
plain["Data in plaintext in memory"]
subgraph pg["PostgreSQL + pg_tde Extension + Percona Patches"]
smgr["SMGR (Storage Manager) — Interception Layer"]
tde["TDE Tables<br/>(USING tde_heap)"]
nontde["Non-TDE Tables<br/>(standard heap)"]
enc["Encryption of pages<br/>(CBC-128)"]
noenc["No encryption"]
walenc["Encryption (optional, WAL only)<br/>(CTR-128) WAL"]
smgr --> tde & nontde
tde --> enc
nontde --> noenc & walenc
end
disk["Disk (encrypted data)<br/>WAL Files (encrypted if pg_tde.wal_encrypt = on)"]
app --> plain --> smgr
enc --> disk
noenc --> disk
walenc --> disk
KMIP Communication Flow
flowchart TB
pg["PostgreSQL + pg_tde<br/>(KMIP Client)"]
kms["Eviden KMS 5.6+<br/>(KMIP Server)<br/><br/>Supported operations:<br/>✓ Create · Get · Destroy · Register<br/>✓ Locate · Activate · Revoke<br/><br/>Protocol: KMIP 1.x and 2.x<br/>Profile: Baseline Server"]
pg -->|"KMIP over TLS 1.2/1.3<br/>Port 5696 (binary)<br/>Required: client_cert.pem, client_key.pem, ca_cert.pem"| kms
Configuration Steps
1. Configure PostgreSQL
Edit your postgresql.conf file to activate the TDE extension:1
shared_preload_libraries = 'pg_tde,percona_pg_telemetry'
Important: Changes to shared_preload_libraries require a PostgreSQL restart to take effect.1
sudo systemctl restart postgresql@17-main.service
2. Enable TDE Extension
Create the pg_tde extension in your target database(s):1
CREATE EXTENSION pg_tde;
This will automatically create event triggers needed for pg_tde operation.
3. Configure the KMS Key Provider
Connect to your PostgreSQL database and add the Eviden KMS as a key provider using the KMIP protocol:1
SELECT pg_tde_add_global_key_provider_kmip(
'kms_provider', -- Provider name (can be customized)
'kms-host.example.com', -- Your KMS server hostname
5696, -- KMIP port (default is 5696)
'/path/to/client_cert.pem', -- Client certificate file path
'/path/to/client_key.pem', -- Client private key file path
'/path/to/ca_cert.pem' -- Certificate Authority file path
);
Note: Replace the placeholder values with your actual KMS server details and certificate paths.1
Certificate Requirements:2
- All certificates must be in PEM format
- Client certificates must be X.509 compliant
- TLS 1.2 or higher is required for KMIP communication
- Certificate files must be readable by the PostgreSQL system user
4. Set the Default Encryption Key
Configure the default encryption key using the KMS provider:1
SELECT pg_tde_create_key_using_global_key_provider('key_01', 'kms_provider');
SELECT pg_tde_set_server_key_using_global_key_provider('key_01', 'kms_provider');
SELECT pg_tde_set_default_key_using_global_key_provider('key_01', 'kms_provider');
The first parameter (key_01) is the key identifier, and the second parameter (kms_provider) must match the provider name from step 3.1
What happens in this step:
pg_tde_create_key_using_global_key_provider()creates a Principal Key managed by Eviden KMSpg_tde_set_server_key_using_global_key_provider()sets the server-level default keypg_tde_set_default_key_using_global_key_provider()sets the database-level default key
5. Ensure Event Triggers Are Set
Event triggers are usually created automatically when the extension is installed. To verify or recreate them:1
CREATE EVENT TRIGGER pg_tde_ddl_start ON ddl_command_start
EXECUTE FUNCTION pg_tde_ddl_command_start_capture();
CREATE EVENT TRIGGER pg_tde_ddl_end ON ddl_command_end
EXECUTE FUNCTION pg_tde_ddl_command_end_capture();
If the trigger already exists, this error can be safely ignored.1
These triggers ensure that DDL operations (table creation, modification) properly handle encryption metadata.
6. Enable WAL Encrypt and TDE Enforce Encryption
Edit your postgresql.conf again and add:1
pg_tde.wal_encrypt = on
pg_tde.enforce_encryption = on
Important: Changes to pg_tde.wal_encrypt or pg_tde.enforce_encryption require a PostgreSQL restart to take effect.1
sudo systemctl restart postgresql@17-main.service
About these parameters:1
pg_tde.wal_encrypt = onencrypts Write-Ahead Log files (production-ready as of Percona PostgreSQL 17.5.3)pg_tde.enforce_encryption = onprevents creation of unencrypted tables when a default key is set (strongly recommended)
7. Create Encrypted Tables
CREATE TABLE sensitive_data (
id serial PRIMARY KEY,
secret_text text
) USING tde_heap;
The USING tde_heap clause ensures the table is encrypted using pg_tde.1
Important: Only tables created with USING tde_heap are encrypted. Existing non-TDE tables remain unencrypted unless migrated.
8. Verify if a Table is Encrypted
SELECT pg_tde_is_encrypted('public.sensitive_data'::regclass);
-- Expected output: t (true)
9. Insert and Query Data Transparently
Encryption is transparent; use standard SQL commands:1
INSERT INTO sensitive_data (secret_text) VALUES ('Top secret info');
SELECT * FROM sensitive_data;
Data is stored encrypted on disk but returned in plaintext when queried.1
10. Check Current Encryption Settings
SHOW pg_tde.wal_encrypt;
SHOW pg_tde.enforce_encryption;
SHOW pg_tde.inherit_global_providers;
Encryption Scope and What Gets Encrypted
✅ WHAT IS ENCRYPTED
Application Data
| Component | Status | Details |
|---|---|---|
Tables USING tde_heap | ✓ Encrypted | Complete row data, all columns3 |
| Index on TDE tables | ✓ Encrypted | B-trees, Hash, GiST, GIN, BRIN, etc.3 |
| TOAST tables | ✓ Encrypted | Compressed/out-of-page data e.g. long TEXT |
| Sequences (TDE tables) | ✓ Encrypted | Related to encrypted tables3 |
| Temporary tables (TDE) | ✓ Encrypted | Temporary tables for TDE data operations3 |
Logs and Transactions
| Component | With pg_tde.wal_encrypt = on | Details |
|---|---|---|
| WAL (Write-Ahead Log) | ✓ Encrypted | Transaction logs GA status since v17.5.3 |
| WAL before images | ✓ Encrypted | Row states before modification4 |
| WAL after images | ✓ Encrypted | Row states after modification4 |
Backup and Recovery
| Tool | Status | Notes |
|---|---|---|
pg_tde_basebackup | ✓ Supported | With --wal-method=stream or --wal-method=none1 |
pgBackRest | ✓ Supported | Compatible with encrypted WAL4 |
| WAL restore | ✓ Supported | Via pg_tde_restore_encrypt wrapper1 |
❌ WHAT IS NOT ENCRYPTED
System Metadata and Catalogs
| Component | Reason | Consequence |
|---|---|---|
| PostgreSQL system catalogs | Architectural | Table/column names, types remain plaintext |
| TDE table metadata | Architectural | Schema, table name, column name, data types |
Statistics (pg_stat_*) | Not supported | System statistics information |
| Configuration files | Not encrypted | postgresql.conf, pg_hba.conf |
Tables and Files
| Component | Reason | Solution |
|---|---|---|
Standard heap tables | By design | Only tde_heap tables are encrypted |
| Non-TDE tables | Selective | Create with USING tde_heap for encryption |
| Temporary files (>work_mem) | Limitation | Overflow data unencrypted on disk[5] |
| System log files | Not supported | PostgreSQL logs in plaintext on disk |
Key Management: DEK, Internal Keys and Principal Keys
Two-Level Key Architecture
pg_tde uses a two-level key hierarchy for data encryption:3
flowchart TB
principal["PRINCIPAL KEY (Master Key)<br/><br/>Stored externally in Eviden KMS via KMIP<br/>ONE per database<br/>Encrypts Internal Keys (AES-128-GCM)<br/>Accessible only via TLS KMIP connection<br/><br/>Created with pg_tde_create_key_using_global_key_provider()"]
internal["INTERNAL KEYS (Data Encryption Keys / DEK)<br/><br/>Stored locally in $PGDATA/pg_tde/<br/>Encrypted by Principal Key<br/>ONE unique key per relation (OID)<br/><br/>Tables: AES-128-CBC · WAL: AES-128-CTR · Keys: AES-128-GCM"]
data["ENCRYPTED DATA (User Data)<br/><br/>Table pages stored encrypted on disk<br/>Index pages stored encrypted<br/>WAL data encrypted (if pg_tde.wal_encrypt = on)"]
principal -->|"Encrypts via KMIP wrap (AES-128-GCM)"| internal
internal -->|"Encrypt (AES-128-CBC / CTR)"| data
Internal Keys (DEK) Details
Generation and Storage
| Aspect | Detail |
|---|---|
| Generation | Automatic when CREATE TABLE ... USING tde_heap3 |
| Identifier | Unique OID (Object Identifier) per relation3 |
| Location | $PGDATA/pg_tde/<database_oid>/3 |
| File | <relation_oid>.key binary, encrypted |
| Visibility | Not readable directly without Principal Key3 |
| Rotation | Via VACUUM FULL, ALTER TABLE SET ACCESS METHOD, or CREATE TABLE AS SELECT3 |
Disk Structure Example
$PGDATA/pg_tde/
├── global/ # Global section
│ ├── provider_config # Global provider configuration
│ └── server_key.key # WAL server key (if enabled)
│
└── 16384/ # Database OID (example)
├── provider_config # Database provider configuration
├── 16385.key # Internal key for table OID=16385
├── 16386.key # Internal key for index OID=16386
├── 16387.key # Internal key for index OID=16387
├── 16388.key # Internal key for TOAST OID=16388
└── 16389.key # Internal key for sequence OID=16389
Security Considerations
| Aspect | Detail | Recommendation |
|---|---|---|
| File Permissions | Inherited from $PGDATA pg:pg 700 | ✓ Good, ensure root cannot read |
| Backup Protection | DEK files copied with backup remain encrypted | ✓ Safe for off-site storage |
| RAM Cache | Principal Key and DEKs decrypted in RAM3 | ⚠️ Protect with: lock_memory, disable core dumps |
| Swap Memory | Keys can be paged to swap3 | ⚠️ Use encrypted swap (dm-crypt, zswap) |
Recommended Protections
# 1. Disable core dumps
echo "kernel.core_pattern = /dev/null" >> /etc/sysctl.conf
sysctl -p
# 2. Encrypt swap (optional but recommended)
# Use dm-crypt or zswap
# 3. Lock PostgreSQL memory (optional but recommended)
ulimit -l unlimited
# or in postgresql.conf:
# lock_memory = true
# 4. Secure KMS certificates
sudo chmod 400 /path/to/client_cert.pem
sudo chmod 400 /path/to/client_key.pem
sudo chown postgres:postgres /path/to/*.pem
Key Monitoring
Verify Current Keys
-- Check server default Principal Key
SELECT pg_tde_server_key_info();
-- Result: (key_name, provider_name)
-- Check current database Principal Key
SELECT pg_tde_key_info();
-- Check default Principal Key (if used)
SELECT pg_tde_default_key_info();
-- List all configured providers
SELECT * FROM pg_tde_list_all_global_key_providers();
SELECT * FROM pg_tde_list_all_database_key_providers();
Verify KMS Connectivity
-- Test Principal Key availability
SELECT pg_tde_verify_key();
SELECT pg_tde_verify_server_key();
SELECT pg_tde_verify_default_key();
-- If these fail: Check PostgreSQL logs for KMIP errors
-- tail -f $PGDATA/log/postgresql.log | grep -i kmip
Verification and Testing
Initial Setup Verification
-- 1. Verify extension is loaded
SELECT * FROM pg_extension WHERE extname = 'pg_tde';
-- 2. Verify configuration parameters
SHOW shared_preload_libraries;
SHOW pg_tde.wal_encrypt;
SHOW pg_tde.enforce_encryption;
-- 3. Verify KMS provider is configured
SELECT * FROM pg_tde_list_all_global_key_providers();
-- 4. Verify keys are set
SELECT pg_tde_server_key_info();
SELECT pg_tde_default_key_info();
-- 5. Verify KMS connectivity
SELECT pg_tde_verify_key();
SELECT pg_tde_verify_server_key();
-- 6. Create test table
CREATE TABLE test_encrypted (
id serial PRIMARY KEY,
data text
) USING tde_heap;
-- 7. Verify it's encrypted
SELECT pg_tde_is_encrypted('public.test_encrypted'::regclass);
-- Expected output: t (true)
-- 8. Test data insertion and retrieval
INSERT INTO test_encrypted (data) VALUES ('Test data');
SELECT * FROM test_encrypted;
-- Data should be returned in plaintext
WAL Encryption Verification
-- Check if WAL encryption is enabled
SHOW pg_tde.wal_encrypt;
-- Verify encryption is active
SELECT pg_tde_is_wal_encrypted();
-- Check WAL files (encrypted WAL segments have standard naming)
SELECT name FROM pg_ls_waldir()
ORDER BY name DESC LIMIT 5;
Troubleshooting & Solutions
Common Issues and Diagnostic Flow
1. PostgreSQL Fails to Start
ERROR: could not load shared library "pg_tde"
or
ERROR: could not connect to KMIP server
Diagnostic steps:
# 1. Check if extension is compiled correctly
ls -la $PGINSTALL/lib/pg_tde.so
# 2. Check PostgreSQL logs
tail -f $PGDATA/log/postgresql.log
# 3. Verify KMS is reachable
telnet <kms-host> 5696
# 4. Check certificate paths
ls -la /path/to/*.pem
file /path/to/client_cert.pem
SQL Verification:
SELECT pg_tde_verify_key();
SELECT pg_tde_verify_server_key();
SELECT * FROM pg_tde_list_all_global_key_providers();
Solutions:
- Verify
shared_preload_librariescontainspg_tde - Restart PostgreSQL after configuration changes
- Ensure Eviden KMS is running:
telnet <kms-host> 5696 - Check firewall/network between PostgreSQL and KMS
2. TLS Certificate Verification Failed
ERROR: SSL/TLS certificate verification failed
DETAIL: certificate verify failed / self signed certificate
Diagnostic:
# Verify certificate details
openssl x509 -in /path/to/ca_cert.pem -text -noout
# Check certificate expiration
openssl x509 -in /path/to/client_cert.pem -noout -dates
# Verify certificate chain
openssl verify -CAfile /path/to/ca_cert.pem /path/to/client_cert.pem
# Test KMIP connection manually (if PyKMIP available)
python3 -m kmip.demos.client -b /path/to/client_cert.pem \
-k /path/to/client_key.pem \
-ca /path/to/ca_cert.pem \
--server <kms-host> --port 5696
Solutions:
- Verify certificate files exist and are readable:
ls -la /path/to/*.pem - Check certificate expiration dates
- Verify CA certificate chain is complete
- Ensure certificate paths in
pg_tde_add_global_key_provider_kmip()are correct
3. Key Not Found or Access Denied
ERROR: Failed to retrieve principal key 'key_01' from KMS provider 'kms_provider'
DETAIL: Key not found / Access denied
Diagnostic:
-- Verify KMS connectivity
SELECT pg_tde_verify_key();
SELECT pg_tde_verify_server_key();
-- Check configured keys
SELECT pg_tde_key_info();
SELECT pg_tde_server_key_info();
-- Check provider configuration
SELECT * FROM pg_tde_list_all_global_key_providers();
Solutions:
- Verify the key exists on Eviden KMS
- Verify the key name matches exactly (case-sensitive)
- Check KMS user/role has permissions to access the key
- Verify database OID if using database-level keys:
SELECT datoid FROM pg_database WHERE datname = current_database(); - Check
$PGDATA/pg_tde/directory permissions
4. Performance Degradation After Enabling TDE
Problem: Slower queries, high CPU usage
Diagnostic:
-- Check cache hit ratio
SELECT sum(heap_blks_read) / (sum(heap_blks_read) +
sum(heap_blks_hit)) AS cache_hit_ratio
FROM pg_stat_user_tables;
-- Check query plans
EXPLAIN ANALYZE SELECT * FROM sensitive_data LIMIT 1000;
Solutions:
-
Increase
shared_buffersto reduce disk I/O -
Check CPU supports AES-NI (hardware acceleration):
grep -o 'aes' /proc/cpuinfo | head -1 -
Monitor I/O performance with
iostat -x 1 -
Note: Percona reports ~10% overhead in most cases4
Certificate Management Best Practices
# 1. Organize certificate files
mkdir -p /etc/postgresql/kmip-certs
sudo cp /path/to/*.pem /etc/postgresql/kmip-certs/
sudo chmod 400 /etc/postgresql/kmip-certs/*.pem
sudo chown postgres:postgres /etc/postgresql/kmip-certs/
# 2. Set correct paths in pg_tde configuration
SELECT pg_tde_add_global_key_provider_kmip(
'kms_provider',
'kms-host.example.com',
5696,
'/etc/postgresql/kmip-certs/client_cert.pem',
'/etc/postgresql/kmip-certs/client_key.pem',
'/etc/postgresql/kmip-certs/ca_cert.pem'
);
# 3. Monitor certificate expiration
openssl x509 -in /etc/postgresql/kmip-certs/client_cert.pem -noout -dates | \
grep notAfter
# 4. Plan certificate rotation before expiration
# Test with new certificates before cutover
Operational Considerations
Migration from Non-TDE to TDE Tables
flowchart TB
start["Migration: non-TDE → TDE table"]
m1["Method 1: CREATE TABLE AS"]
m2["Method 2: ALTER TABLE"]
m1a["CREATE TABLE t_new USING tde_heap<br/>AS SELECT * FROM t_old"]
m2a["ALTER TABLE t_old<br/>SET ACCESS METHOD tde_heap"]
m1b["DROP TABLE t_old<br/>ALTER TABLE t_new RENAME TO t_old"]
m2b["Recreates index, constraints, foreign keys"]
done["✓ TDE table created (exclusive lock)"]
start --> m1 & m2
m1 --> m1a --> m1b --> done
m2 --> m2a --> m2b --> done
Impact:
- Exclusive lock on table during migration
- Complete data rewrite
- Time proportional to table size
- Disk usage x2 during operation
Recommendation: Perform during maintenance window on production systems.
Key Rotation
Principal Key Rotation
-- 1. Create new key on Eviden KMS
SELECT pg_tde_create_key_using_global_key_provider(
'key_02', 'kms_provider'
);
-- 2. Switch to new key
-- (Re-encrypts all internal keys)
SELECT pg_tde_set_default_key_using_global_key_provider(
'key_02', 'kms_provider'
);
-- 3. Verify rotation is complete
SELECT pg_tde_default_key_info();
-- 4. Old key can be archived/destroyed after verification
-- (Eviden KMS: key revoke/destroy operations)
Notes:
- Internal keys are re-encrypted (non-blocking operation)
- Old key retained for recovery purposes
- Does not re-encrypt user data (only wraps internal keys)
- Minimal performance impact
Internal Key Rotation (Existing Tables)
No direct in-place internal key rotation. Use one of these workarounds:
-- Method 1: VACUUM FULL (simpler but locks table)
VACUUM FULL sensitive_data;
-- Note: Table remains in memory during operation
-- Method 2: CREATE TABLE AS (more controlled)
CREATE TABLE sensitive_data_new USING tde_heap AS
SELECT * FROM sensitive_data;
-- Recreate indexes
CREATE INDEX idx_sensitive_data_id ON sensitive_data_new(id);
-- Swap tables
DROP TABLE sensitive_data;
ALTER TABLE sensitive_data_new RENAME TO sensitive_data;
-- Verify new encryption
SELECT pg_tde_is_encrypted('public.sensitive_data'::regclass);
Performance Comparison:
| Method | Lock Duration | Disk I/O | Downtime |
|---|---|---|---|
| VACUUM FULL | Full table | Low | Minimal |
| CREATE TABLE AS | Full table | High (copy all) | Moderate |
Backup and Recovery
Physical Backup with Encrypted WAL
# Full backup with streaming WAL
pg_tde_basebackup -D /path/to/backup \
--wal-method=stream \
-R \
-v
# Or with archived WAL (requires WAL archiving configured)
pg_tde_basebackup -D /path/to/backup \
--wal-method=none \
-R
# WAL archiving setup (in postgresql.conf)
archive_mode = on
archive_command = 'pg_tde_archive_decrypt %f %p | pgbackrest archive-push %p'
# WAL restore setup (in recovery.conf or postgresql.conf)
restore_command = 'pgbackrest archive-get %f %p'
Recovery Point Objective (RPO)
flowchart TB
base["pg_tde_basebackup (baseline)"]
wal["WAL segments (archived via archive_command)"]
pitr["Allows PITR up to last WAL segment"]
rpo["RPO = 1 WAL segment (16 MB by default)<br/>TO = Time to replay WAL"]
base --> wal --> pitr --> rpo
Failover and Standby Setup
Standby Configuration with Patroni
# patroni.yml for pg_tde with Eviden KMS
postgresql:
# Use pg_tde_rewind, NOT standard pg_rewind if WAL encrypted
pg_rewind: pg_tde_rewind
parameters:
shared_preload_libraries: pg_tde
pg_tde.wal_encrypt: on
pg_tde.enforce_encryption: on
# Archive settings
archive_mode: on
archive_command: "pg_tde_archive_decrypt %f %p | pgbackrest archive-push %p"
restore_command: "pgbackrest archive-get %f %p"
Failover Considerations
| Aspect | Impact | Solution |
|---|---|---|
| KMS Availability | Critical | Primary and standby must both access KMS |
| Certificates | Critical | Distribute certificates to all replicas |
| Principal Key | Critical | Key must be accessible during recovery |
| Encrypted WAL | High | Use pg_tde_rewind not standard pg_rewind[5] |
Important: If using encrypted WAL, pg_rewind is incompatible. Use pg_tde_rewind instead.[5]
Eviden KMS Compatibility
Supported features with pg_tde:2
- KMIP 1.x and 2.x protocols
- Baseline Server profile (fully compliant)
- AES-128-CBC, AES-128-CTR, AES-128-GCM algorithms
- Key creation, retrieval, destruction, rotation
- TLS 1.2+ for secure communication
Backup and Replication Tools Compatibility:
| Tool | With WAL Encryption | Notes |
|---|---|---|
| pg_tde_basebackup | ✓ Supported1 | Recommended tool |
| pgBackRest | ✓ Supported4 | Production-ready |
| Patroni | ✓ Supported4 | Use pg_tde_rewind |
| pg_rewind | ✗ Incompatible[5] | Use pg_tde_rewind instead |
| pg_createsubscriber | ✗ Incompatible[5] | Create subscriber manually |
| pg_receivewal | ✗ Incompatible[5] | Use pgBackRest or Patroni |
| Barman | ✗ Incompatible[5] | Use pgBackRest instead |
Ongoing Maintenance
-
Monitor KMS connectivity:
SELECT pg_tde_verify_key(); -
Plan key rotation:
- Principal keys: Via Eviden KMS management
- Internal keys: Via table recreation (VACUUM FULL or ALTER TABLE SET ACCESS METHOD)
-
Backup strategy:
- Use
pg_tde_basebackuporpgBackRest - Archive encrypted WAL files
- Test recovery procedures regularly
- Use
-
Certificate rotation:
- Plan before expiration
- Test with new certificates before cutover
References
- Percona pg_tde Documentation
- Eviden KMS KMIP Support
- Percona pg_tde Architecture
- Percona WAL Encryption Blog (2025-09-01)
- Percona pg_tde Limitations
Official Documentation Links
Eviden KMS integrates with Microsoft SQL Server External key management using a Windows DLL implementing the SQL Server Extensible Key Management (EKM).
The Windows DLL is a SQL Server EKM provider that forwards key operations to the Eviden KMS over mutual TLS. This allows SQL Server features like column-level encryption and Transparent Data Encryption (TDE) to use keys managed by the Eviden KMS, without exposing key material to the SQL Server host.
The Windows DLL is available in a separate project on GitHub; pre-built signed DLLs are available for download.
Deployment Guide
This document explains how to install and configure the Cosmian EKM SQL Server provider, starting from a signed DLL. Follow the steps in order.
Prerequisites
| Requirement | Notes |
|---|---|
| Windows Server 2016+ or Windows 10/11 | x64 |
| SQL Server 2016+ (any edition) with EKM support | Standard or Enterprise; Express does not support EKM |
| Eviden KMS 5.x | Must run on the same machine (or be network-reachable) |
Signed cosmian_ekm_sql_server.dll | See the KMS repository for build instructions |
| PowerShell 5.1 (elevated) | For the setup scripts |
sqlcmd on the system PATH | Part of SQL Server Tools or installable standalone |
1. Install SQL Server
Install SQL Server with default settings. The instance name used throughout
this guide is the default instance (MSSQLSERVER). For a named instance,
substitute MSSQL$<InstanceName> wherever a service name is needed.
Ensure the SQL Server Database Engine service account is noted
(default: NT SERVICE\MSSQLSERVER).
2. Start the Eviden KMS
The KMS must be running and accessible before SQL Server loads the EKM provider.
# Example — adjust paths and config file as needed
cosmian_kms_server.exe --config kms_server.toml
The KMS must be configured with:
- TLS certificate trusted by this machine (or
accept_invalid_certs = trueinconfig.tomlduring development) - At least one client certificate entry matching the SQL Server credential identity
Verify the KMS is reachable:
Test-NetConnection -ComputerName localhost -Port 9998
3. Prepare the machine (one-time)
# Creates directories and grants ACLs to the SQL Server service account
scripts\Initialize-EkmEnvironment.ps1
# Creates the Authenticode code-signing certificate (if not already present)
scripts\New-EkmCertificate.ps1
These are one-time operations per machine.
4. Install the provider configuration
Create C:\ProgramData\Cosmian\EKM\config.toml (see
config.toml.example for the full schema):
max_age_seconds = 1800
stale_collector_period_seconds = 120
[kms]
server_url = "https://localhost:9998"
accept_invalid_certs = false # set true only for local dev
[[kms.certificates]]
username = "admin"
client_cert = 'C:\ProgramData\Cosmian\EKM\admin.cert.pem'
client_key = 'C:\ProgramData\Cosmian\EKM\admin.key.pem'
Copy the mTLS client certificate and key files to the paths referenced above, and copy the KMS CA certificate so TLS verification succeeds.
5. Deploy the DLL
# Must be run as Administrator
scripts\Deploy-EkmDll.ps1
This script:
- Verifies the DLL's Authenticode signature.
- Stops the
MSSQLSERVERservice. - Copies the DLL to
C:\Program Files\Cosmian\EKM\cosmian_ekm_sql_server.dll. - Starts the
MSSQLSERVERservice. - Registers (or re-registers)
CosmianEKMas a cryptographic provider.
To deploy to a named instance or skip the service restart:
scripts\Deploy-EkmDll.ps1 -SqlServiceName "MSSQL`$MyInstance"
scripts\Deploy-EkmDll.ps1 -SkipServiceRestart # register only
6. Enable EKM in SQL Server
Connect to SQL Server (e.g. via SSMS or sqlcmd) and run:
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'EKM provider enabled', 1;
RECONFIGURE;
7. Register the provider
If Deploy-EkmDll.ps1 was run with -SkipRegistration, register manually:
CREATE CRYPTOGRAPHIC PROVIDER CosmianEKM
FROM FILE = 'C:\Program Files\Cosmian\EKM\cosmian_ekm_sql_server.dll';
Verify:
SELECT name, is_enabled FROM sys.cryptographic_providers WHERE name = 'CosmianEKM';
8. Create a credential and map it to a login
Each SQL Server login that uses EKM keys must have a credential that maps to a
KMS identity (the username in config.toml).
-- Create the credential
CREATE CREDENTIAL Cosmian_EKM_Cred
WITH IDENTITY = 'admin', -- must match [[kms.certificates]] username
SECRET = 'unused'
FOR CRYPTOGRAPHIC PROVIDER CosmianEKM;
-- Map to a Windows login (adjust the login name)
ALTER LOGIN [HOSTNAME\YourLogin] ADD CREDENTIAL Cosmian_EKM_Cred;
9. Create keys
USE master;
-- Asymmetric key (RSA 2048)
CREATE ASYMMETRIC KEY MyRsaKey
FROM PROVIDER CosmianEKM
WITH ALGORITHM = RSA_2048,
PROVIDER_KEY_NAME = 'my-rsa-key',
CREATION_DISPOSITION = CREATE_NEW;
-- Symmetric key (AES 256)
CREATE SYMMETRIC KEY MyAesKey
FROM PROVIDER CosmianEKM
WITH ALGORITHM = AES_256,
PROVIDER_KEY_NAME = 'my-aes-key',
CREATION_DISPOSITION = CREATE_NEW;
10. Column-level encryption (quick check)
USE master;
-- Symmetric key protected by the EKM asymmetric key
CREATE SYMMETRIC KEY ColKey
WITH ALGORITHM = AES_256
ENCRYPTION BY ASYMMETRIC KEY MyRsaKey;
-- Encrypt
OPEN SYMMETRIC KEY ColKey DECRYPTION BY ASYMMETRIC KEY MyRsaKey;
SELECT ENCRYPTBYKEY(KEY_GUID('ColKey'), N'Hello EKM!');
CLOSE SYMMETRIC KEY ColKey;
11. Transparent Data Encryption (TDE)
-- Create a login backed by the EKM asymmetric key
CREATE LOGIN Cosmian_TDE_Login FROM ASYMMETRIC KEY MyRsaKey;
-- Credential for unattended access
CREATE CREDENTIAL Cosmian_TDE_Cred
WITH IDENTITY = 'admin', SECRET = 'unused'
FOR CRYPTOGRAPHIC PROVIDER CosmianEKM;
ALTER LOGIN Cosmian_TDE_Login ADD CREDENTIAL Cosmian_TDE_Cred;
-- Enable TDE on a database
USE MyDatabase;
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER ASYMMETRIC KEY MyRsaKey;
ALTER DATABASE MyDatabase SET ENCRYPTION ON;
Monitor encryption progress:
SELECT db.name, dek.encryption_state, dek.percent_complete
FROM sys.dm_database_encryption_keys dek
JOIN sys.databases db ON dek.database_id = db.database_id;
State 3 means fully encrypted.
12. Run integration tests
# All-in-one: build + sign + deploy + copy test config
scripts\Prepare-Integration-Tests.ps1
# Then run the tests
cargo test --test integration -- --test-threads=1
Troubleshooting
Provider not loading
Check the EKM log file:
C:\ProgramData\Cosmian\EKM\logs\cosmian_ekm.log.<date>
"Cannot open database / invalid object name"
The SQL Server service account needs Modify rights on
C:\ProgramData\Cosmian\EKM\. Re-run Initialize-EkmEnvironment.ps1.
KMS connection errors
- Verify
config.tomlhas the correctserver_url. - Confirm the client certificate CN or SAN matches the SQL credential identity.
- Check the KMS server is running:
Test-NetConnection localhost -Port 9998.
Key operations fail after redeployment
If the DLL is replaced, SQL Server must be restarted to reload it. Run
Deploy-EkmDll.ps1 (which handles the restart automatically).
Oracle Database Transparent Data Encryption (TDE)
Oracle Database Transparent Data Encryption (TDE) enables automatic encryption of data at rest in Oracle databases. Users can execute SQL queries normally while TDE handles encryption transparently in the background. Encryption keys are stored directly in the database but can be encrypted using Oracle Key Vault or directly with Hardware Security Modules (HSM) via PKCS#11.
Eviden provides two deployment modes for Oracle TDE integration:
- Oracle Key Vault + HSM Mode: Uses Oracle Key Vault as an intermediary with HSM as Root-of-Trust
- Direct HSM Mode: Direct communication between Oracle Database and HSM via PKCS#11 interface
Mode 1: Oracle Key Vault + HSM Integration
Oracle Key Vault centralizes encryption key management, offering secure storage and distribution for Oracle databases and enterprise applications. It uses wallets to the crucial TDE master key which acts as the Key-Encryption-Key (KEK) for TDE. The master key is stored in a wallet that is protected by a password. This wallet provides a secure and centralized location for managing encryption keys.
For enhanced security, Hardware Security Modules (HSM) can be integrated with Oracle Key Vault to provide additional protection for these wallets. This configuration establishes a Root-of-Trust (RoT): when an HSM is deployed with Oracle Key Vault, the RoT remains in the HSM. The HSM RoT protects the Transparent Data Encryption (TDE) wallet password, which protects the TDE master key, which in turn protects all the encryption keys, certificates, and other security artifacts managed by the Oracle Key Vault server. Note that the HSM in this RoT usage scenario does not store any customer encryption keys. The customer keys are stored and managed directly by the Oracle Key Vault server.
Using HSM as a RoT is intended to mitigate attempts to recover keys from an Oracle Key Vault server which has been started in an unauthorized environment. Physical loss of an Oracle Key Vault server from a facility is one example of such a scenario.
When an Oracle Key Vault server is HSM-enabled, Oracle Key Vault contacts the HSM every five minutes (or whatever you have set the monitoring interval to) to ensure that the Root of Trust key is available and the TDE wallet password can be decrypted.
What Eviden provides is:
- a HSM client: this is a PKCS#11 provider library that make the Oracle Key Vault a HSM client itself. It enables the Root-of-Trust by protecting the Oracle Key Vault wallets passwords. That library also provides a KMS client to communicate with the KMS server.
- a KMS server that is interrogated by the KMS client. The KMS server can either front a HSM or act as a HSM but deployed in a secure environment.
graph TD
subgraph oracle_db[Oracle Database]
okvclient[okvclient.jar]
dek[Encryption Keys
encrypted by
TDE Master Key]
end
okvclient -- OKV endpoint --> OKV
subgraph OKV[Oracle Key Vault]
subgraph hsm_client[Eviden HSM client]
kms_client[Eviden KMS client]
pkcs11_lib[libcosmian_pkcs11.so]
end
subgraph wallet[Wallet protected by HSM]
tde[TDE Master Key]
end
tde --> hsm_client
end
kms_client -- REST API --> KMS[Eviden KMS Server]
KMS --> HSM
subgraph HSM[HSM]
kek[Wallet Encryption Key]
end
Oracle Key Vault Configuration
Before configuring a HSM such as described in Oracle Key Vault, some steps are needed:
For Oracle Database OS, the PKCS#11 library is available here: cosmian-pkcs11.
-
Extract the package:
unzip cosmian-pkcs11-non-fips-static-openssl_5.25.0_linux-amd64.zip -
Copy the PKCS#11 provider library to the Oracle Key Vault server to
/usr/local/okv/hsm/generic/libcosmian_pkcs11.so -
Copy the configuration of the PKCS#11 provider library to
/usr/local/okv/hsm/generic/ckms.toml -
Override the OKV generic HSM configuration files:
/usr/local/okv/hsm/generic/okv_hsm_env
COSMIAN_PKCS11_LOGGING_LEVEL="trace" CKMS_CONF="/usr/local/okv/hsm/generic/ckms.toml" COSMIAN_PKCS11_LOGGING_FOLDER="/var/okv/log/hsm"/usr/local/okv/hsm/generic/okv_hsm_conf
# Oracle Key Vault HSM vendor configuration file # Lines must be shorter than 4096 characters. # The vendor name, to be displayed on the HSM page on the management console. VENDOR_NAME="Cosmian" # The location of the PKCS#11 library. This file must be preserved on upgrade. PKCS11_LIB_LOC="/usr/local/okv/hsm/generic/libcosmian_pkcs11.so" # A colon-separated list of the full paths of files and directories that must # be preserved on upgrade. All of these files and directories should have been # created by the HSM client software setup; none should have existed on Oracle # Key Vault by default. These will be necessary when upgrading to a version # of Oracle Key Vault that is running on a higher major OS version. # Do not use wildcards. PRESERVED_FILES="" -
At this point, the symmetric key labeled
OKV 18.1 HSM Root Keyhas been created in KMS server by Oracle Key Vault. -
Then you can follow the official HSM-Enabling in a Standalone Oracle Key Vault Deployment.
Mode 2: Direct HSM Integration
For simplified deployments or environments where Oracle Key Vault is not available, Oracle Database can communicate directly with HSM via PKCS#11. In this mode, the Eviden PKCS#11 library (libcosmian_pkcs11.so) provides direct access to the Eviden KMS server, which manages the TDE master keys in the HSM.
This approach eliminates Oracle Key Vault from the architecture, reducing complexity while maintaining the security benefits of HSM-protected keys.
graph TD
subgraph oracle_server[Oracle Database Server]
subgraph oracle_db[Oracle Database]
tde_engine[TDE Engine]
dek[Data Encryption Keys
encrypted by
TDE Master Key]
end
pkcs11[Eviden PKCS#11 Library
libcosmian_pkcs11.so]
end
tde_engine -- PKCS#11 --> pkcs11
pkcs11 -- REST API --> KMS[Eviden KMS Server]
KMS --> HSM
subgraph HSM[HSM]
master_key[TDE Master Key]
end
Direct HSM Configuration
Linux
-
Install Eviden PKCS#11 Library
For Oracle Database OS, the PKCS#11 library is available here: cosmian-pkcs11.
# Extract library from PKCS#11 ZIP package. unzip cosmian-pkcs11-non-fips-static-openssl_5.25.0_linux-amd64.zip # Copy to Oracle's HSM directory mkdir -p /opt/oracle/extapi/64/hsm/Cosmian/ cp libcosmian_pkcs11.so /opt/oracle/extapi/64/hsm/Cosmian/ chown oracle:oinstall /opt/oracle/extapi/64/hsm/Cosmian/libcosmian_pkcs11.so -
Configure Eviden PKCS#11 Library
Create the configuration file
/home/oracle/.cosmian/ckms.toml:[http_config] server_url = "http://kms:9998"Set proper ownership:
mkdir -p /home/oracle/.cosmian/ chown oracle:oinstall /home/oracle/.cosmian/ckms.toml -
Prepare Oracle Directory Structure
# Create keystore directories mkdir -p /etc/ORACLE/KEYSTORES/FREE chown -R oracle:oinstall /etc/ORACLE/KEYSTORES/FREE # Setup logging chown -R oracle:oinstall /var/log -
Configure Oracle Database for PKCS#11
Set up TDE to use the HSM via PKCS#11:
-- Set WALLET_ROOT to point to the PKCS#11 library ALTER SYSTEM SET WALLET_ROOT='/opt/oracle/extapi/64/hsm/Cosmian/libcosmian_pkcs11.so' SCOPE=SPFILE; SHUTDOWN IMMEDIATE; STARTUP; -- Configure TDE to use HSM keystore ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM' SCOPE=BOTH SID='*'; SHUTDOWN IMMEDIATE; STARTUP; -
Create and Configure HSM Keystore
-- Open the HSM keystore ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY hsm_identity_pass; -- Create TDE master key in HSM with backup ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY hsm_identity_pass WITH BACKUP; -
Verify Configuration
-- Check keystore status COLUMN WRL_PARAMETER FORMAT A50; SET LINES 200; SELECT WRL_TYPE, WRL_PARAMETER, WALLET_TYPE, STATUS FROM V$ENCRYPTION_WALLET; -- Verify keys are stored in HSM COLUMN NAME FORMAT A40; SET LINES 400; SELECT KEY_ID, KEYSTORE_TYPE, CREATOR_DBNAME, ACTIVATION_TIME, KEY_USE, ORIGIN FROM V$ENCRYPTION_KEYS; -
Optional: Create Test Encrypted Table
-- Create a table with encrypted columns to verify TDE is working CREATE TABLE test_tde (something CHAR(32) ENCRYPT);
Windows
Oracle 26ai Free for Windows has two unfixed HSM/PKCS#11 issues that require workarounds when configuring TDE directly (without Oracle Key Vault):
-
skgdllDiscoverfinds nothing on Windows. The auto-discovery function only scans the hard-coded Linux path/opt/oracle/extapi/64/pkcs11/. No equivalent Windows path is scanned, so Oracle cannot locate any PKCS#11 DLL automatically. -
pkcs11_library_locationrejects Windows paths. TheALTER SYSTEM SETvalidator checks that the supplied path starts with/opt/oracle/extapi/64/pkcs11/. Any Windows path (C:\...) is rejected withORA-46707/ORA-32017.
The steps below apply the required workarounds.
-
Install Eviden PKCS#11 Library
Download
cosmian_pkcs11.dllfrom the release packages.The DLL must be placed at the drive-relative Linux path so that Oracle's
LoadLibrarycall resolves it. On Windows a path starting with/is treated as drive-relative (/opt/...→C:\opt\...on a system whereC:is the current drive).# Create the required directory structure New-Item -ItemType Directory -Force -Path 'C:\opt\oracle\extapi\64\pkcs11' # Install the DLL (both locations are used by Oracle) Copy-Item cosmian_pkcs11.dll 'C:\opt\oracle\extapi\64\pkcs11\cosmian_pkcs11.dll' New-Item -ItemType Directory -Force -Path "$env:ORACLE_HOME\extapi\64\hsm\Cosmian" Copy-Item cosmian_pkcs11.dll "$env:ORACLE_HOME\extapi\64\hsm\Cosmian\cosmian_pkcs11.dll" -
Configure Eviden PKCS#11 Library
Place
ckms.tomlalongside the DLL so it is found regardless of which Windows user account Oracle's service runs under:@' [http_config] server_url = "http://kms:9998" '@ | Set-Content -Path 'C:\opt\oracle\extapi\64\pkcs11\ckms.toml' -Encoding UTF8Note: The PKCS#11 library searches for
ckms.tomlin the following order:CKMS_CONFenvironment variable → directory containing the DLL →%USERPROFILE%\.cosmian\ckms.toml. -
Prepare Oracle Wallet Directory
# Create the wallet directory (adjust path to match your ORACLE_BASE) New-Item -ItemType Directory -Force -Path 'C:\app\oracle\admin\FREE\wallet' -
Configure Oracle Database for PKCS#11
Because
ALTER SYSTEM SET pkcs11_library_locationrejects Windows paths, set all three TDE parameters via a plain PFILE and restart withSTARTUP PFILE=:-- Step 1: capture current in-memory parameters to a text PFILE CREATE PFILE='C:\app\oracle\dbhomeFree\database\initFREE_pkcs11.ora' FROM MEMORY; SHUTDOWN IMMEDIATE;Edit the generated
initFREE_pkcs11.orawith a text editor and add (or update) the following three lines — using forward slashes throughout:*.wallet_root='C:/app/oracle/admin/FREE/wallet' *.tde_configuration='KEYSTORE_CONFIGURATION=HSM' *.pkcs11_library_location='/opt/oracle/extapi/64/pkcs11/cosmian_pkcs11.dll'Then restart and persist:
-- Step 2: start the instance using the edited PFILE STARTUP PFILE='C:\app\oracle\dbhomeFree\database\initFREE_pkcs11.ora'; -- Step 3: write the active configuration back to SPFILE CREATE SPFILE FROM MEMORY; -
Create and Configure HSM Keystore
-- Open the HSM keystore (loads cosmian_pkcs11.dll) ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY hsm_identity_pass; -- Create TDE master key in HSM ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY hsm_identity_pass; -
Verify Configuration
-- Check keystore status COLUMN WRL_PARAMETER FORMAT A50; SET LINES 200; SELECT WRL_TYPE, WRL_PARAMETER, WALLET_TYPE, STATUS FROM V$ENCRYPTION_WALLET; -- Verify keys are stored in HSM SET LINES 400; SELECT KEY_ID, KEYSTORE_TYPE, CREATOR_DBNAME, ACTIVATION_TIME, KEY_USE, ORIGIN FROM V$ENCRYPTION_KEYS; -
Optional: Create Test Encrypted Table
CREATE TABLE test_tde (something CHAR(32) ENCRYPT);
Troubleshooting:
- PKCS#11 log (service user):
C:\WINDOWS\ServiceProfiles\OracleService<SID>\.cosmian\cosmian-pkcs11.log - PKCS#11 log (current user):
%USERPROFILE%\.cosmian\cosmian-pkcs11.log - Oracle alert log:
%ORACLE_BASE%\diag\rdbms\free\<SID>\trace\alert_<SID>.log - Oracle trace dir:
%ORACLE_BASE%\diag\rdbms\free\<SID>\trace\
HSM Identity and Authentication
Architecture: libcosmian_pkcs11.so as a proxy
libcosmian_pkcs11.so is not an HSM driver. It is a thin proxy between Oracle Database
and the Eviden KMS server:
Oracle TDE Engine → libcosmian_pkcs11.so → (HTTP/HTTPS) → Eviden KMS Server → HSM
(PKCS#11 C API) (REST API via (slot + PIN
ckms.toml) managed here)
The KMS server is responsible for the actual HSM connection — including slot selection and HSM
PIN. Oracle never communicates directly with the HSM; libcosmian_pkcs11.so simply forwards
PKCS#11 operations to the KMS over the network.
What the SQL command does
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY hsm_identity_pass;
Oracle's ADMINISTER KEY MANAGEMENT syntax always ends with IDENTIFIED BY <value>. This
command internally translates into two PKCS#11 calls:
C_OpenSession— opens a PKCS#11 session on the slot exposed bylibcosmian_pkcs11.so.C_Login(CKU_USER, pin=hsm_identity_pass)— passeshsm_identity_passas the PKCS#11 user PIN.
hsm_identity_pass and authentication modes
The value after IDENTIFIED BY in Oracle SQL is passed as the PIN to C_Login. The library
supports two modes, controlled by pkcs11_use_pin_as_access_token in ckms.toml:
pkcs11_use_pin_as_access_token | Behavior |
|---|---|
false (default) | C_Login accepts any PIN without validation and returns CKR_OK. The value hsm_identity_pass is a self-documenting placeholder — any non-empty string works. KMS authentication uses credentials from ckms.toml. |
true | C_Login treats the PIN as a short-lived OIDC/JWT bearer token forwarded to the KMS REST API. No credentials are stored in ckms.toml; Oracle supplies the token at keystore-open time. |
Bearer token mode (pkcs11_use_pin_as_access_token = true):
# ckms.toml
pkcs11_use_pin_as_access_token = true
[http_config]
server_url = "https://kms.example.com:9998"
Oracle then passes the JWT token directly:
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY '<jwt_token>';
This approach lets Oracle authenticate to the KMS without storing any credentials in
ckms.toml or on the filesystem.
For all other KMS authentication methods (mTLS, static bearer token, OAuth2/OIDC), configure
ckms.toml using the CLI Authentication guide.
Wallet Migration
Oracle TDE supports migrating the master encryption key between a software wallet (file-based
keystore) and the HSM wallet backed by libcosmian_pkcs11.so. Both directions are supported
and are verified in CI by .mise/scripts/oracle/run_sql_commands.sh.
- Forward (SW → HSM): Oracle calls
C_GenerateKey(CKM_AES_KEY_GEN)to create a new master key in the KMS, thenC_Encryptto re-wrap DEKs. - Reverse (HSM → SW): Oracle calls
C_Decrypton the HSM master key to unwrap DEKs before re-encrypting under the new software key.
Configuration note: In pure HSM mode,
WALLET_ROOTpoints to the PKCS#11 library file path. In hybrid or file-only modes,WALLET_ROOTmust be a directory; Oracle then auto-discovers the library from/opt/oracle/extapi/64/hsm/<vendor>/lib<name>.so.Note:
libcosmian_pkcs11.soprior to version 5.20 reportedCKF_WRITE_PROTECTED, blockingC_GenerateKeyduring forward migration. This flag was removed in 5.20.
HSM Wallet → Software Wallet (Reverse Migration)
Starting from HSM-only mode, follow these steps. Each TDE_CONFIGURATION change requires a restart.
-- 1. Switch WALLET_ROOT from library path to a directory (required for file-based keystore)
ALTER SYSTEM SET WALLET_ROOT='/etc/ORACLE/KEYSTORES/FREE' SCOPE=SPFILE;
SHUTDOWN IMMEDIATE;
STARTUP;
-- 2. Create the software keystore
ADMINISTER KEY MANAGEMENT CREATE KEYSTORE IDENTIFIED BY <sw_password>;
-- 3. Switch to FILE|HSM hybrid mode (file primary, HSM secondary)
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=FILE|HSM' SCOPE=BOTH SID='*';
SHUTDOWN IMMEDIATE;
STARTUP;
-- 4. Open both keystores (software wallet first, then HSM)
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY <sw_password>;
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY <token>;
-- <token> = hsm_identity_pass (or JWT token if pkcs11_use_pin_as_access_token = true)
-- 5. Generate a new software master key and re-wrap DEKs
-- Oracle calls C_Decrypt on the HSM key to unwrap DEKs, then re-encrypts under the new software key.
ADMINISTER KEY MANAGEMENT SET ENCRYPTION KEY
IDENTIFIED BY <sw_password>
REVERSE MIGRATE USING <token>
WITH BACKUP;
-- 6. Switch to file-only mode
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=FILE' SCOPE=BOTH SID='*';
SHUTDOWN IMMEDIATE;
STARTUP;
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY <sw_password>;
Software Wallet → HSM Wallet (Forward Migration)
Starting from file-only mode (after a reverse migration, or from a fresh software wallet),
with WALLET_ROOT already pointing to a directory:
-- 1. Switch to HSM|FILE hybrid mode (HSM primary, file secondary)
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM|FILE' SCOPE=BOTH SID='*';
SHUTDOWN IMMEDIATE;
STARTUP;
-- 2. Open both keystores (HSM first, then software wallet)
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY <token>;
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY <sw_password>;
-- 3. Generate a new HSM master key and re-wrap DEKs
-- Oracle calls C_GenerateKey → C_Encrypt internally.
-- WITH BACKUP is omitted: ORA-46623 prevents backup creation in HSM|FILE mode.
ADMINISTER KEY MANAGEMENT SET ENCRYPTION KEY
IDENTIFIED BY <token>
MIGRATE USING <sw_password>;
-- 4. Switch to HSM-only mode
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM' SCOPE=BOTH SID='*';
SHUTDOWN IMMEDIATE;
STARTUP;
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY <token>;
Multiple Wallets Handling with the Same Database
Oracle TDE supports several multi-wallet configurations on a single database instance. The Eviden PKCS#11 library is transparent to these layouts: every keystore operation that reaches the HSM is forwarded to the KMS server regardless of the number of active wallets.
Combined HSM and Software Wallet
Oracle supports a combined keystore by setting KEYSTORE_CONFIGURATION=HSM|FILE. In this mode the TDE master key is generated and stored in the HSM (via the Eviden PKCS#11 library), while Oracle also maintains a local file-based software wallet. This is useful when an auto-login wallet is required for datafile decryption during automatic instance startup, or for keystore redundancy.
Configure the combined mode:
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM|FILE' SCOPE=BOTH SID='*';
SHUTDOWN IMMEDIATE;
STARTUP;
With the combined configuration, both keystores must be opened explicitly before any key operation:
-- Open the HSM keystore (Eviden PKCS#11)
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY hsm_identity_pass FOR HSM;
-- Open the file-based wallet (use the wallet password here)
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY wallet_password FOR WALLET;
To rotate the TDE master key and update both keystores simultaneously:
ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY hsm_identity_pass
WITH BACKUP USING 'pre_rotation_backup' CONTAINER = ALL;
Per-PDB Isolated Keystores (Multitenant CDB)
In a multitenant Container Database (CDB), each Pluggable Database (PDB) can hold its own TDE master key. All PDB master keys are ultimately protected by the same Eviden KMS through the shared PKCS#11 library, while Oracle enforces key isolation at the PDB boundary.
Activate per-PDB isolated keystores:
-- In the CDB root: enable HSM for all containers
ALTER SYSTEM SET TDE_CONFIGURATION='KEYSTORE_CONFIGURATION=HSM' SCOPE=BOTH SID='*';
SHUTDOWN IMMEDIATE;
STARTUP;
-- Open the root keystore
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY hsm_identity_pass CONTAINER = ALL;
-- Switch to a specific PDB and create its own master key
ALTER SESSION SET CONTAINER = pdb1;
ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY hsm_identity_pass
WITH BACKUP CONTAINER = CURRENT;
Each PDB master key is stored in the Eviden KMS under a unique label prefixed with ORACLE.SECURITY.TDE.HSM.MASTERKEY., ensuring tenant isolation within the same KMS server. No additional KMS configuration is required to support multiple PDBs.
Key Rotation Across Wallets
When rotating TDE master keys in a multi-wallet setup, always open all active keystores before issuing the SET KEY command so Oracle can re-wrap the existing data encryption keys:
-- Open both keystores (combined HSM+FILE example)
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY hsm_identity_pass FOR HSM;
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY wallet_password FOR WALLET;
-- Rotate the master key
ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY hsm_identity_pass
WITH BACKUP USING 'rotation_backup';
After rotation, verify the new key is active:
SELECT KEY_ID, KEYSTORE_TYPE, CREATOR_DBNAME, ACTIVATION_TIME, KEY_USE, ORIGIN
FROM V$ENCRYPTION_KEYS
ORDER BY ACTIVATION_TIME DESC;
Environment Variables Used by cosmian_pkcs11
The Eviden PKCS#11 library reads the following environment variables at startup (i.e. when
C_GetFunctionList is called). All variables are optional unless otherwise noted.
| Variable | Default | Description |
|---|---|---|
CKMS_CONF | (none) | Explicit path to a ckms.toml configuration file. Overrides all other discovery paths. |
COSMIAN_PKCS11_LOGGING_LEVEL | info | Log verbosity level: trace, debug, info, warn, or error. |
COSMIAN_PKCS11_LOGGING_FOLDER | ~/.cosmian/ | (Linux only) Directory where cosmian-pkcs11.log is written. On macOS/Windows the log is always written to ~/.cosmian/. |
COSMIAN_PKCS11_DISK_ENCRYPTION_TAG | disk-encryption | KMS object tag used to identify disk-encryption keys (VeraCrypt, LUKS). Override if your KMS objects use a different tag. |
COSMIAN_PKCS11_SSH_KEY_TAG | ssh-auth | KMS object tag used to identify SSH authentication keys. Override if your KMS objects use a different tag. |
COSMIAN_PKCS11_IGNORE_SESSIONS | false | When set to true, the module reuses a single internal session handle instead of creating one per C_OpenSession call. Intended for applications that call C_OpenSession more times than the token supports. |
Notes
- Variables must be set before the application loads the library (i.e. before the first
call to
C_GetFunctionList). Changes made after loading have no effect. - For Oracle Database (Linux), set variables in the Oracle instance environment before starting
the process, or via the
okv_hsm_envfile for Oracle Key Vault. - For Oracle Database (Windows), set them as system environment variables (visible to the Oracle service account) or in the Oracle service user's profile.
CKMS_CONFis the most commonly needed variable. Ifckms.tomlis not found through any discovery path,C_GetFunctionListreturnsCKR_FUNCTION_FAILEDand the library refuses to load.- The log file is always appended (never rotated). Monitor its size in long-running deployments.
Making variables persistent for the Oracle Database process (Linux)
Oracle Database runs as the OS user oracle (or a custom service account). Environment variables
must be present in that user's process environment at the moment the Oracle instance starts,
not only in an interactive shell. There are several standard approaches:
Option A — Oracle instance environment file (oraenv-style .env)
Oracle Database 12c and later can load a per-instance environment file from
$ORACLE_HOME/dbs/oraenv_<ORACLE_SID> or the path specified by ORACLE_ENV_PATH. Variables
placed there are injected before the instance starts:
# /etc/oratab (verified)
ORCL:/opt/oracle/product/19c/dbhome_1:Y
# /opt/oracle/product/19c/dbhome_1/dbs/oraenv_ORCL (create if absent, owned by oracle)
CKMS_CONF="/home/oracle/.cosmian/ckms.toml"
COSMIAN_PKCS11_DISK_ENCRYPTION_TAG="disk-encryption"
COSMIAN_PKCS11_LOGGING_LEVEL="info"
COSMIAN_PKCS11_LOGGING_FOLDER="/var/log/cosmian/"
Permissions: the file must be readable by the
oracleuser and must not be world-writable.
Option B — oracle user's login profile (~oracle/.bash_profile or ~oracle/.profile)
When Oracle is started manually (e.g. by running sqlplus / as sysdba then
startup) or via a wrapper script that sources the user profile, exporting
variables in the login profile is sufficient:
# ~oracle/.bash_profile (or ~/.profile for sh/ksh)
export CKMS_CONF="/home/oracle/.cosmian/ckms.toml"
export COSMIAN_PKCS11_DISK_ENCRYPTION_TAG="disk-encryption"
export COSMIAN_PKCS11_LOGGING_LEVEL="info"
export COSMIAN_PKCS11_LOGGING_FOLDER="/var/log/cosmian/"
~/.bashrc is not read for non-interactive sessions. Use .bash_profile
(Bash login), .profile (POSIX sh / ksh), or .zprofile (zsh).
When Oracle is started by systemd or another init system, this file is only
sourced if the unit uses User=oracle and the init system spawns a login
shell — which many do not.
Option C — systemd service unit (recommended when Oracle is managed by systemd)
This is the most reliable option when Oracle is controlled by a systemd unit file
(common for Oracle 19c+ on RHEL/OEL 8+):
# /etc/systemd/system/oracle-database.service.d/cosmian.conf
# (drop-in override — create the .d/ directory if absent)
[Service]
Environment="CKMS_CONF=/home/oracle/.cosmian/ckms.toml"
Environment="COSMIAN_PKCS11_DISK_ENCRYPTION_TAG=disk-encryption"
Environment="COSMIAN_PKCS11_LOGGING_LEVEL=info"
Environment="COSMIAN_PKCS11_LOGGING_FOLDER=/var/log/cosmian/"
Reload and restart after adding the drop-in:
sudo systemctl daemon-reload
sudo systemctl restart oracle-database
Verify the variables are visible to the running process:
sudo cat /proc/$(pgrep -o pmon)/environ | tr '\0' '\n' | grep -E 'CKMS|COSMIAN'
Option D — Oracle Key Vault okv_hsm_env (OKV deployments only)
If Oracle Key Vault (OKV) is the HSM manager, the canonical location is the OKV environment file that is sourced before every HSM operation:
# /usr/local/okv/hsm/generic/okv_hsm_env
CKMS_CONF="/usr/local/okv/hsm/generic/ckms.toml"
COSMIAN_PKCS11_DISK_ENCRYPTION_TAG="disk-encryption"
COSMIAN_PKCS11_LOGGING_LEVEL="info"
COSMIAN_PKCS11_LOGGING_FOLDER="/var/log/cosmian/"
See the Oracle Key Vault Administrator's Guide for details on
okv_hsm_envformat and reload procedure.
Verifying that Oracle sees the variables
After any of the above changes, confirm the library picks them up without restarting
Oracle-side applications** by running the diagnostic binary as the oracle user:
sudo -u oracle \
COSMIAN_PKCS11_LOGGING_LEVEL=debug \
ckms pkcs11 verify \
--dll /opt/oracle/extapi/64/hsm/Cosmian/libcosmian_pkcs11.so
If the correct tag and config path appear in the debug output, the variables are propagated correctly.
Verifying the library loads correctly
Use the ckms pkcs11 verify command (part of the Eviden KMS CLI) to confirm that the library
is loadable, ckms.toml is found, and the KMS server is reachable.
Modes 0 and 1 (no auth or static token/TLS cert — the default):
# Basic check (uses ~/.cosmian/ckms.toml by default)
ckms pkcs11 verify --dll /usr/local/lib/libcosmian_pkcs11.so
# Explicit config path
ckms pkcs11 verify \
--dll /opt/oracle/extapi/64/hsm/Cosmian/libcosmian_pkcs11.so \
--conf /home/oracle/.cosmian/ckms.toml
# Verbose — combine with logging env var to also capture library-side trace output
COSMIAN_PKCS11_LOGGING_LEVEL=debug \
ckms pkcs11 verify --dll /usr/local/lib/libcosmian_pkcs11.so
Mode 2 (pkcs11_use_pin_as_access_token = true — OIDC token supplied at keystore open):
A short-lived JWT must be obtained from your identity provider and passed via --token
(or the COSMIAN_PKCS11_TOKEN environment variable):
TOKEN=$(oidc-token my-oidc-profile) # example using oidc-agent; adapt to your IdP
ckms pkcs11 verify \
--dll /opt/oracle/extapi/64/hsm/Cosmian/libcosmian_pkcs11.so \
--conf /home/oracle/.cosmian/ckms.toml \
--token "$TOKEN"
Expected output when everything is working (modes 0 and 1):
[conf] Will use default home config: /home/oracle/.cosmian/ckms.toml
[load] Opening: /usr/local/lib/libcosmian_pkcs11.so
[load] OK: shared library opened
[C_GetFunctionList] OK: ckms.toml parsed
[C_Initialize] OK
[C_GetSlotList] OK: using slot ID 1
[C_OpenSession] OK: session opened on slot 1
[C_FindObjects] Enumerating objects by class:
CKO_DATA: N
CKO_PUBLIC_KEY: N
CKO_PRIVATE_KEY: N
CKO_SECRET_KEY: N
[C_FindObjects] OK: N PKCS#11 object(s) visible on KMS
[C_CloseSession] OK
[C_Finalize] OK
All checks passed.
Expected output for mode 2 (with --token):
[C_GetFunctionList] OK: ckms.toml parsed
[C_Initialize] OK
[C_GetSlotList] OK: using slot ID 1
[C_OpenSession] OK: session opened on slot 1
[C_Login] OK: session authenticated with provided token
[C_FindObjects] Enumerating objects by class:
...
All checks passed.
If --token is omitted with mode 2, object enumeration fails with CKR_USER_NOT_LOGGED_IN.
Authentication from Oracle to KMS
The Eviden PKCS#11 library (libcosmian_pkcs11.so on Linux, cosmian_pkcs11.dll on Windows) communicates with the Eviden KMS server over HTTP or HTTPS. Authentication is configured through the ckms.toml file that the library reads at startup.
Configuration File Discovery
The library resolves ckms.toml using the following search order:
CKMS_CONFenvironment variable — explicit path, takes precedence over everything else. For Oracle Key Vault, set this in/usr/local/okv/hsm/generic/okv_hsm_env.ckms.tomlbeside the PKCS#11 library — a file namedckms.tomlplaced in the same directory as the.so/.dll. Convenient when the library is deployed at a fixed path (e.g.C:\opt\oracle\extapi\64\pkcs11\ckms.tomlon Windows).~/.cosmian/ckms.toml— home directory of the OS user running the Oracle process (typically/home/oracle/.cosmian/ckms.tomlon Linux)./etc/cosmian/ckms.toml— system-wide fallback on Linux.
For Oracle Key Vault, set CKMS_CONF in the OKV environment file so all Oracle Key Vault processes share the same configuration:
# /usr/local/okv/hsm/generic/okv_hsm_env
CKMS_CONF="/usr/local/okv/hsm/generic/ckms.toml"
No Authentication (Development / Internal Networks)
For development environments or deployments where the KMS is on a fully trusted internal network:
[http_config]
server_url = "http://kms:9998"
Bearer Token Authentication
When the KMS server is configured with API-token or JWT/OIDC authentication, supply an access_token. The token is sent as an Authorization: Bearer <token> HTTP header on every request.
[http_config]
server_url = "https://kms.example.com:9998"
access_token = "<your-bearer-token>"
Note: storing a long-lived token in
ckms.tomlmeans any OS user who can read the file gains KMS access. For production, prefer TLS client certificates (below) or the OIDC dynamic-token mode.
OIDC / JWT Keystore Authentication (Dynamic Token)
This mode keeps zero credentials in ckms.toml. Instead, when Oracle opens the encrypted wallet, the DBA supplies a short-lived JWT from an identity provider via the IDENTIFIED BY clause. The library validates it against the KMS on every keystore open.
| Mode | ckms.toml credentials | When KmsClient is created | C_Login behavior |
|---|---|---|---|
| 0 — No auth | none | library load | no-op |
| 1 — Static token / TLS cert | token or cert paths | library load | no-op |
| 2 — OIDC dynamic token | none (flag only) | C_Login call | validates + uses token |
ckms.toml for mode 2
[http_config]
server_url = "https://kms.example.com:9998"
# No credentials stored here
pkcs11_use_pin_as_access_token = true
Oracle SQL
The value after IDENTIFIED BY becomes the bearer token sent to the KMS:
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN
IDENTIFIED BY 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...';
A wrapper script that fetches a fresh token before opening the keystore is strongly recommended:
#!/usr/bin/env bash
# Fetch a short-lived JWT (example using oidc-agent; adapt to your IdP)
TOKEN=$(oidc-token my-oidc-profile)
sqlplus -s / as sysdba <<EOF
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY '$TOKEN';
EOF
Security properties
ckms.tomlcontains no secrets — reading the file grants nothing.- Each keystore open requires a fresh token from the IdP; expired tokens are rejected (
401 Unauthorizedfrom KMS →C_Loginfailure). - An empty
IDENTIFIED BYstring returnsCKR_PIN_INCORRECT(Oracle:ORA-28354). - Use
ckms pkcs11 verify --token <JWT>to test the full flow end-to-end; see Verifying the library loads correctly.
TLS Client Certificate Authentication (Recommended for Production)
Mutual TLS (mTLS) is the recommended authentication method for production deployments. Each Oracle host or database instance is provisioned with a unique client certificate; the KMS identifies and authorises callers by the certificate's Common Name (CN).
KMS server prerequisites: the server must be started in TLS mode with a CA certificate configured to validate client certificates. See TLS configuration and Authentication for the server-side setup.
PEM Certificates (FIPS-Compatible, Recommended)
[http_config]
server_url = "https://kms.example.com:9998"
# Client certificate in PEM format (leaf certificate, or leaf + intermediate chain)
tls_client_pem_cert_path = "/home/oracle/.cosmian/oracle-client.crt"
# Matching private key in PEM format (PKCS#8 or traditional RSA/EC)
tls_client_pem_key_path = "/home/oracle/.cosmian/oracle-client.key"
PKCS#12 Bundle (Non-FIPS Only)
[http_config]
server_url = "https://kms.example.com:9998"
# PKCS#12 bundle containing the client certificate and private key
tls_client_pkcs12_path = "/home/oracle/.cosmian/oracle-client.p12"
tls_client_pkcs12_password = "changeit"
Combined mTLS + Bearer Token (Multi-Factor)
[http_config]
server_url = "https://kms.example.com:9998"
tls_client_pem_cert_path = "/home/oracle/.cosmian/oracle-client.crt"
tls_client_pem_key_path = "/home/oracle/.cosmian/oracle-client.key"
# Additional JWT bearer token for a second authentication factor
access_token = "<JWT_BEARER_TOKEN>"
Server Certificate Pinning
To validate the KMS server against a specific PEM certificate (instead of the system CA bundle), use verified_cert. This is particularly useful when the KMS uses a self-signed or internal CA certificate:
[http_config]
server_url = "https://kms.example.com:9998"
# PEM-encoded server certificate expected from the KMS
verified_cert = """
-----BEGIN CERTIFICATE-----
MIIBxTCCAW...
-----END CERTIFICATE-----
"""
For testing only, you can disable server certificate verification entirely (not for production):
[http_config]
server_url = "https://kms.example.com:9998"
accept_invalid_certs = true # INSECURE — testing only
For the complete set of authentication options available on the KMS server side, see Authentication.
EDB Postgres Advanced Server TDE with Cosmian KMS
This guide demonstrates how to configure EDB Postgres Advanced Server 17 Transparent Data Encryption (TDE) to use Cosmian KMS as its key management server via KMIP over mTLS.
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 2.1 over TCP/TLS with mutual certificate authentication (mTLS) |
| Port | 5696 or 15696 (configurable) |
| Key type | AES-256 symmetric key (CBC mode with PKCS#5 padding) |
| EDB version | EDB Postgres Advanced Server 15.2+ and 17.x |
| Client | edb_tde_kmip_client.py (shipped inside the EDB image) |
| Cosmian KMS feature | Works in non-FIPS mode (PyKMIP uses ssl.wrap_socket) |
Architecture
flowchart TB
pg["EDB Postgres Advanced Server<br/>(initdb --data-encryption)"]
client["edb_tde_kmip_client.py<br/>(PGDATAKEYWRAPCMD / PGDATAKEYUNWRAPCMD)"]
kms["Cosmian KMS<br/>(KMIP 2.1, mTLS, port 15696)"]
pg -- "wrap DEK on initdb" --> client
pg -- "unwrap DEK on startup" --> client
client -- "KMIP Encrypt / Decrypt<br/>AES-256-CBC" --> kms
During initdb --data-encryption:
- Postgres generates a random cluster DEK.
- It invokes
PGDATAKEYWRAPCMD— theedb_tde_kmip_client.py encryptcommand. - The client calls KMIP Encrypt on the Cosmian KMS, which returns
[IV][ciphertext]. - The wrapped DEK is written to
pg_encryption/key.bin.
On every subsequent server start, Postgres calls PGDATAKEYUNWRAPCMD
(edb_tde_kmip_client.py decrypt) to unwrap the DEK before mounting the cluster.
Wire Format
The edb_tde_kmip_client.py script defines the on-disk format for the wrapped DEK:
key.bin = [16-byte IV][AES-256-CBC ciphertext]
This format is assembled client-side; the KMS is unaware of it.
KMIP Variants
The client supports two --variant options that differ in how they call KMIP:
| Variant | Encrypt | Decrypt |
|---|---|---|
pykmip (required for Cosmian KMS) | Encrypt(data=DEK) → KMS returns IVCounterNonce=IV, Data=CT | Decrypt(Data=CT, IVCounterNonce=IV) — standard KMIP |
thales | Same as pykmip | Decrypt(Data=IV‖CT) — no IVCounterNonce; specific to Thales CipherTrust Manager |
Note: Cosmian KMS follows the KMIP mandatory conformance requirement: a Decrypt request without
IVCounterNoncereturnsInvalid_Message. Always use--variant=pykmipwhen connectingedb_tde_kmip_client.pyto Cosmian KMS.
Prerequisites
- A running Cosmian KMS server with the KMIP socket enabled (
listen_address/port). - mTLS certificates: CA, server, and client certificate+key.
- EDB Postgres Advanced Server 15.2+ or 17.x.
edb_tde_kmip_client.pyinstalled via theedb-tde-kmip-clientpackage from EDB repositories.- Python 3 with PyKMIP (
pip3 install PyKMIP).
Configuration
1. KMS Configuration
Add the KMIP socket listener to kms.toml:
[server]
port = 9998
[server.kmip]
server_port = 15696
Generate or reuse mTLS certificates for the KMS and the EDB client. See Certificates for details.
2. Create the Master Key
The edb_tde_kmip_client.py script does not implement key creation.
Use create_master_key.py (bundled with the Cosmian KMS test scripts)
or any other KMIP client to create an AES-256 key:
# Using the bundled helper script
python3 .mise/scripts/edb_tde/create_master_key.py \
--pykmip-config-file=/path/to/pykmip.conf
# → prints the key UID, e.g. 0193a4b2-...
The pykmip.conf file must point to the Cosmian KMS KMIP socket:
[client]
host = localhost
port = 15696
keyfile = /path/to/client.key
certfile = /path/to/client.crt
ca_certs = /path/to/ca.crt
3. Configure PGDATAKEYWRAPCMD / PGDATAKEYUNWRAPCMD
export PGDATAKEYWRAPCMD='python3 /usr/edb/kmip/client/edb_tde_kmip_client.py \
encrypt \
--pykmip-config-file=/path/to/pykmip.conf \
--key-uid=<UID from step 2> \
--variant=pykmip \
--out-file=%p'
export PGDATAKEYUNWRAPCMD='python3 /usr/edb/kmip/client/edb_tde_kmip_client.py \
decrypt \
--pykmip-config-file=/path/to/pykmip.conf \
--key-uid=<UID from step 2> \
--variant=pykmip \
--in-file=%p'
4. Initialize the Cluster
initdb -D /var/lib/edb/data -y -U enterprisedb \
--key-wrap-command="$PGDATAKEYWRAPCMD" \
--key-unwrap-command="$PGDATAKEYUNWRAPCMD"
initdb calls PGDATAKEYWRAPCMD once to seal the freshly generated cluster DEK.
5. Start the Server
pg_ctl -D /var/lib/edb/data start
Verify TDE is active:
SELECT data_encryption_version FROM pg_control_init();
-- Returns 1 if TDE is enabled
Key Rotation
To rotate the master key:
PGDATA=/var/lib/edb/data
OLD_KEY=<old UID>
NEW_KEY=<new UID created via create_master_key.py>
KMIP_CONF=/path/to/pykmip.conf
CLIENT=/usr/edb/kmip/client/edb_tde_kmip_client.py
cd $PGDATA/pg_encryption
cp key.bin key.bin.bak
python3 $CLIENT decrypt --in-file=key.bin \
--pykmip-config-file=$KMIP_CONF --key-uid=$OLD_KEY --variant=pykmip \
| python3 $CLIENT encrypt --out-file=key.bin \
--pykmip-config-file=$KMIP_CONF --key-uid=$NEW_KEY --variant=pykmip
sed -i "s/$OLD_KEY/$NEW_KEY/" $PGDATA/postgresql.conf
pg_ctl -D $PGDATA restart
Running the Integration Tests
The Cosmian KMS repository includes a full integration test suite for EDB TDE.
It requires an EDB subscription token to pull the edb-postgres-advanced:17
Docker image.
EDB_SUBSCRIPTION_TOKEN=<token> \
mise run test:edb_tde --variant non-fips
The test suite:
- Logs in to
docker.enterprisedb.com, starts the EDB container. - Runs
initdbwith TDE — the realedb_tde_kmip_client.pyseals the cluster DEK against Cosmian KMS over KMIP/mTLS. - Verifies
data_encryption_version = 1. - Exercises both
--variant=pykmipand--variant=thaleswrap/unwrap roundtrips. - Tests key rotation (re-wrap DEK with a new master key).
See .mise/scripts/edb_tde/README.md for full test documentation.
Reference
| Resource | Link |
|---|---|
| EDB TDE documentation | https://www.enterprisedb.com/docs/tde/latest/ |
| Thales CipherTrust integration | https://www.enterprisedb.com/docs/partner_docs/ThalesCipherTrustManager/05-UsingThalesCipherTrustManager/ |
| IBM Guardium CM integration | https://www.ibm.com/docs/en/guardium-cm/2.0.0?topic=ctc-configuring-postgresql-transparent-database-encryption-tde-key-management-guardium-cryptography-manager |
| Entrust KeyControl integration | https://nshielddocs.entrust.com/interops-docs/pdfs/EDB_Postgres_v16.4-Entrust_KeyControl_v10.3.1_(PUBLIC)_ig.pdf |
| PyKMIP documentation | https://pykmip.readthedocs.io/en/latest/client.html |
InterSystems IRIS Database Encryption with Eviden KMS
InterSystems IRIS supports database encryption via the KMIP 2.0 protocol, allowing encryption keys to be managed externally by a dedicated Key Management System. Eviden KMS acts as the KMIP server: IRIS connects to it over a mutual TLS (mTLS) channel, retrieves or creates symmetric keys, and uses them to encrypt database files on disk.
Architecture overview
flowchart LR
subgraph iris["InterSystems IRIS"]
enc["Database encryption engine"]
kmip_client["KMIP 2.0 client\n(^SECURITY / ^EncryptionKey)"]
enc --> kmip_client
end
subgraph kms["Eviden KMS (non-FIPS)"]
socket["KMIP socket server\nport 5696 (TLS)"]
db["Key store"]
socket --> db
end
kmip_client -->|"mTLS — KMIP 2.0"| socket
The mTLS channel requires:
| Side | Material |
|---|---|
| KMS | Server certificate + private key (PKCS#12) |
| IRIS | Client certificate + private key + CA certificate |
| Both | Same CA that signed both certificates |
Prerequisites
| Component | Version | Notes |
|---|---|---|
| Eviden KMS | 5.0+ (non-FIPS build) | KMIP socket server requires --features non-fips |
| InterSystems IRIS | 2022.1+ | Community or Enterprise edition |
| KMIP protocol | 2.0 | Configured on the IRIS side |
| OpenSSL | 3.0+ | For TLS 1.3 |
FIPS note: The KMIP socket server is only available in the non-FIPS build of Eviden KMS. Start the server with
--features non-fipsor use the non-FIPS Docker image.
Certificate preparation
Both the KMS server and the IRIS client must present certificates signed by the same CA.
The repository ships test certificates under test_data/certificates/client_server/; for production, generate your own PKI.
test_data/certificates/client_server/
ca/
ca.crt ← CA certificate (trusted by both sides)
server/
kmserver.acme.com.p12 ← KMS server cert + key (PKCS#12, password: "password")
owner/
owner.client.acme.com.crt ← IRIS client certificate
owner.client.acme.com.key ← IRIS client private key
Starting Eviden KMS with the KMIP socket server
The KMIP socket server is disabled by default. Enable it with:
cosmian_kms \
--database-type sqlite \
--sqlite-path /var/lib/kms/data \
--socket-server-start true \
--socket-server-port 5696 \
--tls-p12-file /path/to/kmserver.acme.com.p12 \
--tls-p12-password <p12-password> \
--clients-ca-cert-file /path/to/ca.crt \
--port 9998 \
--hostname 0.0.0.0
| Flag | Purpose |
|---|---|
--socket-server-start | Enable the KMIP TCP/TLS socket listener |
--socket-server-port | TCP port for KMIP (default: 5696) |
--tls-p12-file | PKCS#12 bundle containing the server certificate and key |
--tls-p12-password | Password for the PKCS#12 bundle |
--clients-ca-cert-file | CA that must have signed every connecting client cert |
Verify the socket is up:
openssl s_client -connect <kms-host>:5696 \
-cert /path/to/client.crt \
-key /path/to/client.key \
-CAfile /path/to/ca.crt \
-quiet 2>&1 | head -5
# Expected: "Verify return code: 0 (ok)"
Configuring IRIS
All configuration is done via ObjectScript in the %SYS namespace. You can run these commands interactively in the IRIS terminal, via the Management Portal, or in batch mode with iris session IRIS -B.
Step 1 — Create a TLS/SSL configuration
IRIS uses named SSL configurations to reference certificate material. Create one for the Cosmian KMS connection:
zn "%SYS"
; Create a client TLS configuration using the Security.SSLConfigs ObjectScript API
set tls = ##class(Security.SSLConfigs).%New()
set tls.Name = "CosmianKMSTLS"
set tls.Enabled = 1
set tls.Type = 1 ; 1 = client
set tls.CertificateFile = "/path/to/client.crt"
set tls.PrivateKeyFile = "/path/to/client.key"
set tls.CAFile = "/path/to/ca.crt"
set tls.VerifyPeer = 1 ; verify KMS server cert
set sc = tls.%Save()
write $select(sc=1:"OK",1:"ERROR: "_$system.Status.GetErrorText(sc)),!
Type = 1configures the SSL entry as a client configuration. SetVerifyPeer = 1to enforce server-certificate verification (recommended for production).
Step 2 — Register the KMIP server
The documented command-line interface for KMIP server management is ^SECURITY option 14.
Run it from a %SYS terminal session and follow the interactive prompts:
do ^SECURITY
14 ← KMIP server setup
1 ← Create KMIP server
CosmianKMS ← Server name
Eviden KMS – mTLS ← Description
<kms-host> ← Host DNS name or IP
5696 ← TCP port
2.0 ← OASIS KMIP protocol version
CosmianKMSTLS ← SSL/TLS configuration name (from Step 1)
Y ← Non-blocking I/O (recommended)
N ← Auto-reconnect
30 ← I/O timeout in seconds
N ← Log KMIP messages
N ← Debug SSL/TLS
Y ← Confirm creation
0 ← Back
q ← Quit
Step 3 — Create an encryption key
Use the ^EncryptionKey routine to create a key on the external KMIP server:
- From the IRIS terminal, run
do ^EncryptionKey. - Select 5 – Manage KMIP server.
- Enter the server name:
CosmianKMS. - Select 2 – Create new key and choose the desired key length (256-bit recommended).
The key is created on the KMS and referenced in IRIS by its KMIP object identifier.
Step 4 — Activate the KMIP key for database encryption
After creating the key, activate it for database encryption using ^EncryptionKey
(IRIS docs — Activate a Database Encryption Key from a KMIP Server):
- Run
do ^EncryptionKey. - Select 3 – Database encryption.
- Select 1 – Activate database encryption keys.
- Select 2 – Use KMIP server.
- Enter the KMIP server name:
CosmianKMS. - Select the key number shown in the list (e.g.,
1for the first key).
The key is now activated in IRIS memory and can be used to encrypt databases.
Step 5 — Encrypt a database
- Go to the IRIS Management Portal → System Administration → Encryption → Database Encryption.
- Select the database you want to encrypt.
- Click Encrypt and choose the activated KMIP key.
- IRIS starts a background encryption task for that database.
Configuring with Docker
If IRIS runs inside a Docker container and the KMS runs on the Docker host, use
host.docker.internal as the KMS hostname and pass the --add-host flag:
docker run \
--add-host host.docker.internal:host-gateway \
--volume /path/to/certs:/iris-kmip-certs:ro \
intersystemsdc/iris-community:latest
Mount the CA certificate, client certificate, and client key under /iris-kmip-certs/
and reference those paths in the ObjectScript configuration above.
CI integration
The repository includes an automated mTLS integration test that:
- Builds and starts Eviden KMS (non-FIPS) with the KMIP socket server.
- Validates the mTLS sad path (connection without a client certificate is rejected).
- Validates the mTLS happy path (connection with a valid client certificate succeeds).
- Pulls the IRIS Docker image.
- Detects whether KMIP support is available by probing
^SECURITYoption 14. - If KMIP is available:
- Creates a TLS configuration (
Security.SSLConfigsAPI). - Creates a KMIP server entry via
^SECURITYoption 14 (documented command-line interface). - Creates a symmetric encryption key via
^EncryptionKeyoption 5. - Activates the KMIP key for database encryption via
^EncryptionKeyoption 3 → 1 → 2 (per IRIS docs — Activate a Database Encryption Key from a KMIP Server). - Enables encryption on the TEST namespace database (
SYS.DatabaseAPI). - Verifies at-rest encryption: inserts test data, proves it is NOT readable in
IRIS.DAT, proves it IS readable via IRIS session.
- Creates a TLS configuration (
- If KMIP is not available (Community edition): reports SKIPPED cleanly — the mTLS test still passes.
IRIS editions and KMIP support
| Edition | KMIP support | Detection |
|---|---|---|
IRIS Community (intersystemsdc/iris-community) | No | ^SECURITY option 14 not available |
| IRIS Enterprise / licensed | Yes | ^SECURITY option 14 shows KMIP server setup sub-menu |
The test script detects KMIP availability at runtime by probing ^SECURITY option 14.
If the KMIP server setup sub-menu does not appear in the output, all IRIS KMIP steps are skipped gracefully.
The CI job exits 0 with the KMIP steps marked as SKIPPED when using the Community image.
False-positive protection: IRIS terminal batch mode echoes each command before executing it. A naïve
grep "OK_MARKER"would match the command echo (WRITE "OK_MARKER",!) even when the command failed. The test uses anchored grep (grep -q "^OK_MARKER$") to match only the bare output line produced by thewritecommand — not the surrounding echo.
Running the test
# Local run (uses Community image by default)
bash .mise/scripts/test/test_iris.sh --variant non-fips
# With a licensed IRIS image (full KMIP test)
IRIS_DOCKER_IMAGE=containers.intersystems.com/intersystems/iris:latest \
bash .mise/scripts/test/test_iris.sh --variant non-fips
# Via the Nix wrapper (matches CI exactly)
mise run test:iris --variant non-fips
Environment variables
| Variable | Default | Purpose |
|---|---|---|
IRIS_DOCKER_IMAGE | intersystemsdc/iris-community:latest | Override to use a licensed or ARM image |
IRIS_LICENSE_KEY | (empty) | ISC license key injected as ISC_PACKAGE_LICENSEKEY |
On ARM hardware (Apple Silicon, AWS Graviton), use
intersystemsdc/iris-community-arm64:latestor the script will automatically add--platform linux/amd64to run the x86-64 image via emulation.
GitHub Actions
The CI job (iris-mtls in .github/workflows/test_all.yml) runs on every PR
from the main repository and on every release tag. It supports two optional secrets
for accessing enterprise IRIS images from the InterSystems Container Registry:
| Secret / Variable | Purpose |
|---|---|
ISC_DOCKER_USERNAME | Username for containers.intersystems.com |
ISC_DOCKER_PASSWORD | Password for containers.intersystems.com |
IRIS_LICENSE_KEY | License key for licensed IRIS images |
IRIS_DOCKER_IMAGE (var) | Repository variable to override the image |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
handshake failure | IRIS client cert not signed by the KMS trusted CA | Ensure both certs share the same CA (--clients-ca-cert-file) |
Instance is not running | iris session called before IRIS fully initialized | Wait for the instance; retry for up to 120 s |
ERROR: <status code> | Wrong ^SECURITY option 14 prompt answer | Check the IRIS version; menu prompts may vary between releases |
KMS log: unexpected EOF | Client connected without a certificate (expected for sad path) | Normal — mTLS enforced; provide a valid client cert |
host.docker.internal not found | Docker Desktop < 4.0 or Linux without --add-host | Add --add-host host.docker.internal:host-gateway to docker run |
Veracrypt integration with Cosmian KMS
The Cosmian KMS is integrated with Veracrypt disk encryption using the Cosmian KMS PKCS#11 provider library.
Veracrypt is a free, open-source disk encryption software for Windows, macOS, and Linux, and is a successor to TrueCrypt, certified by ANSSI. Veracrypt has undergone a formal security evaluation by the BSI.
Using the Cosmian KMS PKCS#11 provider library, Veracrypt can use keys stored in the KMS to encrypt and decrypt volumes.
Installing the PKCS#11 provider library on Veracrypt
Go to Veracrypt Settings > Security Tokens and use the Select Library...
button to select the Cosmian KMS PKCS#11 library for your operating system.
Then click OK.

Configuring access to the KMS
The PKCS#11 provider library uses the same configuration file as the CLI.
See Authenticating users to the KMS to learn how to configure the KMS to use OpenID Connect or certificate authentication. Please note that the KMS can also manage the machines' certificates.
Here is an example configuration file for the PKCS#11 provider library accessing the KMS using a PKCS#12 file for authentication.
[kms_config.http_config]
server_url = "https://kms.acme.com:9999"
ssl_client_pkcs12_path = "./certificates/machine123.acme.p12"
ssl_client_pkcs12_password = "machine123_pkcs12_password"
To use Open ID connect, install the KMS CLI from https://package.cosmian.com/kms/ and
use the ckms login command to authenticate to the KMS first.
Logging
The PKCS#11 module logs to the cosmian-pkcs11.log file in the same .cosmian subdirectory of the configuration file.
The COSMIAN_PKCS11_LOGGING_LEVEL environment variable controls logging of the PKCS#11 module.
The logging level can be set to trace, debug, info, warn, or error, and defaults to info
when not set.
Creating keys to use with Veracrypt
The keys used to encrypt Veracrypt volumes are created in the KMS as Symmetric Keys and must
carry at least two tags, one being disk-encryption. The other tag(s) will be displayed to the
user in the Veracrypt GUI when selecting the key to use to mount the volume. The other tag(s) can
also be used to identify the key when using Veracrypt CLI.
To create a key using the CLI, which will be shown as vol1 to the user, use the following command:
ckms sym keys create -t disk-encryption -t vol1
The keys are exposed to Veracrypt as PKCS#11 token files (CKO_DATA objects).
The label shown in the Veracrypt GUI is the first user-defined tag sorted alphabetically (e.g. vol1).
The PKCS#11 provider discovers disk-encryption keys using the tag disk-encryption by default.
To use a different tag, set the COSMIAN_PKCS11_DISK_ENCRYPTION_TAG environment variable before
starting Veracrypt.
COSMIAN_PKCS11_DISK_ENCRYPTION_TAG=my-veracrypt-keys veracrypt
Keys must remain non-sensitive (exportable) so the PKCS#11 provider can
retrieve the key material. This is the default for ckms sym keys create.
Do not forget to grant Get access to the key to the machine that will mount the Veracrypt volume.
ckms access-rights grant <MACHINE_CN> <KEY_ID> get
where <MACHINE_CN> is the Common Name of the certificate used to authenticate the machine to the
KMS and <KEY_ID> is the ID of the key created in the previous step.
Mounting a Veracrypt volume using the GUI
When mounting a Veracrypt volume, select the Use keyfiles option and select the key to use to
mount the volume using the Keyfiles... button.

Click Add Token Files...

Select the key to use to mount the volume and click OK

Mounting a Veracrypt volume using the CLI
When mounting a Veracrypt volume using the CLI, use the -k option followed by
token://slot/1/file/vol1 where vol1 is the other tag chosen to identify the key in the KMS.
Revoking the access to a key
To revoke access to the key, either
- remove the access to the key <KEY_ID> for the machine <MACHINE_CN> using the following command:
ckms access-rights revoke <MACHINE_CN> <KEY_ID> get
- revoke the key itself using the following command:
ckms sym keys revoke <KEY_ID>
Note: a revoked key can never be reused.
Rotating a key
To rotate a key,
- Create a new key.
- Grant access to the machine to the new key.
- Perform the key rotation/change in the Veracrypt GUI or CLI.
- Revoke the access to the old key for the machine.
- Optionally revoke the old key itself.
LUKS
The Eviden KMS can provision secrets to open Linux LUKS encrypted partitions. The secret never leaves the KMS and can be used to unlock the partition at boot time.
Installing p11-kit and the Eviden KMS PKCS#11 module
The Eviden KMS provides a PKCS#11 module that can be used to access the KMS from applications that support PKCS#11, using the p11-kit framework.
With LUKS, the system provided systemd-cryptenroll command must have support for p11-kit which you can check by running systemd-cryptenroll --help and checking for the +P11KIT flag.
❯ systemd-cryptenroll --version
systemd 253 (253.5-1ubuntu6.1)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL
+ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY
+P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT
default-hierarchy=unified
Unfortunately, Ubuntu 22.04 does not provide p11-kit support; however the setup works fine for Ubuntu 24.04.
1. Install the p11-kit package
Ubuntu 24.04
sudo apt install p11-kit cryptsetup
Rocky Linux 9
sudo dnf install p11-kit cryptsetup
2. Create the PKCS#11 configuration and module directories
sudo mkdir -p /etc/pkcs11/modules
3. Create a configuration file for the PKCS#11 module
sudo tee /etc/pkcs11/pkcs11.conf <<EOF
# This setting controls whether to load user configuration from the
# ~/.config/pkcs11 directory. Possible values:
# none: No user configuration
# merge: Merge the user config over the system configuration (default)
# only: Only user configuration, ignore system configuration
user-config: merge
EOF
4. Copy the PKCS#11 module to the pkcs11 directory
sudo cp libcosmian_pkcs11.so /usr/local/lib/
5. Create a configuration file for the cosmian PKCS#11 module
sudo tee /etc/pkcs11/modules/cosmian_pkcs11.module <<EOF
# Eviden KMS PKCS#11 module
module: /usr/local/lib/libcosmian_pkcs11.so
EOF
6. Check that the module loads correctly
> p11-kit list-modules
...
cosmian_pkcs11: /usr/local/lib/libcosmian_pkcs11.so
library-description: Eviden KMS PKCS#11 provider
library-manufacturer: Cosmian
library-version: x.y
token: Cosmian-KMS
manufacturer: Cosmian
model: software
serial-number: x.y.z
flags:
rng
write-protected
login-required
user-pin-initialized
protected-authentication-path
token-initialized
Configuring the access to the KMS
The PKCS#11 module uses the same configuration file as the CLI. Since it may be run as a system user, the configuration file should be made available in /etc/cosmian/ckms.toml.
See Authenticating users to the KMS to learn how to configure the KMS to use Open ID Connect or certificate authentication.
Here is an example configuration file for the PKCS#11 provider library accessing the KMS using a PKCS#12 file for authentication.
[http_config]
server_url = "https://kms.acme.com:9999"
ssl_client_pkcs12_path = "./certificates/machine123.acme.p12"
ssl_client_pkcs12_password = "machine123_pkcs12_password"
To use Open ID connect, install the KMS CLI from Cosmian packages and use the ckms login command to authenticate to the KMS first.
Logging
The PKCS#11 module logs to the cosmian-pkcs11.log file in the same .cosmian subdirectory of the configuration file.
The COSMIAN_PKCS11_LOGGING_LEVEL environment variable controls logging of the PKCS#11 module.
The logging level can be set to trace, debug, info, warn, or error, and defaults to info
when not set.
Creating an RSA key pair using openssl and importing it into the Eviden KMS
To generate a self-signed certificate with RSA 2048bit key and in PKCS12 format, you can use the OpenSSL command-line tool. Here are the steps:
1. Generate a new private key
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
2. Create a self-signed certificate
openssl req -new -x509 -key private_key.pem -out cert.pem -days 365
3. Convert the certificate and private key to PKCS12 format
openssl pkcs12 -export -out certificate.p12 -inkey private_key.pem -in cert.pem
4. Import the PKCS12 file into the Eviden KMS using a disk-encryption tag
ckms certificates import -f pkcs12 -t disk-encryption certificate.p12 disk-encryption
The private key in the PKCS12 file was imported with id: 6fc631...
Tags:
- disk-encryption
A tag different from disk-encryption can be used, but it must be set in the
in the COSMIAN_PKCS11_DISK_ENCRYPTION_TAG environment variable when enrolling the token (sse
below).
Creating a LUKS partition
First, allocate some space, then create a LUKS partition using cryptsetup.
1. Allocating space for the LUKS partition
LUKS partitions can be created from either disk partitions or files.
From a file
Use either dd or fallocate to create a file that will be used as the LUKS partition.
# Create a 1GB file
fallocate -l 1G /path/to/file
Then use path/to/file as the device to encrypt.
From a disk partition
Using parted, determine or create a partition on the disk that you want to encrypt.
In this example, we assume the disk is available as /dev/vda.
If needed, use partedto resize the last partition and create free space at the end of the disk.
sudo parted /dev/vda
(parted) print free
Number Start End Size File system Name Flags
17.4kB 1049kB 1031kB Free Space
1 1049kB 1128MB 1127MB fat32 boot, esp
2 1128MB 3276MB 2147MB ext4
3 3276MB 102GB 98.7GB
102GB 103GB 1079MB Free Space
Make a 4th partition /dev/vda4 from the free space at the end.
(parted) mkpart 4 102GB 103GB
2. Creating a LUKS 2 partition on the allocated space
Enter a passphrase to protect the partition when prompted. The encrypted passphrase will be stored in the LUKS header in key slot 0.
sudo cryptsetup luksFormat --type luks2 --key-slot 0 /dev/vda4
or alternatively, if you created a file:
sudo cryptsetup luksFormat --type luks2 --key-slot 0 /path/to/file
Make sure to remember the passphrase, as it will be needed to unlock the partition
during cryptenroll or when rotating the RSA keys.
Enrolling the LUKS partition with the Eviden KMS
The RSA key pair is searched on the KMS using a tag controlled by
the COSMIAN_PKCS11_DISK_ENCRYPTION_TAG environment variable.
When not set, the default tag searched is disk-encryption.
1. Enroll the partition with the Eviden KMS
# this is equivalent to
# sudo COSMIAN_PKCS11_LOGGING_LEVEL=info COSMIAN_PKCS11_DISK_ENCRYPTION_TAG=disk-encryption systemd-cryptenroll /dev/vda4 --pkcs11-token-uri=pkcs11:token=Cosmian-KMS
> sudo systemd-cryptenroll --pkcs11-token-uri=pkcs11:token=Cosmian-KMS /dev/vda4
🔐 Please enter current passphrase for disk /dev/vda4: *************
cosmian-pkcs11 module logging at INFO level to file /var/log/cosmian-pkcs11.log
Successfully logged into security token 'Cosmian-KMS' via protected authentication path.
New PKCS#11 token enrolled as key slot 1.
3. Verify the enrollment
> sudo cryptsetup luksDump /dev/vda4
LUKS header information
Version: 2
Epoch: 5
...
Keyslots:
0: luks2
....
1: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: pbkdf2
Hash: sha512
...
Tokens:
0: systemd-pkcs11
pkcs11-uri: pkcs11:token=Cosmian-KMS
pkcs11-key: 0b 94 e0 ...
...
4. Test attaching the LUKS partition to /dev/mapper/myluks using the Cosmian-KMS token in slot 0
> sudo cryptsetup open --type luks2 --token-id=0 --token-only /dev/vda4 myluks
cosmian-pkcs11 module logging at INFO level to file /var/log/cosmian-pkcs11.log
Successfully logged into security token 'Cosmian-KMS' via protected authentication path.
Successfully decrypted key with security token.
5. Format the LUKS partition (do this only once)
sudo mkfs.ext4 /dev/mapper/myluks
6. Mount the partition
sudo mkdir /mnt/myluks #only once
sudo mount /dev/mapper/myluks /mnt/myluks
7. Close the LUKS partition
sudo umount /mnt/myluks
sudo cryptsetup close myluks
Automatically unlocking the LUKS partition at boot
To automatically unlock the LUKS partition at boot, you cannot use the /etc/crypttab file
because the network is not available when systemd-cyptsetup is run.
You need to create a systemd service that unlocks the LUKS partition at the right time, after the network is available.
1. Create the bash script that unlocks and mounts the partition
sudo tee -a /root/mount_myluks.sh <<EOF
#!/bin/bash
set -e
set -x
# unlock the partition
cryptsetup open --type luks2 --token-id=0 --token-only /dev/vda4 myluks
# mount the partition
mount /dev/mapper/myluks /mnt/myluks
EOF
sudo chmod +x /root/mount_myluks.sh
2. Create the systemd service file
sudo tee -a /etc/systemd/system/mount_myluks.service <<EOF
[Unit]
Description=open and mount the encrypted /dev/vda4 to /mnt/myluks
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash /root/mount_myluks.sh
[Install]
WantedBy=multi-user.target
EOF
3. Enable the service
> sudo systemctl enable mount_myluks.service
Created symlink /etc/systemd/system/multi-user.target.wants/mount_myluks.service → /etc/systemd/system/mount_myluks.service.
sudo systemctl daemon-reload
4. Reboot the machine to test the service
sudo reboot
The LUKS partition should be automatically unlocked and mounted at boot to /mnt/myluks.
Check dmesg, and /var/log/cosmian-pkcs11.log for any errors.
Rotating the keys
To rotate the keys used to encrypt the LUKS partition, you can generate a new key pair and import it into the Eviden KMS.
Then, you can re-enroll the LUKS partition with the new key. You MUST know the passphrase to perform this operation.
1. Wipe the old key from the LUKS partition
sudo systemd-cryptenroll /dev/vda4 --wipe-slot=pkcs11
Wiped slot 1.
2. Revoke the old key from the Eviden KMS
ckms certificates revoke -k 6fc631... "revoked"
Successfully revoked: 6fc631....
3. Follow the steps to generate a new key pair and import it into the Eviden KMS
4. Enroll the LUKS partition with the new key; you will be prompted for the passphrase
External documentation
Prim'X CRYHOD
The Eviden KMS can be used to unlock Prim'x CRYHOD partitions
Configuring Prim'X CRYHOD
If you get the following pop-up when trying to encrypt a disk

Additional configuration is required.
Launch the CRYHOD policies application.

Configure the P131 policy:

For testing, you can set the value to th.
Configure the P821 policy:

For testing, you can keep the default values.
Configuring the location of the PKCS#11 provider using the policy P296

Enter the full path of the cosmian_pkcs11.dll as the value name and leave the value empty.
Note: if you change the value, kill all CRYHOD processes or restart for the change to take into effect
Encrypting a partition
Launch Computer Encryption Center

And select the partition to encrypt.
Then select Key stored in a smart card or USB device (PKCS#11)

Click next; the Comsian KMS should appear in the list

Click next
Adjusting the KMS location and authentication
The configuration file is located in the User home .cosmian sub-directory,
in the ckms.toml file.
See Authenticating users to the KMS to learn how to configure the KMS to use Open ID Connect or certificate authentication. Please note that the KMS can also manage the machines' certificates.
Here is an example configuration file for the PKCS#11 provider library accessing the KMS using a PKCS#12 file for authentication.
[http_config]
server_url = "https://kms.acme.com:9999"
ssl_client_pkcs12_path = "./certificates/machine123.acme.p12"
ssl_client_pkcs12_password = "machine123_pkcs12_password"
Viewing the logs
By default, the logs are available in the User home .cosmian sub-directory.
Get-Content -path C:\<USER HOME>\.cosmian\cosmian-pkcs11.log -wait
The log level can be adjusted using the COSMIAN_PKCS11_LOGGING_LEVEL environment variable.
setx COSMIAN_PKCS11_LOGGING_LEVEL "debug"
Creating an RSA private key and Certificate to use with CRYHOD
Create an RSA key with 2048 bits and the disk-encryption tag.
This tag is the default tag searched. The value can be changed by setting
the COSMIAN_PKCS11_DISK_ENCRYPTION_TAG environment variable.
cosmian.exe rsa keys create -s 2048 -t disk-encryption
Public key unique identifier: ec572e57-eab0-481c-9393-805a11c12ac0_pk
Private key unique identifier: ec572e57-eab0-481c-9393-805a11c12ac0
VMware vSphere VM Encryption with an External KMS
This guide explains how to protect your VMware vSphere infrastructure using Eviden KMS as an external Key Management Server (KMS), and walks you through the full setup:
- Why use an external KMS with vSphere?
- Architecture and security principles
- What gets protected
- Setting up certificates
- Configuring the KMS server
- Connecting vCenter
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.1 over TCP/TLS with mutual certificate authentication |
| Port | 5696 (IANA-registered KMIP port) |
| Key type | AES-256 symmetric key |
| vSphere version | vSphere 6.5 and above (Standard Key Provider) |
| Eviden KMS feature | Works with both FIPS and non-FIPS builds |
Why Use an External KMS with vSphere?
VMware vSphere supports three key provider types (since vSphere 6.5/7.0):
| Key Provider | Available Since | External KMS Required |
|---|---|---|
| Standard Key Provider | vSphere 6.5 | Yes (KMIP) |
| Trusted Key Provider | vSphere 7.0 | Yes (KMIP + vSphere Trust Authority) |
| Native Key Provider | vSphere 7.0 U2 | No (built-in, keys stored in vCenter) |
Using a Standard Key Provider backed by an external, dedicated KMS is the recommended approach for production environments and regulated industries because it provides:
- Separation of duties: encryption keys are stored in a dedicated, hardened system — completely separate from the compute infrastructure they protect. A compromised ESXi host or vCenter cannot expose the master keys.
- Centralised key lifecycle management: key creation, rotation, revocation, and auditing are managed in one place across all workloads.
- Compliance readiness: many frameworks (PCI-DSS, HIPAA, GDPR, SOC 2, FedRAMP) explicitly require that encryption keys be managed independently from the data they protect.
- FIPS 140-3 compliance: Eviden KMS operates in FIPS 140-3 validated mode, satisfying the cryptographic requirements of the most demanding regulatory environments.
- Zero-trust posture: even with physical access to a storage array or datastore, data remains unintelligible without authorised key access from the KMS.
References
Architecture and Security Principles
Key Hierarchy
vSphere VM encryption uses a two-level key hierarchy to minimize key exposure:
| Key | Generated by | Stored | Purpose |
|---|---|---|---|
| Key Encryption Key (KEK) | External KMS (Eviden) | KMS only | Wraps (encrypts) the DEK |
| Data Encryption Key (DEK) | ESXi host | With the VM (wrapped by KEK) | Encrypts VM disk I/O |
The KEK never leaves the KMS in plaintext. ESXi hosts receive the KEK transiently in memory to unwrap the DEK; neither key is ever persisted unprotected on the hypervisor or storage.
Communication Flow
sequenceDiagram
autonumber
participant Admin as vSphere Admin
participant VC as vCenter Server
participant KMS as Eviden KMS
participant ESXi as ESXi Host
participant DS as Datastore (VMDK)
Admin->>VC: Assign VM Storage Policy<br/>(Encryption enabled)
VC->>KMS: KMIP Create — request new KEK<br/>(mTLS, port 5696)
KMS-->>VC: KEK ID + KEK (AES-256)
VC->>ESXi: Push KEK (in-memory, encrypted channel)
ESXi->>ESXi: Generate DEK locally (AES-256 XTS)
ESXi->>ESXi: Wrap DEK with KEK → wrapped DEK
ESXi->>DS: Store VM files encrypted<br/>(VMDK, VMX, swap — AES-256 XTS)
ESXi->>DS: Store wrapped DEK alongside VM
Note over KMS,DS: KEK resides only in KMS.<br/>Wrapped DEK stored with VM.<br/>Plaintext DEK exists only in ESXi RAM.
rect rgb(240, 248, 255)
Note over VC,ESXi: On VM power-on (key refresh)
ESXi->>VC: Request KEK for this VM
VC->>KMS: KMIP Get (KEK ID)<br/>(mTLS)
KMS-->>VC: KEK
VC-->>ESXi: KEK (in-memory)
ESXi->>ESXi: Unwrap DEK using KEK
ESXi->>DS: Decrypt/Encrypt disk I/O using DEK
end
Network Architecture
graph TB
subgraph Mgmt["Management Network (isolated)"]
VC["vCenter Server\n(KMIP client)"]
end
subgraph KMSZone["KMS DMZ / Secure Zone"]
KMS["Eviden KMS\nport 5696 (KMIP/TLS)\nport 9998 (HTTP API)"]
DB[("Key Store\n(SQLite / PostgreSQL\n/ Redis-findex)")]
KMS --- DB
end
subgraph Compute["Compute Cluster"]
ESXi1["ESXi Host 1"]
ESXi2["ESXi Host 2"]
ESXiN["ESXi Host N"]
end
subgraph Storage["Storage Network"]
SAN["SAN / NFS Datastore\n(encrypted VMDKs)"]
end
VC -- "KMIP 1.1+\nmTLS (port 5696)\nCertificate Auth" --> KMS
VC -- "Push KEK\n(encrypted, in-memory)" --> ESXi1
VC -- "Push KEK" --> ESXi2
VC -- "Push KEK" --> ESXiN
ESXi1 -- "AES-256 XTS\nencrypted I/O" --> SAN
ESXi2 -- "AES-256 XTS\nencrypted I/O" --> SAN
ESXiN -- "AES-256 XTS\nencrypted I/O" --> SAN
style KMSZone fill:#e8f5e9,stroke:#388e3c
style Mgmt fill:#e3f2fd,stroke:#1565c0
style Compute fill:#fff3e0,stroke:#e65100
style Storage fill:#fce4ec,stroke:#c62828
Security Properties
| Property | How it is enforced |
|---|---|
| Encryption at rest | All VMDK files, VM swap files, VM core dumps, and the VM configuration (VMX) are encrypted with AES-256 XTS on the ESXi host before any write to the datastore |
| Key separation | KEK lives only inside Eviden KMS; the ESXi host holds the plaintext DEK in RAM only for the duration of active I/O |
| Mutual TLS (mTLS) | Both vCenter and Eviden KMS authenticate each other with X.509 certificates over every KMIP connection; no unauthenticated key request can succeed |
| No keys on storage | The datastore contains only the wrapped DEK (ciphertext); raw key material is never written to disk outside the KMS |
| Audit trail | Every KMIP operation (Create, Get, Activate, Revoke, Destroy) is logged by Eviden KMS with timestamp, caller identity, and key ID |
| Key rotation | VMware supports re-keying VMs (shallow re-key: new KEK; deep re-key: new DEK + new KEK) without downtime on vSphere 7.0+ |
| FIPS 140-3 | Eviden KMS uses a FIPS 140-3 validated OpenSSL 3.x provider; all symmetric keys use AES-256; all asymmetric operations use NIST-approved curves |
| Revocation / disaster recovery | Revoking the KEK in Eviden KMS immediately prevents any new VM power-on or vMotion, enabling a cryptographic kill-switch |
What Gets Protected
Encryption at Rest
When a VM Storage Policy with encryption is applied, the following objects are transparently encrypted:
- VMDK files (flat and sparse) — all disk data via AES-256 XTS
- VM configuration file (
.vmx) - VM swap file (
.vswp) — prevents memory snooping via storage - VM core dump files (
.vmss,.vmem) — prevents key material leakage in snapshots and crash dumps - Snapshot delta disks (
.vmdkdelta files created during snapshot)
Items not encrypted by VM encryption: vSphere log files, NVRAM state, and the vSphere datastore catalogue itself. Use datastore-level encryption (vSAN Encryption or storage-array encryption) as a complement for full coverage.
Encryption in Transit
All key material travels over mutually authenticated TLS:
- vCenter ↔ KMS: KMIP 1.1+ over TLS 1.2+, enforced by certificate pinning on both sides
- vCenter ↔ ESXi: key distribution uses the internal vSphere encrypted management channel
- KMS API: Eviden KMS exposes its management API over HTTPS (TLS 1.2+); the KMIP socket server runs on a dedicated port (default 5696)
Access Control
- Only vCenter Server (identified by its client certificate) can request keys from the KMS
- ESXi hosts never communicate directly with the KMS; they receive KEKs from vCenter through the authenticated management plane
- Eviden KMS access control enforces per-key and per-user permissions; the vCenter service account should be granted the minimum set of KMIP operations (
Create,Get,Activate,Revoke,Locate)
Prerequisites
- OpenSSL (≥ 1.1.1) installed and on your PATH
- A working copy of
openssl.cnfwith a[ v3_ca ]section - UNIX shell (bash, zsh, etc.)
- A directory to store your certificates, e.g.,
/etc/ssl/{{ORG_NAME}}_certs - VMware vSphere: 6.5 or higher
1. Generate Your CA
Create a 2048-bit RSA private key for your CA, then issue a self-signed root certificate:
# 1. Generate CA private key
openssl genrsa -out ca.key 2048
# 2. Create self-signed CA certificate (10 year validity)
openssl req -x509 -nodes -days 3650 \
-new -key ca.key \
-out ca.crt \
-config openssl.cnf \
-extensions v3_ca \
-subj "/C=<COUNTRY>/ST=<STATE>/L=<CITY>/O=<ORG_NAME>/OU=<UNIT>/CN=<CA_COMMON_NAME>"
ca.key: CA private key (keep this highly secure!)ca.crt: Public root certificate, used to sign and verify downstream certificates
2. Generate Server Key & CSR
Create a new 2048-bit RSA key for your KMS server and a CSR including EKU extensions:
openssl req -newkey rsa:2048 -nodes \
-keyout server.key \
-out server.csr \
-subj "/CN=<SERVER_COMMON_NAME>/O=<ORG_NAME>/C=<COUNTRY>" \
-addext "keyUsage = digitalSignature, keyEncipherment" \
-addext "extendedKeyUsage = clientAuth, serverAuth"
server.key: Server's private keyserver.csr: Certificate Signing Request, withclientAuth&serverAuthEKUs
3. Sign the Server Certificate
Use your CA to sign the CSR, embedding the same EKU settings in the issued certificate:
openssl x509 -req \
-in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt \
-days 365 \
-extfile <(printf "[req_ext]\n\
keyUsage = digitalSignature,keyEncipherment\n\
extendedKeyUsage = clientAuth,serverAuth\n") \
-extensions req_ext
server.crt: The signed certificate, valid for 1 year
4. Verify the Certificate Extensions
Confirm that your certificate contains the correct EKU fields:
openssl x509 -in server.crt -text -noout | grep -A1 "Extended Key Usage"
Expected output:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
5. Export to PKCS#12
Bundle your server certificate, private key, and CA chain into a single .p12 archive:
openssl pkcs12 -export \
-in server.crt \
-inkey server.key \
-certfile ca.crt \
-out server.p12 \
-name "{{SERVER_ALIAS}}" \
-passout pass:<P12_PASSWORD>
server.p12: PKCS#12 archive containing your key and certificates<P12_PASSWORD>: Password to unlock the archive — use a strong secret!
6. Configure the KMS Server (kms.toml)
Below is a template kms.toml. Update file paths, usernames, and passwords as required:
# General Configuration
default_username = "<USERNAME>"
force_default_username = false
socket_server_start = true
[http]
port = 9998
hostname = "0.0.0.0"
# TLS configuration moved to [tls] section
# See the [tls] section below for certificate configuration
authority_cert_file = "/etc/ssl/{{ORG_NAME}}_certs/ca.crt"
Start the KMS with:
systemctl start cosmian_kms
vCenter Integration
Step 1: Go on your vCenter UI and add a Key Provider

Step 2: Add new Standard KMS Provider

Step 3: Set up your Standard Key Provider

Step 4: Trust the newly added Eviden KMS

Step 5: Establish Trust with the Eviden KMS



Step 6: Go on the KMS server and get .crt and .key certificates

Step 7: Upload KMS Credentials and establish trust

Step 8: Your KMS is connected

Bonus: Encrypt your Virtual Machine

Keep all private keys secure and back up your CA key (
ca.key) offline in an encrypted vault.
Synology DSM — NAS Volume Encryption with Eviden KMS
Synology DiskStation Manager (DSM) 7.x supports delegating NAS volume encryption key management to an external KMIP-compliant Key Management Server. By connecting a Synology NAS to Eviden KMS, you ensure that volume encryption keys are never stored on the NAS itself: they live in a centrally managed, audited, and optionally HSM-backed key store.
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.2 over TCP/TLS with mutual certificate authentication |
| Port | 5696 (IANA-registered KMIP port) |
| Key type | AES-256 symmetric key |
| DSM version | DSM 7.1 and above |
| Eviden KMS feature | Requires non-FIPS build (PKCS#12 TLS + AES-CBC key wrapping) |
What Synology DSM does
When you configure an external KMS in DSM, the NAS performs the following KMIP operations on every volume creation and every subsequent volume mount:
| Step | KMIP Operation | Purpose |
|---|---|---|
| 1 | DiscoverVersions | Negotiate KMIP protocol version |
| 2 | Query | Enumerate server capabilities (6 query functions) |
| 3 | Locate | Check whether the volume key already exists |
| 4 | Register | Register a SecretData object (opaque 32-byte key material, KMIP 1.x OperationPolicyName="default" attribute included) |
| 5 | Activate | Transition the key from PreActive to Active state |
| 6 | ModifyAttribute | Rename the key to the volume UUID |
| 7 | GetAttributes | Verify key attributes (state, object type) |
| 8 | Get | Retrieve key material to mount the encrypted volume |
| 9 | Locate | Find the key by name after a NAS reboot |
| 10 | Revoke | Revoke the key during volume deletion or key rotation |
| 11 | Destroy | Delete the key from the KMS |
Two fixes were required for full Synology DSM 7.2.2 compatibility:
OperationPolicyName(issue #796): DSM includes this KMIP 1.x attribute (deprecated in 1.3, removed in 2.0) in everyRegisterrequest. The server now silently ignores it instead of emitting a confusingWARNlog entry.ModifyAttribute(issue #760): DSM callsModifyAttributeimmediately afterRegisterto rename the key to the volume UUID. This operation was not fully implemented and caused DSM to report "cannot create keys". It is now fully supported.
Prerequisites
- Eviden KMS server running in non-FIPS mode
- TLS enabled on the KMS server with a valid PKCS#12 certificate
- Client certificate and CA certificate for mutual TLS authentication
- DSM 7.1 or later with the Encryption Key Manager feature enabled (see Control Panel → Security → Encryption Key Manager)
Server-Side Setup
1. Configure TLS
Synology DSM requires mutual certificate authentication over TLS. Edit your
kms.toml:
[tls]
tls_p12_file = "/etc/cosmian/kms/server.p12"
tls_p12_password = "your-p12-password"
clients_ca_cert_file = "/etc/cosmian/kms/clients-ca.crt"
[socket_server]
socket_server_start = true
socket_server_port = 5696 # standard KMIP port
socket_server_hostname = "0.0.0.0"
2. Issue a client certificate for the NAS
The NAS identifies itself to the KMS using a client TLS certificate signed by
the clients_ca_cert_file CA. Use OpenSSL or the cosmian CLI to generate
the certificate:
# Generate a CA and a client certificate (example using OpenSSL)
openssl genrsa -out clients-ca.key 4096
openssl req -new -x509 -days 3650 -key clients-ca.key \
-subj "/CN=KMS Clients CA" -out clients-ca.crt
openssl genrsa -out synology-nas.key 2048
openssl req -new -key synology-nas.key \
-subj "/CN=synology-nas-01" -out synology-nas.csr
openssl x509 -req -days 3650 -in synology-nas.csr \
-CA clients-ca.crt -CAkey clients-ca.key -CAcreateserial \
-out synology-nas.crt
3. Start Eviden KMS
cosmian_kms --config /etc/cosmian/kms/kms.toml
Or via Docker:
docker run -p 9998:9998 -p 5696:5696 \
-v /etc/cosmian/kms:/etc/cosmian/kms:ro \
-e COSMIAN_KMS_CONF=/etc/cosmian/kms/kms.toml \
ghcr.io/cosmian/kms:latest
DSM-Side Configuration
- Log in to Synology DSM as an administrator.
- Go to Control Panel → Security → Encryption Key Manager.
- Click Add KMS Server.
- Fill in the connection details:
| Field | Value |
|---|---|
| KMS Server Address | IP or hostname of the Eviden KMS host |
| Port | 5696 |
| Client Certificate | PEM or PKCS#12 file you issued for the NAS |
| Private Key | Matching private key (if not bundled in PKCS#12) |
| CA Certificate | clients-ca.crt (the CA that signed the KMS server cert) |
- Click Test Connection — DSM will run a
DiscoverVersions+Queryprobe. - Click Save.
Encrypting a volume
- Open Storage Manager.
- Select the volume you want to encrypt.
- Click Encrypt and choose the KMS server you just configured.
- DSM will call
Create → Activate → Get → GetAttributesand mount the encrypted volume.
Automated CI Testing
Because Synology DSM is proprietary hardware/software, there is no official
Docker image available for automated testing. Instead, the Eviden KMS test
suite includes a Python simulation client (scripts/synology_dsm_client.py)
that replays the exact KMIP operation sequence performed by DSM.
Running the simulation locally
# Build KMS server (non-FIPS required)
cargo build --bin cosmian_kms --features non-fips
# Start the KMS server with KMIP socket enabled (uses scripts/kms.toml)
COSMIAN_KMS_CONF=scripts/kms.toml \
cargo run --bin cosmian_kms --features non-fips &
# Wait until both ports are ready (HTTP: 9998, KMIP: 15696)
# Then run the DSM simulation
python3.11 scripts/synology_dsm_client.py \
--configuration scripts/pykmip.conf \
--verbose
Or use the convenience test runner:
bash scripts/test_synology_dsm.sh simulate
Running via nix-shell (recommended for CI parity)
mise run test:synology_dsm --variant non-fips
GitHub Actions CI
The Synology DSM simulation is included in the CI matrix in
.github/workflows/test_all.yml under the synology_dsm job (non-FIPS only):
matrix:
type:
- ...
- synology_dsm
features: [fips, non-fips]
exclude:
- type: synology_dsm
features: fips
The CI job:
- Builds Eviden KMS with
--features non-fips. - Starts the server with TLS and the KMIP socket enabled.
- Runs
scripts/synology_dsm_client.pyagainst it. - Asserts that all 10 steps (DiscoverVersions → Destroy) succeed.
Simulation Script Reference
| Script | Purpose |
|---|---|
scripts/synology_dsm_client.py | Python KMIP client replicating DSM's operation sequence |
scripts/test_synology_dsm.sh | Local test runner (prereq checks + venv activation) |
.mise/scripts/test_synology_dsm.sh | CI entry point (builds server, starts it, runs test) |
scripts/pykmip.conf | Shared PyKMIP TLS configuration (host, port, certs) |
scripts/kms.toml | KMS server configuration used by KMIP tests |
Troubleshooting
DSM reports "Connection failed"
- Verify that port 5696 is reachable from the NAS (firewall rules).
- Confirm
socket_server_start = trueandtls_p12_fileis set inkms.toml. - Check KMS logs:
RUST_LOG=cosmian_kms_server=debug cargo run …
DSM reports "Certificate verification failed"
- The NAS client certificate must be signed by the CA listed in
clients_ca_cert_fileinkms.toml. - The KMS server certificate must be trusted by the NAS. Upload the server's CA certificate to DSM under Control Panel → Security → Certificate.
ModifyAttribute returns an error
- Ensure you are running Eviden KMS ≥ 5.17 which includes the
ModifyAttributefix for Synology DSM compatibility (issue #760). - The operation requires the key to be in Active state. Call
ActivatebeforeModifyAttribute.
Key not found after NAS reboot
- DSM uses
Locatewith the key name to reconnect. Ensure the key name is unique and consistent across reboots. - Check that the client certificate presented on reconnect is the same one used at creation time (or that both have access rights granted in the KMS access policy).
OperationPolicyName warning in server logs
Older DSM versions (using the KMIP 1.0 protocol) include an OperationPolicyName
attribute in their Register/Create requests. This attribute was deprecated in
KMIP 1.3 and removed in KMIP 2.0+. Eviden KMS ≥ 5.18 silently ignores it
(issue #796). Earlier versions log
a harmless WARN entry; the key operation still succeeds.
Security Considerations
- Mutual TLS: Always require client certificate authentication
(
clients_ca_cert_fileset inkms.toml) so that only authorised NAS devices can access keys. - Key access policy: Use the Eviden KMS policy to restrict each NAS to its own keys.
- Key rotation: Revoke and re-create keys periodically. DSM will re-encrypt the volume DEK with the new KMS key on the next mount.
- Audit logging: Enable KMS access logs (
RUST_LOG=info) and forward them to a SIEM for compliance.
VAST Data — Storage Encryption with Eviden KMS
VAST Data storage clusters use KMIP for external encryption key management (EKM). By connecting a VAST Data cluster to Eviden KMS, you ensure that data encryption keys (DEKs) and key encryption keys (KEKs) are centrally managed, audited, and never stored unprotected on the storage appliance.
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.4 binary TTLV over HTTP/TLS with mutual certificate authentication |
| Endpoint | POST /kmip on the KMS HTTP port (default 9998) |
| Key types | AES-256 symmetric keys |
| Key creation | In batches of 2–3 keys per encryption group |
| VAST version | VAST Data Platform 5.x and above |
| Eviden KMS mode | FIPS and non-FIPS builds supported |
What VAST Data does
When you configure an external KMS in the VAST Data management console, the storage cluster performs the following KMIP operations for encryption key lifecycle management:
| Step | KMIP Operation | Purpose |
|---|---|---|
| 1 | DiscoverVersions | Session initialization handshake (once per connection) |
| 2 | Create | Create an AES-256 symmetric key (CryptographicUsageMask = Encrypt|Decrypt) |
| 3 | AddAttribute ×3 | Set Name, ObjectGroup, and OperationPolicyName (3 calls per key) |
| 4 | Activate | Transition the key from Pre-Active to Active state |
| 5 | Locate | Find a key by its VAST-assigned name (VAST_EKM_KEY_2_<uuid>_<index>) |
| 6 | Get | Retrieve plaintext key material |
| 7 | GetAttributes | Verify key State (Active) and ActivationDate (polled every ~61 seconds) |
| 8 | ReKey | Rotate an active key — generates new key material with a new Unique Identifier |
| 9 | Revoke | Revoke a key during decommissioning |
| 10 | Destroy | Permanently delete the key from the KMS |
Key lifecycle workflow
The following sequence diagram shows the complete lifecycle as observed in production logs (June 2026):
sequenceDiagram
participant V as VAST Data
participant K as Eviden KMS
Note over V,K: Session Start
V->>K: DiscoverVersions (KMIP 1.4)
Note over V,K: Key Creation (per encrypted path, 2–3 keys)
loop For each key in group
V->>K: Create (AES-256 SymmetricKey)
V->>K: AddAttribute (Name)
V->>K: AddAttribute (ObjectGroup)
V->>K: AddAttribute (OperationPolicyName)
V->>K: Activate
end
Note over V,K: Initial Key Fetch
loop For each key
V->>K: Locate (by name)
V->>K: Get (plaintext key material)
end
Note over V,K: Continuous Monitoring (~61s interval)
loop Forever
loop For each key
V->>K: Locate (by name)
V->>K: GetAttributes (State, ActivationDate)
end
end
Note over V,K: Key Rotation (triggered externally)
loop For each key to rotate
V->>K: Locate (find current key by name)
V->>K: ReKey (new UID returned, old key stays Active)
V->>K: Locate (verify new key by name)
V->>K: Get (fetch new key material)
end
Note over V,K: Key Decommissioning (later, on encrypted path deletion)
loop For each key to retire
V->>K: Locate (find key by name)
V->>K: Revoke (Active → Deactivated)
V->>K: Locate (confirm state)
V->>K: Destroy (permanently delete)
end
Key naming convention
VAST creates keys with structured names following the pattern:
VAST_EKM_KEY_2_<encryption_group_uuid>_<index>
VAST_EKM_KEY_2_— static prefix (version 2 of VAST's naming scheme)<encryption_group_uuid>— UUID identifying the encrypted path/group_<index>— 0-based index within the group (typically 0 or 1)
These names are used in Locate operations to find keys associated with
specific encryption groups. After ReKey, the name is transferred to the
new replacement key.
Prerequisites
- Eviden KMS server running (FIPS or non-FIPS mode)
- TLS enabled on the KMS with mutual certificate authentication
- Client certificate and CA certificate configured for the VAST cluster
- VAST Data Platform 5.x or later with External Key Manager (EKM) feature enabled
Server-Side Setup
1. Configure TLS
VAST Data connects via HTTP POST to /kmip using KMIP 1.4 binary TTLV with
mutual TLS authentication. Configure your kms.toml:
[tls]
tls_cert_file = "/etc/cosmian/kms/server.crt"
tls_key_file = "/etc/cosmian/kms/server.key"
clients_ca_cert_file = "/etc/cosmian/kms/clients-ca.crt"
2. Generate client certificates
Create a client certificate for the VAST cluster signed by the same CA
configured in clients_ca_cert_file:
# Generate VAST client key and CSR
openssl genrsa -out vast-client.key 2048
openssl req -new -key vast-client.key -out vast-client.csr \
-subj "/CN=vast-cluster-01/O=VAST Data"
# Sign with CA
openssl x509 -req -in vast-client.csr \
-CA clients-ca.crt -CAkey clients-ca.key -CAcreateserial \
-out vast-client.crt -days 365
# Convert to PKCS#12 for VAST (if required by your VAST version)
openssl pkcs12 -export -in vast-client.crt -inkey vast-client.key \
-out vast-client.p12 -name "vast-cluster-01"
VAST-Side Configuration
1. Navigate to EKM settings
In the VAST Data management console:
- Go to Settings → Security → External Key Manager
- Click Add External KMS
2. Enter KMS connection details
| Field | Value |
|---|---|
| KMS Address | <kms-server-hostname> |
| KMS Port | 9998 (default KMS HTTP port) |
| Client Certificate | Upload vast-client.crt |
| Client Key | Upload vast-client.key |
| CA Certificate | Upload the CA that signed the KMS server certificate |
3. Test connection
Use the Test Connection button in the VAST management console to verify
connectivity. A successful test performs a Create + Get + Destroy cycle.
Compatibility Notes
KMIP 1.x attributes
VAST sends the OperationPolicyName("default") attribute via AddAttribute
after key creation (or inline in the Create template, depending on VAST version).
This is a KMIP 1.x attribute that was deprecated in KMIP 1.3 and removed in KMIP 2.0.
The Eviden KMS stores this attribute as a vendor extension and returns it in
GetAttributes responses to KMIP 1.4 clients. A log warning is emitted during
deserialization:
WARN KMIP 2.1 does not support the KMIP 1 attribute OperationPolicyName("default")
This warning is informational and does not affect functionality. The attribute is
preserved across ReKey rotations (transferred to the replacement key along with
Name and other attributes).
ReKey behavior
When VAST sends a ReKey request, the KMS implements KMIP 2.1 §6.1.46:
- The KMS creates a new symmetric key with a new Unique Identifier
- The Name attribute is transferred from the old key to the new key
- Bidirectional links are set:
ReplacementObjectLinkon old → new,ReplacedObjectLinkon new → old - The old key's State is unchanged (it remains
Active) — the KMIP spec does not deactivate the existing key during ReKey - VAST can then
Locateby name and finds the new key
VAST expects the ReKey response to return a different Unique Identifier
from the original. After rotation, the old key remains Active in the database.
Later, when VAST decommissions an encrypted path, it sends Locate → Revoke →
Locate → Destroy for each key to retire.
Monitoring interval
VAST polls the KMS every ~61 seconds per key with Locate + GetAttributes
to verify keys remain in Active state with a valid ActivationDate. This is
normal health-check behavior and produces high-volume but lightweight traffic.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
unsupported KMIP 1 operation: ReKey | KMS version < 5.22.0 missing ReKey support | Upgrade Eviden KMS to 5.22.0+ |
| Rotate key fails / cannot create new encrypted path | KMS < 5.23.0 dropped OperationPolicyName via AddAttribute | Upgrade to 5.23.0+; re-apply OPN on affected keys with AddAttribute |
OperationPolicyName warnings in KMS logs | Normal — VAST sends this deprecated KMIP 1.x attribute | No action required; informational warning only |
| TLS handshake failure | Certificate mismatch or missing CA | Verify clients_ca_cert_file matches the CA that signed VAST's client cert |
tlsv1 alert decrypt error (SSL alert 51) in KMS logs | VAST background reconnection attempt with stale connection state | Transient; no action required — the KMIP workflow itself is unaffected |
| Connection reset by peer (os error 104) | Network instability | Transient; VAST will reconnect automatically |
Verified Operations
The following KMIP operations have been validated with VAST Data production environments (logs from June 2026):
| Operation | Status | Notes |
|---|---|---|
DiscoverVersions | ✅ | Session initialization; confirms KMIP 1.4 support |
Create | ✅ | AES-256 SymmetricKey; 76 keys created across 5 days |
AddAttribute | ✅ | Called 3× per key: Name, ObjectGroup, OperationPolicyName |
Activate | ✅ | Transitions key to Active state |
Locate | ✅ | By Name (UninterpretedTextString); ~11,800 calls over 5 days |
Get | ✅ | Plaintext key material retrieval; 182 calls |
GetAttributes | ✅ | State + ActivationDate; ~11,500 calls (monitoring) |
ReKey | ✅ | Key rotation with new UUID; 16 rotations observed |
Revoke | ✅ | Key revocation before destruction; 69 calls |
Destroy | ✅ | Permanent key deletion; 69 calls |
Veeam Backup & Replication — KMS Encryption Key Management
Veeam Backup & Replication supports delegating backup encryption key management to an external KMIP-compliant Key Management Server. By connecting Veeam to Eviden KMS, encryption keys for backup jobs are never stored on the Veeam infrastructure itself: they are managed in a centrally audited, optionally HSM-backed key store.
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.4 over TCP/TLS with mutual certificate authentication |
| Port | 5696 (IANA-registered KMIP port) |
| Key type | RSA-2048 asymmetric key pair |
| Veeam version | Veeam Backup & Replication 12 and above |
| Eviden KMS feature | Works with both FIPS and non-FIPS builds |
What Veeam does
When you configure an external KMS in Veeam, the Veeam server performs the following KMIP operations for each protected backup job:
| Step | KMIP Operation | Purpose |
|---|---|---|
| 1 | Locate | Find an existing key by name / identifier |
| 2 | Get (PublicKey) | Retrieve the RSA public key to encrypt backup metadata |
| 3 | CreateKeyPair | Create a new RSA-2048 key pair when none exists |
| 4 | Activate | Transition the key pair from PreActive to Active state |
| 5 | Get (PrivateKey) | Retrieve the RSA private key for decryption during restore |
| 6 | Destroy | Delete the key pair on job removal or rotation |
Two fixes were required for full Veeam Backup & Replication compatibility. Both are included in Eviden KMS as of the version that introduced this documentation:
-
KeyValueattributes inGetresponse (bug fix): Veeam's KMIP 1.4 decoder forPublicKeyandPrivateKeyexpects theKeyValuestructure to contain only key material — it does not support anyAttributeelements insideKeyValue. Previous versions of Eviden KMS embedded all object metadata attributes (state, identifiers, links, etc.) insideKeyValuewhen converting from the internal KMIP-2.1 representation to KMIP-1.4 wire format. This caused Veeam to throwKmipUnexpectedTagException: Unexpected Tag 66, expected Attributeand abort the key retrieval. The server now strips all attributes fromKeyValuefor asymmetric keys when responding to KMIP 1.x clients. -
TLS session ID context (bug fix): Veeam reuses KMIP connections via TLS session resumption. When both
SSL_VERIFY_PEERand OpenSSL session caching are active, OpenSSL requires a session-ID context to be set on the server acceptor. Without it, session-resumption attempts fail withssl_get_prev_session:session id context uninitialized, causing each reconnect to produce an SSPI authentication error on the Veeam side. The server now callsSSL_CTX_set_session_id_contextduring TLS acceptor initialisation.
Prerequisites
- Eviden KMS server 4.x or later (both FIPS and non-FIPS builds are supported)
- TLS enabled on the KMS socket server (port 5696) with mutual certificate authentication
- A server TLS certificate and the corresponding CA to be trusted by Veeam
- A client certificate (signed by a CA known to the KMS) to authenticate Veeam
Server-Side Setup
1. Configure TLS and the KMIP socket server
Edit your kms.toml:
[tls]
tls_p12_file = "/etc/cosmian/kms/server.p12"
tls_p12_password = "your-p12-password"
clients_ca_cert_file = "/etc/cosmian/kms/clients-ca.crt"
[socket_server]
socket_server_start = true
socket_server_port = 5696
socket_server_hostname = "0.0.0.0"
2. Issue a client certificate for Veeam
Veeam identifies itself to the KMS using a client TLS certificate signed by
the clients_ca_cert_file CA:
# Generate a CA and a client certificate
openssl genrsa -out clients-ca.key 4096
openssl req -new -x509 -days 3650 -key clients-ca.key \
-subj "/CN=KMS Clients CA" -out clients-ca.crt
openssl genrsa -out veeam-client.key 2048
openssl req -new -key veeam-client.key \
-subj "/CN=veeam-backup-server" -out veeam-client.csr
openssl x509 -req -days 3650 -in veeam-client.csr \
-CA clients-ca.crt -CAkey clients-ca.key -CAcreateserial \
-out veeam-client.crt
Bundle the client certificate and key as a PKCS#12 file for import into Veeam:
openssl pkcs12 -export \
-in veeam-client.crt -inkey veeam-client.key \
-certfile clients-ca.crt \
-out veeam-client.p12 -passout pass:veeam-p12-password
3. Start Eviden KMS
cosmian_kms --config /etc/cosmian/kms/kms.toml
Or via Docker (note the -p 5696:5696 for the KMIP socket port):
docker run -p 9998:9998 -p 5696:5696 \
-v /etc/cosmian/kms:/etc/cosmian/kms:ro \
-e COSMIAN_KMS_CONF=/etc/cosmian/kms/kms.toml \
ghcr.io/cosmian/kms:latest
Veeam-Side Configuration
- In the Veeam Backup & Replication console, open Menu → Manage Credentials (or Encryption Manager depending on your version).
- Add a new KMS Server with the following parameters:
| Field | Value |
|---|---|
| Server name / IP | Hostname or IP of your Eviden KMS host |
| Port | 5696 |
| Certificate | Upload the PKCS#12 file (veeam-client.p12) |
| Password | The PKCS#12 password |
| KMS CA Certificate | Upload the KMS server CA certificate (ca.crt or the CA that signed the server certificate) |
- Click Test Connection. Veeam will perform a
Locateprobe against the server. A successful test shows a green check-mark. - Assign the KMS server to a backup job under Job Properties → Storage → Advanced → Encryption.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
KmipUnexpectedTagException: Unexpected Tag 66, expected Attribute | Old Eviden KMS version (pre-fix) embedding attributes inside KeyValue | Upgrade Eviden KMS |
A call to SSPI failed / SSL_ERROR_SSL on reconnect | TLS session-ID context not set | Upgrade Eviden KMS |
Test Connection fails with certificate error | CA mismatch or self-signed cert | Verify clients_ca_cert_file contains the CA that signed the Veeam client cert, and that Veeam trusts the KMS server certificate |
| Key not found after Veeam server migration | Unique identifier stored by Veeam differs from KMS | Re-configure the KMS server entry in Veeam; the keys remain in the KMS store |
Snowflake Native App for Large-Scale Data Encryption
Eviden offers a Snowflake Native App that seamlessly integrates with the Eviden KMS to provide robust encryption and decryption capabilities directly within your Snowflake environment. This solution builds upon the Python UDF library to deliver enterprise-grade cryptographic operations at scale.
The Native App exposes dedicated encrypt and decrypt functions that can be called directly from Snowflake SQL
queries, allowing you to implement column-level encryption without modifying your existing data workflows.
You can find the Snowflake Native App on GitHub, where comprehensive documentation covers deployment procedures, configuration options, and usage examples to help you get started quickly.
User Defined Functions in Python for Eviden KMS
Eviden maintains a Python UDF library that enables efficient, large-scale cryptographic operations with the Eviden KMS.
Purpose and Applications
These User Defined Functions (UDFs) are designed specifically for:
- Data processing platforms like PySpark, Databricks, Snowflake, and Kafka
- Implementing application-level encryption in Big Data environments
- Protecting sensitive data by encrypting it before storage and only decrypting during processing
- Minimizing clear-text exposure of sensitive information
Technical Capabilities
The library provides:
- Batch processing capabilities for efficient encryption/decryption
- Parallelization to optimize throughput
- Support for multiple encryption contexts and key identifiers
- Performance optimizations for Big Data workloads
Expected throughput is in the range of 5 million decryption in 5 seconds with a 10 vCPU KMS instance.
Supported Cryptographic Algorithms
The UDFs support several NIST-approved and RFC-standardized algorithms:
- AES-GCM (NIST SP 800-38D): Standard authenticated encryption
- AES-GCM-SIV (RFC 8452): Deterministic authenticated encryption with nonce misuse resistance
- AES-XTS (NIST SP 800-38E): Storage encryption for fixed-length data
- ChaCha20-Poly1305 (RFC 8439): High-performance authenticated encryption
Performance Considerations
Key performance factors include:
- Network latency between the UDF execution environment and KMS server
- Batch size optimization for your specific workload
- Algorithm selection based on security requirements
- Potential use of deterministic encryption (like AES-GCM-SIV) for performance-critical applications
Check the encryption and decryption a scale section for details.
Getting Started
For implementation details, examples, and best practices, refer to
the GitHub repository, particularly the tests directory which
contains practical code samples for various use cases.
FortiGate / FortiOS — External KMS via KMIP
Fortinet FortiGate appliances running FortiOS 7.4+ support delegating cryptographic key storage to an external KMIP-compliant Key Management Server. Connecting FortiOS to Eviden KMS lets network appliances retrieve their encryption keys from a centrally audited, optionally HSM-backed key store.
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.0–1.4 over TCP/TLS |
| Port | 5696 (IANA-registered KMIP port) |
| FortiOS version | FortiOS 7.4 and above (tested on FortiOS 7.6.0 / FortiGate 40F) |
| Eviden KMS feature | Works with both FIPS and non-FIPS builds |
KMIP operations used by FortiOS
| KMIP Operation | Purpose |
|---|---|
Create | Create a symmetric key |
Locate | Find an existing key by name using TemplateAttribute filter |
Get | Retrieve key material |
Activate | Transition the key to Active state |
Destroy | Delete a key on removal or rotation |
FortiOS uses an older KMIP 1.x encoding that required specific server-side fixes, included as of Eviden KMS 5.22.0:
-
Authenticationwrapper (bug fix): FortiOS wraps its credentials using the fullAuthentication { Credential { CredentialType, CredentialValue } }nesting required by the KMIP 1.0 specification. Earlier server versions looked forCredentialTypeas a direct child ofAuthenticationand failed withmissing field 'CredentialType'. The TTLV deserializer now handles the correct nesting for all KMIP 1.x clients. -
Locatename filter viaTemplateAttribute(bug fix): FortiOS wrapsAttributeitems inside aTemplateAttributestructure in theLocaterequest payload. Without the matchingtemplate_attributefield on the KMIP 1.4Locatetype, the server silently discarded the name filter, causing everyLocateto match all objects andMaximumItems=1to always return the same first key regardless of the requested name. The server now correctly readsTemplateAttribute-wrapped filters from KMIP 1.0/1.1 clients.
Configuration
1. Enable the KMIP socket server
Add a [socket_server] section to your kms.toml:
[socket_server]
port = 5696
# TLS is required; FortiOS verifies the server certificate
tls_cert_file = "/etc/kms/server.crt"
tls_key_file = "/etc/kms/server.key"
# Optional: require client certificates
# tls_ca_file = "/etc/kms/ca.crt"
See Enabling TLS and Configuration file reference for full details.
2. Configure FortiOS
In the FortiGate web UI (or via CLI):
config system kmip
set status enable
set server-ip <KMS server IP>
set server-port 5696
set ca-cert <path to KMS CA certificate>
end
Refer to the Fortinet KMIP documentation for your FortiOS version to complete key-encryption policy assignment.
Related resources
OpenSSH Integration
The Eviden KMS PKCS#11 provider enables OpenSSH to use SSH keys stored in the KMS for authentication. The private key never leaves the KMS: every signing operation is performed server-side and only the signature is returned to the SSH client.
How it works
- You create an asymmetric key pair in the KMS and tag it with
ssh-auth. - You export the corresponding public key and add it to
~/.ssh/authorized_keyson every server you want to reach. - You tell OpenSSH to use the Eviden PKCS#11 library (
libcosmian_pkcs11.so) as its hardware security token provider. - When you
sshto a server, OpenSSH callsC_Signthrough the library, which forwards the signing request to the KMS. Only the signature comes back.
Supported algorithms
| Algorithm | Key size / curve | PKCS#11 mechanism |
|---|---|---|
| ECDSA | NIST P-256 | CKM_ECDSA |
| ECDSA | NIST P-384 | CKM_ECDSA |
| EdDSA | Ed25519 | CKM_EDDSA |
| RSA PKCS#1 v1.5 | 2048 bit | CKM_RSA_PKCS |
| RSA PKCS#1 v1.5 | 4096 bit | CKM_RSA_PKCS |
Prerequisites
- A running Eviden KMS instance (see the Quick-start guide).
- The
ckmsCLI configured and authenticated against it. - OpenSSH client ≥ 7.3 (ships with every modern Linux / macOS).
- The
libcosmian_pkcs11.so(Linux) orlibcosmian_pkcs11.dylib(macOS) shared library. If you installed the Eviden KMS CLI package this is already at/usr/local/lib/libcosmian_pkcs11.so.
Step 1 — Create the SSH key pair in the KMS
Tag the key pair with ssh-auth so that the PKCS#11 provider can discover it.
ECDSA P-256 (recommended)
ckms ec keys create --curve nist-p256 --tag ssh-auth --tag my-laptop
Ed25519 (non-FIPS builds only)
ckms ec keys create --curve ed25519 --tag ssh-auth --tag my-laptop
RSA 4096
ckms rsa keys create --size_in_bits 4096 --tag ssh-auth --tag my-laptop
After the command succeeds, record the private-key ID and public-key ID printed by the CLI:
Private key unique identifier : 3fa85f64-5717-4562-b3fc-2c963f66afa6
Public key unique identifier : 3fa85f64-5717-4562-b3fc-2c963f66afa6_pk
Step 2 — Export the public key for authorized_keys
Export the public key from the KMS in PKCS#8 / SubjectPublicKeyInfo format and then convert it to
the OpenSSH wire format that goes into authorized_keys.
# Export the public key as PEM-encoded SubjectPublicKeyInfo (SPKI)
ckms ec keys export \
--key-id 3fa85f64-5717-4562-b3fc-2c963f66afa6_pk \
--key-format pkcs8-pem \
/tmp/id_ecdsa_kms.pub.pem
# Convert to OpenSSH public key format
ssh-keygen -f /tmp/id_ecdsa_kms.pub.pem -e -m pkcs8 > /tmp/id_ecdsa_kms.pub
# Optionally add a comment
cat /tmp/id_ecdsa_kms.pub
# ecdsa-sha2-nistp256 AAAA…== (no comment yet)
# Append to authorized_keys on each target server
cat /tmp/id_ecdsa_kms.pub | ssh user@server "cat >> ~/.ssh/authorized_keys"
For RSA keys, substitute ckms ec keys export with ckms rsa keys export.
Step 3 — Configure the OpenSSH client
Option A — Per-connection flag
ssh -I /usr/local/lib/libcosmian_pkcs11.so user@server
Option B — Add to ~/.ssh/config (permanent)
Host *
PKCS11Provider /usr/local/lib/libcosmian_pkcs11.so
Or scope it to a specific host:
Host my-server.example.com
User alice
PKCS11Provider /usr/local/lib/libcosmian_pkcs11.so
Environment variables
| Variable | Default | Description |
|---|---|---|
COSMIAN_KMS_CLI_CONF | ~/.cosmian/kms.toml | Path to the ckms client config (KMS URL, credentials). |
COSMIAN_PKCS11_LOGGING_LEVEL | info | Log level for the provider: trace, debug, info, warn, error. |
COSMIAN_PKCS11_SSH_KEY_TAG | ssh-auth | The KMS vendor tag used to discover SSH key pairs. Override to use a custom tag. |
Verification
# List the key pairs that the provider will expose
COSMIAN_PKCS11_LOGGING_LEVEL=debug ssh -I /usr/local/lib/libcosmian_pkcs11.so user@server whoami
You should see lines similar to the following in the debug output and the remote command's output:
debug1: provider /usr/local/lib/libcosmian_pkcs11.so: manufacturerID <cosmian>
debug1: have 1 keys from provider /usr/local/lib/libcosmian_pkcs11.so
Troubleshooting
no keys found or authentication rejected
- Verify the public key is in
~/.ssh/authorized_keyson the server. - Check the KMS tag: the private and public key pair must be tagged with
ssh-auth(or the value you set inCOSMIAN_PKCS11_SSH_KEY_TAG). - Run
ckms ec keys locate --tag ssh-authto confirm the KMS returns your key.
provider ... not supported or unsupported algorithm
- The Ed25519 / EdDSA mechanism (
CKM_EDDSA) requires a non-FIPS build of the Eviden KMS and library. In FIPS mode, use ECDSA P-256 or RSA instead.
COSMIAN_KMS_CLI_CONF not set or connection refused
- The library reads the same
ckmsconfiguration file as the CLI. Make sure the environment variable points to a valid configuration and that the KMS server is reachable.
macOS — library not loaded
macOS requires code-signed PKCS#11 libraries to be loaded by SSH. Use the .dylib built for
macOS and ensure it is in your library path:
ssh -I /usr/local/lib/libcosmian_pkcs11.dylib user@server
The Eviden KMS strives to be compatible with the PyKMIP client library, which is widely used for KMIP protocol interactions. This document provides a comprehensive guide to testing and validating PyKMIP compatibility with the Eviden KMS server.
Overview
| Item | Details |
|---|---|
| Protocol | KMIP 1.2 over TCP/TLS with mutual certificate authentication |
| Port | 5696 (IANA-registered KMIP port) |
| Library | PyKMIP (Python KMIP client library) |
| Eviden KMS feature | Requires non-FIPS build |
Purpose of PyKMIP compatibility tests
The PyKMIP compatibility tests serve to:
- Verify that our KMS server correctly implements the KMIP protocol standard
- Ensure interoperability with existing KMIP client implementations
- Catch any regression issues that might break compatibility with PyKMIP clients
- Validate that common KMIP operations work as expected across different client implementations
- Test edge cases and error handling for unsupported operations
Prerequisites
- Python 3.x installed on your system
- PyKMIP library (will be installed by setup script)
- Eviden KMS server running and accessible with KMIP socket server enabled
- All scripts must be executed from the project root directory (not from within the
scripts/directory) - Virtual environment (.venv) set up and activated for Python dependencies
Quick Start
The fastest way to test PyKMIP compatibility is to use the automated test runner:
# 1. Set up the environment (from project root)
./scripts/setup_pykmip.sh
# 2. Start the KMS server (in another terminal)\
pkill -f cosmian_kms # Stop any existing instance
COSMIAN_KMS_CONF=./scripts/kms.toml cargo run --bin cosmian_kms --features non-fips
# 3. Run all compatibility tests
./scripts/test_pykmip.sh all
# 4. Or run specific operations
./scripts/test_pykmip.sh query -v
./scripts/test_pykmip.sh create
./scripts/test_pykmip.sh check
The test runner automatically:
- Activates the Python virtual environment
- Validates prerequisites and connectivity
- Executes the requested operations with proper error handling
- Provides detailed output and status reporting
- Runs with timeout protection to prevent hanging tests
Supported Operations
The current test suite supports the following KMIP operations:
Core Operations
- query - Discover server capabilities and protocol versions
- create - Create symmetric keys
- create_keypair - Create RSA key pairs
- get - Retrieve an object
- get_attributes - Retrieve object attributes
- destroy - Delete objects from the server
- locate - Find objects by search criteria
Cryptographic Operations
- encrypt - Encrypt data using managed keys
- decrypt - Decrypt data using managed keys
- mac - Generate Message Authentication Codes
- activate - Activate objects for use
Management Operations
- revoke - Revoke objects and certificates
- discover_versions - Discover supported KMIP protocol versions
Special Commands
- all - Execute all supported operations in sequence
- check - Validate prerequisites and connectivity
- rust-test - Run Rust-based PyKMIP integration tests
Experimental/Unsupported Operations
- certify - Certificate signing (implemented via separate module
pykmip_certify.py, uses operations not yet supported by Eviden KMS)
Note: Some operations may fail due to server limitations or KMIP 1.x compatibility constraints. The test runner handles these gracefully and provides detailed error reporting.
Understanding Test Results
The test script provides comprehensive output for each operation with clear status indicators:
Success Case
Operations that complete successfully will show:
{
"operation": "Create",
"status": "success",
"unique_identifier": "abc123-def456-789",
"additional_info": {
...
}
}
Failure Case
Operations that fail will show:
{
"operation": "MAC",
"status": "error",
"error": "Invalid parameter provided",
"details": "Cryptographic algorithm not supported"
}
Test Summary
After running all operations, you'll see a summary like:
======================================
FINAL TEST RESULTS SUMMARY
======================================
✅ SUCCESSFUL operations (12/13):
✅ query
✅ create
✅ get_attributes
✅ get
✅ destroy
✅ encrypt
✅ decrypt
✅ locate
✅ discover_versions
✅ mac
✅ activate
✅ revoke
✅ create_keypair
🔍 certify (not supported in PyKMIP - workaround under study)
Operation Status Types
- ✅ SUCCESS: Operation completed and returned successful status
- ❌ FAILED: Operation returned error status or threw exception
- ⚠️ TIMEOUT: Operation timed out after 30 seconds
- 🔍 UNSUPPORTED: Operation not supported by server or KMIP version
Troubleshooting
Common Issues
-
Script execution fails: Ensure you're running from the project root, not from
scripts/# Wrong - don't do this cd scripts && ./test_pykmip.sh # Correct - run from project root ./scripts/test_pykmip.sh all -
PyKMIP import errors: Run
setup_pykmip.shto install dependenciesError: No module named 'kmip' Solution: ./scripts/setup_pykmip.sh -
Connection refused: Verify the KMS server is running with KMIP socket server enabled
Error: Connection refused on port 5696 Solution: Check server is running and socket_server_start = true in config -
Virtual environment not found: The test runner requires a .venv directory
Error: Virtual environment not found Solution: Run ./scripts/setup_pykmip.sh to create .venv -
TLS/Certificate errors: Verify certificate paths and validity
Error: [SSL: CERTIFICATE_VERIFY_FAILED] Solution: Check certificate files in test_data/certificates/client_server/ -
Operation timeouts: Some operations may timeout due to server processing time
Error: Operation timed out after 30 seconds Solution: Check server logs, increase timeout, or use -v for verbose output
Advanced Troubleshooting
Enable verbose output to see detailed operation information:
./scripts/test_pykmip.sh query -v
Check server logs while running tests:
# In another terminal
tail -f logs/server.log
Test connectivity manually:
./scripts/test_pykmip.sh check
Run individual operations to isolate issues:
./scripts/test_pykmip.sh create -v
./scripts/test_pykmip.sh get -v
File Structure
The PyKMIP test suite consists of the following files:
scripts/
├── README_PYKMIP.md # Additional documentation
├── setup_pykmip.sh # Environment setup script
├── verify_pykmip.sh # Configuration verification script
├── test_pykmip.sh # Main compatibility test runner
├── pykmip_client.py # PyKMIP client implementation (12 operations)
├── pykmip_certify.py # Separate certify operation module
├── pykmip.conf # PyKMIP configuration file
├── kms.toml # KMS server configuration for testing
├── activate_venv.sh # Virtual environment activation helper
└── certify_implementation_summary.py # Certify operation analysis script
Key Files
test_pykmip.sh: Main test runner with colored output, timeout protection, and comprehensive error handlingpykmip_client.py: Core client implementing 12 KMIP operations with JSON output formattingpykmip_certify.py: Modular implementation of certificate-related operations (experimental)pykmip.conf: Configuration file with TLS settings, authentication, and server connection detailskms.toml: KMS server configuration optimized for PyKMIP compatibility testing
Configuration
The pykmip.conf file contains the connection settings for the PyKMIP client. Key configuration sections:
Server Connection
[server]
host=127.0.0.1
port=5696
TLS Configuration
[tls]
client_cert_file=test_data/certificates/client_server/owner/owner.client.acme.com.crt
client_key_file=test_data/certificates/client_server/owner/owner.client.acme.com.key
ca_cert_file=test_data/certificates/client_server/ca/ca.crt
Protocol Settings
[protocol]
kmip_version=1.0
Ensure these parameters match your KMS server setup:
- Server hostname/IP and port (default: 127.0.0.1:5696)
- TLS certificate paths (must exist and be valid)
- KMIP protocol version compatibility
KMS Server Configuration
Your KMS server must be configured to accept KMIP connections. Key settings in scripts/kms.toml:
[server]
# Enable KMIP socket server
socket_server_start = true
socket_server_port = 5696
socket_server_hostname = "0.0.0.0"
[tls]
# Server certificate and key
# For FIPS mode (default build):
tls_cert_file = "test_data/certificates/client_server/server/kmserver.acme.com.crt"
tls_key_file = "test_data/certificates/client_server/server/kmserver.acme.com.key"
# For non-FIPS mode:
# tls_p12_file = "test_data/certificates/client_server/server/kmserver.acme.com.p12"
# tls_p12_password = "password"
clients_ca_cert_file = "test_data/certificates/client_server/ca/ca.crt"
Contributing
When adding new PyKMIP compatibility tests:
-
Add new operations to the
operationsarray intest_pykmip.sh:operations=("activate" "create" "create_keypair" "decrypt" "destroy" "discover_versions" "encrypt" "get" "locate" "mac" "query" "revoke") -
Implement operation functions in
pykmip_client.py:def perform_new_operation(proxy, verbose=False): """Implement new KMIP operation""" if verbose: print("Performing new operation...") # Implementation here return {"operation": "NewOperation", "status": "success"} -
Add to argument parser choices in
pykmip_client.py:parser.add_argument('--operation', default='query', choices=['activate', 'create', ..., 'new_operation'], help='KMIP operation to perform') -
Update help text in
test_pykmip.shto include the new operation -
Handle modular operations like certify by creating separate files:
- Create
pykmip_operation.pyfor complex operations - Import and call from main client:
from pykmip_operation import perform_operation
- Create
-
Test both success and failure scenarios to ensure proper error handling
-
Update this README if new setup steps or dependencies are required
Testing Best Practices
- Always test with both verbose (
-v) and normal output modes - Verify operations work individually and in the "all" test suite
- Check for JSON serialization issues with complex data types
- Ensure timeout handling works correctly for long-running operations
- Document any server limitations or KMIP version constraints
Available Operations (Detailed Examples)
Using the Test Runner (Recommended)
The test runner (test_pykmip.sh) automatically handles environment setup and provides consistent output formatting:
# Run all operations with summary report
./scripts/test_pykmip.sh all
# Run specific operation with verbose output
./scripts/test_pykmip.sh query -v
# Check prerequisites and connectivity
./scripts/test_pykmip.sh check
# Run individual operations
./scripts/test_pykmip.sh create
./scripts/test_pykmip.sh encrypt
./scripts/test_pykmip.sh mac
Manual Client Usage (Advanced)
For direct client access with custom parameters:
1. Query Server Capabilities
source .venv/bin/activate
python scripts/pykmip_client.py \
--configuration scripts/pykmip.conf \
--operation query \
--verbose
2. Create Symmetric Key
source .venv/bin/activate
python scripts/pykmip_client.py \
--configuration scripts/pykmip.conf \
--operation create
3. Create RSA Key Pair
source .venv/bin/activate
python scripts/pykmip_client.py \
--configuration scripts/pykmip.conf \
--operation create_keypair
4. Test Encryption/Decryption
source .venv/bin/activate
python scripts/pykmip_client.py \
--configuration scripts/pykmip.conf \
--operation encrypt
python scripts/pykmip_client.py \
--configuration scripts/pykmip.conf \
--operation decrypt
5. Activate Objects
source .venv/bin/activate
python scripts/pykmip_client.py \
--configuration scripts/pykmip.conf \
--operation activate
Related Documentation
- KMIP Protocol Support
- TLS Configuration
- Authentication
- PyKMIP Official Documentation
- Eviden KMS Server Documentation
Deploying email encryption with S/MIME
S/MIME is a standard for public key encryption and signing of MIME data. It is used to secure email messages and is supported by most email clients and servers.
- Deploying email encryption with S/MIME
- Overview of the S/MIME workflow
- Generating a key pair and a certificate
- Exporting and viewing
- Loading the PKCS#12 file in an email client
- Apple mail, MacOS
- Outlook, Windows
Overview of the S/MIME workflow
To enable S/MIME, a user will go through the following steps:
Setup (once)
- Generate a key pair and a certificate holding the correct x509 extensions for S/MIME
- Import this certificate and private key (usually in the form of a PKCS#12 file) in its email client
Handshake (once per recipient)
- Send a signed, non-encrypted, email to a recipient to share its certificate
- Receive a signed, encrypted, or non-encrypted, email from the recipient and import its certificate
No further actions are required to exchange signed encrypted emails with this recipient.
Generating a key pair and a certificate
For interoperability, the user certificate should be ultimately signed by a public certificate authority commonly found on email clients. If you want to use your own certificate authority, for internal use or test purposes, please see the instructions below on how to create a root CA and an intermediate CA.
Please note that these certificates require certain x509 extensions to be compatible with Google CSE S/MIME and some other operators. Check the Google requirements for details.
For a user, there are 3 main possibilities to generate a key pair and an S/MIME certificate:
Getting a user certificate from a public certificate authority
Many public authorities can issue user S/MIME certificates. Some authorities even provide free certificates for personal use. This is the case of Actalis for instance.
!!! important Case sensitivity Some email clients, such as Outlook, consider the email address to be case-sensitive. Make sure the email address in your request matches the email address you are using in your email client.
Once generated, these authorities will provide you with a PKCS#12 file containing the certificate and the private key. The file is usually protected by a password.
This file can directly be imported in your email client.
If you wish to store it in the KMS, you can import it using the following command:
ckms certificates import --format pkcs12 --pkcs12-password mysecret \
--replace john_doe.p12 john.doe@acme.com
To export it as a PEM file, use the following command:
ckms certificates export --format pem --certificate-id john.doe@acme.com john_doe.pem
Getting an intermediate signer certificate from a public certificate authority
If you have many users, you will probably want top buy an intermediate certificate from a public certificate authority. This intermediate certificate will be used to sign the user certificates.
First, import the intermediate certificate and its private key in the KMS:
ckms certificates import --format pkcs12 --pkcs12-password mysecret \
--replace intermediate.p12 acme_intermediate_ca
Then generate a user certificate signed by the intermediate certificate.
Creating an S/MIME certificate authority with a root and intermediate CA
If you wish to be your own certificate authority, you can create a root and an intermediate CA.
Create a Root CA
Say, we are ACME Inc. Let us create a self-signed root certificate with the following details:
- Common Name: ACME Root CA
- Organization: ACME
- Organizational Unit: IT
- Locality: New York
- State: New York
- Country: US
- Validity: 10 years (3650 days)
- Key Algorithm: NIST P-256
ckms certificates certify \
--certificate-id acme_root_ca \
--generate-key-pair \
--algorithm rsa4096 \
--subject-name "CN=ACME Root CA,OU=IT,O=ACME,L=New York,ST=New York,C=US" \
--days 3650 \
--certificate-extensions ca.ext
The ca.ext file should contain the following content (which should meet Google CSE):
[ v3_ca ]
subjectKeyIdentifier=hash
basicConstraints=critical,CA:TRUE
Create an Intermediate CA
Let us create an intermediate CA signed by the Root CA. This intermediate will be used to issue end-users S/MIME certificates. It will be created with the following details:
- Common Name: ACME Intermediate CA
- Organization: ACME
- Organizational Unit: IT
- Locality: New York
- State: New York
- Country: US
- Validity: 5 years (1825 days)
- Key Algorithm: NIST P-256
- Extensions: a
intermediate.extfile with the following content:
[ v3_ca ]
basicConstraints=critical,CA:TRUE,pathlen:0
keyUsage=critical,keyCertSign,digitalSignature
extendedKeyUsage=emailProtection
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
crlDistributionPoints=URI:https://acme.com/crl.pem
Note: these extensions make the intermediate CA compatible with Google CSE for GMail S/MIME requirements
ckms certificates certify \
--certificate-id acme_intermediate_ca \
--issuer-certificate-id acme_root_ca \
--generate-key-pair \
--algorithm rsa4096 \
--subject-name "CN=ACME S/MIME intermediate,OU=IT,O=ACME,L=New York,ST=New York,C=US" \
--days 1825 \
--certificate-extensions intermediate.ext
Generate a user certificate signed by the intermediate certificate
Then, generate a user certificate signed by the intermediate certificate:
Important some email clients, such as Outlook, consider the email address to be case-sensitive. Make sure the email address in the certificate Common Name matches the email address you are using in your email client.
To be used for S/MIME, the user certificate needs to have certain extensions which are set in a
file containing a [ v3_ca ] section.
Say we want to create an S/MIME certificate for user john.doe@acme.com, signed by the intermediate certificate, with the following details:
- Common Name: john.doe@acme.com
- Organization: ACME
- Organizational Unit: IT
- Locality: San Francisco
- State: California
- Country: US
- Validity: 1 year (365 days)
- Key Algorithm: NIST P-256
- Extensions: a user.ext file with the following content:
The user.ext file should contain the following content (which should meet Google CSE
requirements):
[ v3_ca ]
keyUsage=critical,nonRepudiation,digitalSignature,dataEncipherment,keyEncipherment
extendedKeyUsage=emailProtection
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
Issue the following command to generate the certificate:
ckms certificates certify --certificate-id john.doe@acme.com \
--issuer-certificate-id acme_intermediate_ca \
--generate-key-pair --algorithm nist-p256 \
--subject-name "CN=john.doe@acme.com,OU=IT,O=ACME,L=San Francisco,ST=California,C=US" --days 365 \
--certificate-extensions user.ext
Exporting and viewing
Use the ckms certificates export command to export the certificate and the private key in the
desired format. Most email clients require the certificate and the private key to be in a PKCS#12
file.
PKCS#12 format
To export the certificate and the private key in PKCS#12 format,
use either the pkcs12 or pkcs12-legacy format option.
The pkcs12-legacy format is deprecated but is compatible with older versions of OpenSSL (1.1.x)
and some keystores such as the Java keystore or the macOS keychain.
ckms certificates export --certificate-id john.doe@acme.com \
--format pkcs12-legacy --pkcs12-password mysecret \
john_doe.p12
OpenSSL can be used to view the content of the PKCS#12 file.
You will need to provide the password you used to protect the file (mysecret above).
If you are using OpenSSL 3.0 and above and want to view a legacy PKCS#12 file,
add the -legacy option:
> openssl pkcs12 -info -in john_doe.p12 -nodes
Enter Import Password:
MAC Iteration 2048
MAC verified OK
PKCS7 Encrypted data: Certificate bag
Bag Attributes
localKeyID: 82 C3 F3 83 32 68 ED B4 71 15 96 12 0B 01 4C 34 8D 58 DC 58
subject=/CN=john.doe@acme.com/OU=IT/C=US/ST=California/L=San Francisco/O=ACME
issuer=/CN=ACME S/MIME intermediate/OU=IT/C=US/ST=New York/L=New York/O=ACME
-----BEGIN CERTIFICATE-----
MIICQDCCAeagAwIBAgIBADAKBggqhkjOPQQDAjByMSEwHwYDVQQDDBhBQ01FIFMv
TUlNRSBpbnRlcm1lZGlhdGUxCzAJBgNVBAsMAklUMQswCQYDVQQGEwJVUzERMA8G
A1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZb3JrMQ0wCwYDVQQKDARBQ01F
MB4XDTI0MDkxMzA5MzkwMloXDTI1MDkxMzA5MzkwMlowcjEaMBgGA1UEAwwRam9o
bi5kb2VAYWNtZS5jb20xCzAJBgNVBAsMAklUMQswCQYDVQQGEwJVUzETMBEGA1UE
CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwE
QUNNRTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOvAZj+RBjElLMWVipGx+rbG
mniD8NApM2inWLN+1avvd2QslOh9mhiT18u2KJkrjG9hIbVh8cyr4/dxtWL6Goij
bTBrMAsGA1UdDwQEAwIDyDATBgNVHSUEDDAKBggrBgEFBQcDBDAcBgNVHREEFTAT
gRFqb2huLmRvZUBhY21lLmNvbTApBgNVHR8EIjAgMB6gHKAahhhodHRwczovL2Fj
bWUuY29tL2NybC5wZW0wCgYIKoZIzj0EAwIDSAAwRQIgYUf5lGAU3dQ9wIPdX5x+
RtJioGwdVZZmprEAdNL203wCIQDbDk9yRjfPUUWph05LlC45EA8B3OJYEShdo3s9
pImIww==
-----END CERTIFICATE-----
Certificate bag
Bag Attributes: <No Attributes>
subject=/CN=ACME S/MIME intermediate/OU=IT/C=US/ST=New York/L=New York/O=ACME
issuer=/CN=ACME Root CA/OU=IT/C=US/ST=New York/L=New York/O=ACME
-----BEGIN CERTIFICATE-----
MIICJjCCAc2gAwIBAgIBADAKBggqhkjOPQQDAjBmMRUwEwYDVQQDDAxBQ01FIFJv
b3QgQ0ExCzAJBgNVBAsMAklUMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlv
cmsxETAPBgNVBAcMCE5ldyBZb3JrMQ0wCwYDVQQKDARBQ01FMB4XDTI0MDkxMzA5
MzYwNVoXDTI5MDkxMjA5MzYwNVowcjEhMB8GA1UEAwwYQUNNRSBTL01JTUUgaW50
ZXJtZWRpYXRlMQswCQYDVQQLDAJJVDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5l
dyBZb3JrMREwDwYDVQQHDAhOZXcgWW9yazENMAsGA1UECgwEQUNNRTBZMBMGByqG
SM49AgEGCCqGSM49AwEHA0IABEG7Ei75r1WuGrfMdXEQseoxf4n5KM7Bov5GIP+0
ZSHt2CYEgIkvBElHiLtDs2XP8vPmHKQPA2fOTIqsxGG7NPijYDBeMA8GA1UdEwQI
MAYBAf8CAQAwCwYDVR0PBAQDAgKEMBMGA1UdJQQMMAoGCCsGAQUFBwMEMCkGA1Ud
HwQiMCAwHqAcoBqGGGh0dHBzOi8vYWNtZS5jb20vY3JsLnBlbTAKEBggqhkjOPQQD
AgNHADBEAiBbVpxNtT+wLNxAUIrA9r9fR4UT1aCw15rShZZiCjrvcAIgURwRsODz
bB/+NeaLa9WgwjtZk7Vm1c7fVnb30TBcN78=
-----END CERTIFICATE-----
Certificate bag
Bag Attributes: <No Attributes>
subject=/CN=ACME Root CA/OU=IT/C=US/ST=New York/L=New York/O=ACME
issuer=/CN=ACME Root CA/OU=IT/C=US/ST=New York/L=New York/O=ACME
-----BEGIN CERTIFICATE-----
MIIBujCCAV+gAwIBAgIBADAKBggqhkjOPQQDAjBmMRUwEwYDVQQDDAxBQ01FIFJv
b3QgQ0ExCzAJBgNVBAsMAklUMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlv
cmsxETAPBgNVBAcMCE5ldyBZb3JrMQ0wCwYDVQQKDARBQ01FMB4XDTI0MDkxMzA5
MzQxNFoXDTM0MDkxMTA5MzQxNFowZjEVMBMGA1UEAwwMQUNNRSBSb290IENBMQsw
CQYDVQQLDAJJVDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYD
VQQHDAhOZXcgWW9yazENMAsGA1UECgwEQUNNRTBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABPj86uAwMjnITXnnnLY9wmHbxtGz2IWAN7JLdbmD77RfbpvcK+BxMzVI
20ITcWv8dyfhcMLyBa+ygDVPgVK1jLQwCgYIKoZIzj0EAwIDSQAwRgIhAJenykHa
jjVPke8vX+GyaMTqNJZN94QyCYHgqUeDeZVCAiEAuokqc/TfyzvkzmWcJgeGsFyM
Nk/pqUsPr8eR1sHQWgg=
-----END CERTIFICATE-----
PKCS7 Data
Shrouded Keybag: Bag Attributes
localKeyID: 82 C3 F3 83 32 68 ED B4 71 15 96 12 0B 01 4C 34 8D 58 DC 58
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIGHTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQge5si3Le85K18XOLc
ae8QE50qCE0yUMipcPvHwZM1k1ChRANCAATrwGY/kQYxJSzFlYqRsfq2xpp4g/DQ
KTNop1izftWr73dkLJTofZoYk9fLtiiZK4xvYSG1YfHMq+P3cbVi+hqI
-----END PRIVATE KEY-----
Exporting for Google CSE S/MIME
To export the expected Google CSE Root certificate in order to import it in the Apps/Google Workspace/Settings for Gmail/User Settings, proceed as follows:
openssl pkcs12 -in john_doe.p12 -cacerts -nokeys -out ca.pem -passin pass:"$MY_PASSWD"
openssl pkcs12 -in john_doe.p12 -clcerts -nokeys -out certificate.pem -passin pass:"$MY_PASSWD"
cp certificate.pem fullchain.pem
cat ca.pem >>fullchain.pem
PEM format
To export the certificate only, in PEM format, use the following command:
ckms certificates export --certificate-id john.doe@acme.com --format pem john_doe.pem
You can then view its content, using openssl for instance:
> openssl x509 -inform pem -text -in john_doe.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN=ACME S/MIME intermediate, OU=IT, C=US, ST=New York, L=New York, O=ACME
Validity
Not Before: Sep 11 14:09:25 2024 GMT
Not After : Sep 11 14:09:25 2025 GMT
Subject: CN=john.doe@acme.com, OU=IT, C=US, ST=California, L=San Francisco, O=ACME
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:4b:0e:f2:7b:5b:93:91:1c:4a:a2:d1:91:24:ce:
a4:6e:97:5c:41:9f:fd:92:74:70:83:05:64:69:58:
41:46:c5:64:bc:5e:89:30:d6:83:c8:06:64:f6:e8:
b9:a2:a9:2f:ad:e5:93:fd:49:45:4c:e5:c3:2b:29:
e1:7e:a0:16:a9
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Agreement
X509v3 Extended Key Usage:
E-mail Protection
X509v3 Subject Alternative Name:
<EMPTY>
X509v3 CRL Distribution Points:
Full Name:
URI:https://acme.com/crl.pem
Signature Algorithm: ecdsa-with-SHA256
30:45:02:21:00:cf:31:c9:f1:a7:d7:f5:cd:3a:b6:e3:4e:13:
20:ef:e1:6d:b9:21:55:66:27:c4:5d:b0:68:29:f2:07:7e:5b:
eb:02:20:1d:92:ff:52:1d:c2:f1:ab:34:f7:d7:f1:29:87:bc:
f5:33:3c:0b:6c:93:23:4c:4f:c7:69:c1:df:23:95:0e:78
-----BEGIN CERTIFICATE-----
MIICLTCCAdOgAwIBAgIBADAKBggqhkjOPQQDAjByMSEwHwYDVQQDDBhBQ01FIFMv
TUlNRSBpbnRlcm1lZGlhdGUxCzAJBgNVBAsMAklUMQswCQYDVQQGEwJVUzERMA8G
A1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZb3JrMQ0wCwYDVQQKDARBQ01F
MB4XDTI0MDkxMTE0MDkyNVoXDTI1MDkxMTE0MDkyNVowcjEaMBgGA1UEAwwRam9o
bi5kb2VAYWNtZS5jb20xCzAJBgNVBAsMAklUMQswCQYDVQQGEwJVUzETMBEGA1UE
CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwE
QUNNRTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEsO8ntbk5EcSqLRkSTOpG6X
XEGf/ZJ0cIMFZGlYQUbFZLxeiTDWg8gGZPbouaKpL63lk/1JRUzlwysp4X6gFqmj
WjBYMAsGA1UdDwQEAwIDyDATBgNVHSUEDDAKBggrBgEFBQcDBDAJBgNVHREEAjAA
MCkGA1UdHwQiMCAwHqAcoBqGGGh0dHBzOi8vYWNtZS5jb20vY3JsLnBlbTAKEBggq
hkjOPQQDAgNIADBFAiEAzzHJ8afX9c06tuNOEyDv4W25IVVmJ8RdsGgp8gd+W+sC
IB2S/1IdwvGrNPfX8SmHvPUzPAtskyNMT8dpwd8jlQ54
-----END CERTIFICATE-----
Loading the PKCS#12 file in an email client
Apple mail, MacOS
To use your S/MIME certificate, load it in the login keychain:

Then, in the Mail application, create a new email and tick the "encrypt" and "sign" boxes:

When handshaking with a new recipient, send a signed email to the recipient (not encrypted).
When receiving a signed email from the recipient, import the recipient's certificate in your contacts.
Outlook, Windows
Setup
In Outlook (classic) go to File -> Options -> Trust Center -> Trust Center Settings

Then go to Email Security and click on Import/Export to import the PKCS#12 file.

Finally, go to the Email Security and click the Settings... button of Default Setting. In the popup, select the certificate you just imported, adjust the hash algorithm to SHA256 for maximum compatibility and make sure you tick the box "Send these certificates with signed messages."

Sending a message
Click on New Email, then Options -> Encrypt and Sign.
To perform a handshake with a new recipient, send a first email to the recipient that is signed only (not encrypted).

Eviden KMS can be installed on various platforms, including Docker, Ubuntu, Rocky Linux, macOS, and Windows.
It is prepackaged with an integrated web ui (except for macOS) that is available on the /ui path of the server.
The KMS is also available on the marketplaces of major cloud providers, prepackaged to run confidentially in an Eviden VM. Please check this page for more information.
When installed using the options below, the KMS server will be automatically configured to run using an SQLite database. If you wish to change the database configuration, please refer to the database guide.
For high availability and scalability, refer to the High Availability Guide.
Verifying release signatures
All Eviden KMS release packages (DEB, RPM, DMG) are GPG-signed.
Each package is accompanied by a .asc signature file that can be used to verify its authenticity and integrity.
Import the Eviden public key**
gpg --import cosmian-kms-public.asc
The key is also bundled inside DMG installers and available in the GitHub repository.
Verify a downloaded package**
gpg --verify <package>.asc <package>
For example:
# Debian package
gpg --verify cosmian-kms-server-non-fips-static-openssl_5.25.0_amd64.deb.asc \
cosmian-kms-server-non-fips-static-openssl_5.25.0_amd64.deb
# RPM package
gpg --verify cosmian-kms-server-non-fips-static-openssl_5.25.0_x86_64.rpm.asc \
cosmian-kms-server-non-fips-static-openssl_5.25.0_x86_64.rpm
# DMG package
gpg --verify cosmian-kms-server-non-fips-static-openssl-5.25.0_arm64.dmg.asc \
cosmian-kms-server-non-fips-static-openssl-5.25.0_arm64.dmg
A successful verification prints:
gpg: Good signature from "Eviden KMS Release <tech@cosmian.com>"
!!!warning If the signature does not match, do not use the package.
Installation
!!!info "KMS CLI" The KMS CLI lets you interact with the KMS from the command line. Install it from KMS CLI and configure it.
Run the container as follows:
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest
- The KMS UI is available at
http://localhost:9998/ui. - The KMS REST API is available on
http://localhost:9998, - The server stores its data inside the container in the
/root/cosmian-kms/sqlite-datadirectory.
A FIPS version is also available:
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms-fips:latest
To persist data between restarts, mount the /root/cosmian-kms/sqlite-data path to a filesystem
directory or a Docker volume:
docker run --rm -p 9998:9998 \
-v cosmian-kms:/root/cosmian-kms/sqlite-data \
--name kms ghcr.io/cosmian/kms:latest
A custom configuration file can be provided by mounting it in the container:
docker run --rm -p 9998:9998 \
-v cosmian-kms:/root/cosmian-kms/sqlite-data \
-v /path/to/your/kms.toml:/etc/cosmian/kms.toml \
--name kms ghcr.io/cosmian/kms:latest
Download the package and install it (works on all Debian distributions from Debian 10):
sudo apt update && sudo apt install -y wget
# Standard build (non-FIPS, static OpenSSL)
wget https://package.cosmian.com/kms/5.25.0/deb/amd64/non-fips/static/cosmian-kms-server-non-fips-static-openssl_5.25.0_amd64.deb
sudo apt install ./cosmian-kms-server-non-fips-static-openssl_5.25.0_amd64.deb
sudo cosmian_kms --version
Or install the FIPS build:
wget https://package.cosmian.com/kms/5.25.0/deb/amd64/fips/static/cosmian-kms-server-fips-static-openssl_5.25.0_amd64.deb
sudo apt install ./cosmian-kms-server-fips-static-openssl_5.25.0_amd64.deb
sudo cosmian_kms --version
A cosmian_kms service will be configured; the service file is located at /etc/systemd/system/cosmian_kms.service.
To start the KMS, run:
sudo systemctl start cosmian_kms
- The server uses the configuration file located at
/etc/cosmian/kms.toml. - The KMS UI is available at
http://localhost:9998/ui.
Download the package and install it (works for Rocky Linux 8/9/10):
sudo dnf update && sudo dnf install -y wget
wget https://package.cosmian.com/kms/5.25.0/rpm/amd64/non-fips/static/cosmian-kms-server-non-fips-static-openssl_5.25.0_x86_64.rpm
sudo dnf install ./cosmian-kms-server-non-fips-static-openssl_5.25.0_x86_64.rpm
sudo cosmian_kms --version
To start the KMS, run:
sudo systemctl start cosmian_kms
- The server uses the configuration file located at
/etc/cosmian/kms.toml. - The KMS UI is available at
http://localhost:9998/ui.
Download the installer for your architecture and run it:
-
Apple Silicon (ARM64):
open "https://package.cosmian.com/kms/5.25.0/dmg/arm64/non-fips/static/cosmian-kms-server-non-fips-static-openssl-5.25.0_arm64.dmg"
Then drag-and-drop the app to Applications or follow the DMG instructions.
Note: The 5.25.0 DMG is provided for Apple Silicon (ARM64).
After installation, run:
/Applications/Cosmian\ KMS\ Server.app/Contents/MacOS/cosmian_kms --version
/Applications/Cosmian\ KMS\ Server.app/Contents/MacOS/cosmian_kms
- The server uses the configuration file located at
/etc/cosmian/kms.toml. - The KMS UI is available at
http://localhost:9998/ui.
Static vs Dynamic builds
- Static builds: ship with OpenSSL statically linked into the binary. Simplest to deploy; no external crypto libraries required; consistent behavior across environments.
- Dynamic builds: link OpenSSL dynamically. This allows replacing the OpenSSL shared library at runtime to use custom or system-provided crypto. On Linux, replace the relevant
.sofiles; on macOS, replace the.dylibfiles, ensuring ABI compatibility.
Available dynamic packages for Debian-based distributions:
# Non-FIPS dynamic (OpenSSL linked dynamically)
wget https://package.cosmian.com/kms/5.25.0/deb/amd64/non-fips/dynamic/cosmian-kms-server-non-fips-dynamic-openssl_5.25.0_amd64.deb
# FIPS dynamic
wget https://package.cosmian.com/kms/5.25.0/deb/amd64/fips/dynamic/cosmian-kms-server-fips-dynamic-openssl_5.25.0_amd64.deb
Available dynamic packages for Rocky Linux:
# Non-FIPS dynamic
wget https://package.cosmian.com/kms/5.25.0/rpm/amd64/non-fips/dynamic/cosmian-kms-server-non-fips-dynamic-openssl_5.25.0_x86_64.rpm
# FIPS dynamic
wget https://package.cosmian.com/kms/5.25.0/rpm/amd64/fips/dynamic/cosmian-kms-server-fips-dynamic-openssl_5.25.0_x86_64.rpm
To use custom OpenSSL with dynamic builds, install or place the desired OpenSSL
shared libraries here: /usr/local/cosmian/lib/ossl-modules.
On Windows, download the NSIS installer:
https://package.cosmian.com/kms/5.25.0/windows/x86_64/non-fips/static-openssl/cosmian-kms-server-non-fips-static-openssl_5.25.0_x86_64.exe
Run the installer to install Eviden KMS Server. The installer will:
- Install the KMS server with integrated web UI
- Set up the configuration file at
C:\Users\<username>\AppData\Local\Cosmian KMS Server\kms.toml
After installation, you can run the server:
cosmian_kms --version
- The KMS UI is available at
http://localhost:9998/ui - The server uses the configuration file located at
C:\Users\<username>\AppData\Local\Cosmian KMS Server\kms.toml - See the server configuration for more information
A KMS-ready instance based on Eviden Confidential VM can be deployed on virtual machines that supports AMD SEV-SNP or Intel TDX technologies, and is available on the marketplace of the major cloud providers.
If you are interested in the confidential computing technology and the Eviden VM, please first read the guide about how to setup an Eviden VM.
Deploy Eviden VM KMS on a cloud provider
Go the Eviden marketplace webpage of the chosen cloud provider.
Select an OS and continue until the Eviden VM KMS instance is spawned.
!!! important Cloud provider support
Here's the list of instance types by cloud provider
| Cloud provider | Azure | GCP | AWS |
| -------------- | ----------------- | ------------ | ------------- |
| **AMD** | **SNP** | **SNP** | **SNP** |
| | Standard_DCas_v5 | n2d-standard | M6a |
| | Standard_DCads_v5 | | C6a |
| | | | R6a |
| **Intel** | **TDX** | **TDX** | **TDX** |
| | DCes_v5-series | c3-standard | Not available |
| | ECesv5-series | | |
| | (preview) | | |
The Eviden KMS contains:
- a ready-to-go Nginx setup (listening on port
443and locally on port9998) - a ready-to-go KMS service
- the Eviden VM software stack. As reminder, Eviden VM Agent is listening
on port
5555.
Configure the KMS 📜
Default configuration
By default:
- the KMS server is locally listening on port 9998
- its database is a local Redis database with encrypted data using the scheme Findex.
- the KMS configuration file is located in the encrypted LUKS container
at
/var/lib/cosmian_vm/data/app.confand has the following content:
default_username = "admin"
[http]
port = 9998
hostname = "0.0.0.0"
[db]
database_type = "redis-findex"
database_url = "redis://0.0.0.0:6379"
redis_master_password = "master-password"
For testing purposes (connectivity, features, etc.), KMS server can also use a SQLite database by modifying the configuration file:
default_username = "admin"
[http]
port = 9998
hostname = "0.0.0.0"
!!! important Protect your secrets
The Eviden KMS configuration can potentially contain secrets
(such as this `redis_master_password` field), that is why
the configuration file is save in a LUKS container (default path: `/var/lib/cosmian_vm/data`).
To override the default
configuration, a new configuration SHOULD be sent remotely and securely via
the Eviden VM CLI following [see app init](#override-the-default-configuration).
Override the default configuration
The default configuration can be overridden remotely by using the Eviden VM CLI without any SSH connection.
It is safe to provide secrets (such as passwords) in
the configuration file because this file is going to be stored in the encrypted
folder (LUKS) of the Eviden VM KMS (which is mounted by default on /var/lib/cosmian_vm/data).
Eviden VM CLI has to be installed on the client machine (Ubuntu, RHEL or via Docker). Please follow the installation instructions.
Then proceed as follows:
cosmian_vm --url https://${EVIDEN_KMS_IP_ADDR}:5555 \
--allow-insecure-tls \
app init -c kms.toml
Processing the init of the deployed app...
The app has been configured and started
This command will send via an encrypted tunnel the configuration that will be
written in the remotely path /var/lib/cosmian_vm/data/app.conf which is
contained in an encrypted container (LUKS).
where kms.toml can be:
default_username = "admin"
[http]
port = 9998
hostname = "0.0.0.0"
[db]
database_type = "redis-findex"
database_url = "redis://<EXTERNAL_HOSTNAME_OR_IP>:6379"
redis_master_password = "master-password"
- The database type
redis-findexis a Redis database with encrypted data and encrypted indexes thanks to Cosmian Findex. - The
database_urlpoints to the Redis, typically an external managed Redis database. - The
redis_master_passwordis used to encrypt the Redis data and indexes.
Service
Systemd is used to supervise and run the KMS server and the Eviden VM agent.
As an administrator, you can see the running services with the following commands:
systemctl status cosmian_kms
systemctl status cosmian_vm_agent
You can read as well full logs using:
journalctl -u cosmian_kms
journalctl -u cosmian_vm_agent
Check the connection with the KMS
$ curl --insecure https://${EVIDEN_VM_IP_ADDR}/version
"5.25.0"
When the agent starts (see Snapshot the VM) self-signed certificate is created to enable HTTPS out of the box.
These certificates must be replaced by trusted ones using tools like
cosmian_certtool or Linux tools (certbot with Let's Encrypt for instance).
Snapshot the VM 📸
Once the VM is configured as needed, Eviden VM Agent can do a snapshot of the VM containing fingerprint of the executables and metadata related to TEE and TPM.
The agent creates an encrypted folder (LUKS container) to store sensitive information, creates self-signed certificate for Nginx and starts a snapshot.
Wait for the agent to initialize the LUKS and generate the certificates. This is automatically at boot.
In short, to generate a snapshot, please follow.
The associated command is:
cosmian_vm --url https://${EVIDEN_VM_IP_ADDR}:5555 --allow-insecure-tls snapshot
Verify the Eviden VM KMS integrity ✅
Verifying trustworthiness of the Eviden VM KMS is exactly the same process as verifying the Eviden VM itself.
In short, to verify a snapshot, please follow.
The associated command is:
cosmian_vm --url https://${EVIDEN_VM_IP_ADDR}:5555 --allow-insecure-tls verify \
--snapshot cosmian_vm.snapshot
This mode offers high availability through redundancy and load-balancing.
The KMS servers are stateless, so they can be scaled horizontally from a single node up to any number of nodes, simply by connecting them all to the same database and fronting them with a load balancer.
Architecture with HAProxy and Keepalived
%%{init: {"flowchart": {"curve": "linear"}}}%%
flowchart TB
%% Styling (reuses the same palette as the previous diagram version)
classDef client fill:#e1d5e7,stroke:#9673a6,stroke-width:2px,color:#000
classDef vip fill:#f8cecc,stroke:#b85450,stroke-width:2px,stroke-dasharray: 5 5,color:#000
classDef lb fill:#dae8fc,stroke:#6c8ebf,stroke-width:2px,color:#000
classDef kms fill:#d5e8d4,stroke:#82b366,stroke-width:2px,color:#000
classDef db fill:#ffe6cc,stroke:#d79b00,stroke-width:2px,color:#000
subgraph clients_group["💻 Clients (KMIP / HTTP)"]
client1["Client 1"]:::client
client2["Client 2"]:::client
clientN["Client n"]:::client
end
subgraph lb_cluster["🔀 Load balancers (HAProxy + Keepalived)"]
direction LR
vip["🌐 Virtual IP (VIP)"]:::vip
lb1["HAProxy + Keepalived<br/>LB 1 (MASTER)"]:::lb
lb2["HAProxy + Keepalived<br/>LB 2 (BACKUP)"]:::lb
end
subgraph kms_cluster["🛡️ KMS nodes"]
node1["Eviden KMS<br/>Node 1"]:::kms
node2["Eviden KMS<br/>Node 2"]:::kms
nodeN["Eviden KMS<br/>Node n"]:::kms
end
db[("🗄️ Shared database<br/>(SQL / Redis)")]:::db
client1 -->|single endpoint| vip
client2 --> vip
clientN --> vip
vip -.->|active on| lb1
vip -.->|standby on| lb2
lb1 --> node1 & node2 & nodeN
lb2 --> node1 & node2 & nodeN
node1 & node2 & nodeN --> db
All KMS clients (backup software, applications) connect exclusively to the Virtual IP (VIP). Individual KMS node IPs are never exposed to clients.
The number of KMS nodes can be adjusted at any time without reconfiguring clients: add a new node to the database and to the HAProxy backend, and it will start receiving traffic immediately.
Because the KMS nodes are stateless, the shared database is the source of truth: ensure you have regular database backups (and periodically test restores) using your database engine's recommended procedures.
Configuring the load balancer
Since the KMS servers are stateless, any load-balancing strategy may be selected, such as a simple round-robin.
When the Eviden KMS servers are configured to export an HTTPS port (as is the case when running inside a confidential VM):
- all the Eviden KMS servers should expose the same server certificate on their HTTPS port
- and the load balancer should be configured as an SSL load balancer (HAProxy is a good example of a high-performance SSL load balancer)
HAProxy Configuration
Use the same configuration on all HAProxy nodes — Keepalived handles which one is active.
In a typical two-node setup, HAProxy and Keepalived are installed on two dedicated load balancer nodes. Each load balancer node:
- runs HAProxy (load-balances requests to all KMS nodes)
- runs Keepalived (shares a Virtual IP between the HAProxy instances so clients have a single endpoint)
Typical configuration file path (may vary by distribution):
- HAProxy:
/etc/haproxy/haproxy.cfg
On systemd-based distributions, after updating the configuration you can restart HAProxy with:
sudo systemctl restart haproxy
Health checks use the Eviden KMS /health endpoint on the HTTP port (9998), while KMIP traffic is forwarded to
port 5696. Add or remove server lines in the backend to match your number of KMS nodes.
global
log /dev/log local0
maxconn 2000
user haproxy
group haproxy
defaults
log global
mode tcp # TCP mode: required for TLS/KMIP passthrough
option tcplog
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
# Frontend for KMIP traffic (standard KMIP port)
frontend kmip_frontend
bind *:5696
default_backend kmip_backend
backend kmip_backend
mode tcp
balance roundrobin
# Health check via Eviden KMS /health endpoint (HTTP port 9998)
option httpchk GET /health
http-check expect status 200
# Check every 3s; mark DOWN after 3 failures, mark UP after 2 successes
default-server inter 3s fall 3 rise 2
# Add one line per KMS node.
# Traffic goes to port 5696; health is checked on port 9998.
server kms1 <kms1-ip>:5696 check port 9998
server kms2 <kms2-ip>:5696 check port 9998
# server kms3 <kms3-ip>:5696 check port 9998
# …
Keepalived Configuration
Keepalived manages the Virtual IP (VIP) across the load balancer nodes. Use the same configuration on all load balancer nodes,
adjusting only state and priority per node:
You must define a Virtual IP (VIP) that will be shared by the nodes. Keepalived ensures that only the current MASTER node responds to the VIP, so clients always connect to a single stable address.
Typical configuration file path (may vary by distribution):
- Keepalived:
/etc/keepalived/keepalived.conf
On systemd-based distributions, after updating the configuration you can restart Keepalived with:
sudo systemctl restart keepalived
| Load balancer node | state | priority |
|---|---|---|
| Primary | MASTER | highest value (e.g. 101) |
| Secondary | BACKUP | lower value (e.g. 100) |
| Additional | BACKUP | lower still (e.g. 99, 98, …) |
vrrp_script chk_haproxy {
script "killall -0 haproxy" # Checks that the HAProxy process is running
interval 2
weight 2
}
vrrp_instance VI_1 {
state MASTER # → BACKUP on all non-primary nodes
interface eth0 # Adapt to your network interface name
virtual_router_id 51 # Must be identical on all load balancer nodes
priority 101 # → Decrease by 1 for each additional node
advert_int 1
authentication {
auth_type PASS
auth_pass SecretPassword # Strong shared secret; must be identical on all nodes
}
virtual_ipaddress {
192.168.1.100 # VIP — configure this address in all KMS clients
}
track_script {
chk_haproxy
}
}
Failover behavior
| Event | Result |
|---|---|
| Active HAProxy node goes down | Keepalived promotes the next highest-priority HAProxy; VIP moves within ~2s |
| A KMS node goes down | HAProxy detects failure via /health within inter × fall ≈ 9s and stops routing to it; remaining nodes absorb the traffic |
| A KMS node recovers | HAProxy re-adds it after 2 successful checks (~6s) |
| A new KMS node is added | Add a server line to the HAProxy backend and reload HAProxy; no client reconfiguration needed |
Deployment options
You can run a single HAProxy instance (similar to using Nginx as a reverse-proxy/load balancer) in front of the KMS nodes. This provides load balancing but introduces a single point of failure (SPOF): if that HAProxy server goes down, clients cannot reach the KMS.
Using Keepalived (with at least two HAProxy instances) avoids the SPOF by providing a floating VIP.
TOML configuration file
The KMS server can be configured using a TOML file. When a configuration file is provided,
the command line arguments are ignored (except --help / --version).
Interactive configuration wizard
The fastest way to create a valid configuration file is the built-in interactive wizard:
cosmian_kms configure
The wizard guides you step-by-step through all configuration sections:
| Step | Section | What it covers |
|---|---|---|
| 1/9 | Database | Type (SQLite / PostgreSQL / MySQL / Redis-Findex), URL, paths, cache settings |
| 2/9 | HTTP server | Listening port and hostname |
| 3/9 | TLS / Certificates | Enable TLS; optionally generates a self-signed PKI (CA → server + client certs) |
| 4/9 | KMIP socket server | Enable the binary KMIP socket listener (port 5696) |
| 5/9 | Authentication | API token, JWT/OIDC providers, mTLS client certificates |
| 6/9 | HSM | Model, admin user, slot numbers and passwords |
| 7/9 | Logging | Log level, OTLP endpoint, syslog, rolling logs |
| 8/9 | Proxy | Outbound proxy for JWKS fetch (URL, auth, exclusions) |
| 9/9 | Advanced | Workspace paths, KEK, MS DKE, KMIP policy, Google CSE, Azure EKM, AWS XKS, Web UI |
At the end the wizard writes the resulting TOML file to the default system path
(/etc/cosmian/kms.toml on Linux/macOS, C:\ProgramData\Cosmian\kms.toml on Windows)
and prints the command to start the server:
Start the server with:
cosmian_kms -c /etc/cosmian/kms.toml
Self-signed PKI generation
When TLS is enabled and you choose to generate certificates, the wizard creates a
complete PKI under the chosen output directory (default /etc/cosmian/):
| File | Description |
|---|---|
ca.crt | Self-signed CA certificate (RSA-4096, valid 10 years by default) |
server.crt | Server leaf certificate signed by the CA (RSA-2048) |
server.key | Server private key (PKCS#8 PEM) |
client.crt | Client leaf certificate signed by the CA — distribute to mTLS clients |
client.key | Client private key (PKCS#8 PEM) |
Distribute client.crt and client.key to any client that must authenticate
with mutual TLS. You can verify the chain at any time with:
openssl verify -CAfile /etc/cosmian/ca.crt /etc/cosmian/server.crt
openssl verify -CAfile /etc/cosmian/ca.crt /etc/cosmian/client.crt
Manual configuration
Configuration file loading precedence:
- Command line flag
-c/--config <FILE>(highest precedence). If the file does not exist, the server exits with an error. - Environment variable
COSMIAN_KMS_CONF(must point to an existing file). - Default system path:
/etc/cosmian/kms.toml(Linux/macOS) orC:\\ProgramData\\Cosmian\\kms.toml(Windows). - If none of the above files is found, the server falls back to parsing the command line arguments and environment variables.
Important: If a configuration file is found via the default system path (rule 3) and extra command-line arguments are also provided, the server exits with an error. This prevents silently ignoring arguments the user intended to take effect. To use a different configuration, point explicitly to it with
-c/--config <FILE>. Examples:
# Explicit configuration file
./cosmian-kms -c ./test_data/configs/server/jwt_auth.toml
# Using an environment variable
export COSMIAN_KMS_CONF=./test_data/configs/server/jwt_auth.toml
./cosmian-kms
The file should be a TOML file with the following structure:
# The default username to use when no authentication method is provided
default_username = "admin"
# When an authentication method is provided, perform the authentication
# but always use the default username instead of the one provided by the authentication method
force_default_username = false
# This setting enables the Microsoft Double Key Encryption service feature of this server.
#
# It should contain the external URL of this server as configured in Azure App Registrations
# as the DKE Service (<https://learn.microsoft.com/en-us/purview/double-key-encryption-setup#register-your-key-store>)
#
# The URL should be something like <https://cse.my_domain.com/ms_dke>
# ms_dke_service_url = "<ms dke service url>"
# The exposed URL of the KMS - this is required if Google CSE configuration is activated.
# If this server is running on the domain `cse.my_domain.com` with this public URL,
# The configured URL from Google admin should be something like <https://cse.my_domain.com/google_cse>
# The URL is also used during the authentication flow initiated from the KMS UI.
# kms_public_url = "kms-public-url"
# Print the server configuration information and exit
info = false
# The HSM model.
# `Trustway Proteccio`, `Trustway Crypt2pay`, `Utimaco General Purpose HSM`,
# `Smartcard HSM`, and `SoftHSM2` are natively supported.
# Other HSMs are supported too; specify `other` and check the documentation
# hsm_model = "softhsm2" # softhsm2 | utimaco | proteccio | crypt2pay | smartcardhsm | other
# List of KMS usernames that are granted HSM admin privileges.
# HSM admins can create, destroy, and potentially export objects on the HSM.
# Use `"*"` as the only entry to grant all authenticated users admin access.
# Repeat the option or use a comma-separated list to specify multiple admins:
# `--hsm-admin alice@example.com --hsm-admin bob@example.com`
# or set `KMS_HSM_ADMIN=alice@example.com,bob@example.com`
# hsm_admin = ["admin"] # KMS users with admin rights on this HSM
# HSM slot number. The slots used must be listed.
# Repeat this option to specify multiple slots
# while specifying a password for each slot (or an empty string for no password)
# e.g.
# ```sh
# --hsm-slot 1 --hsm-password password1 \
# --hsm-slot 2 --hsm-password password2
# ```
# hsm_slot = [0] # PKCS#11 slot indices
# Password for the user logging in to the HSM Slot specified with `--hsm_slot`
# Provide an empty string for no password
# see `--hsm_slot` for more information.
# Set `KMS_HSM_PASSWORD` to avoid the password appearing in `ps` output.
# hsm_password = ["changeme"] # Login passwords (same order as hsm_slot)
#
# ── New multi-instance format ─────────────────────────────────────────────────
# Uses the new UID convention: hsm::<model>::<slot_id>::<key_id>
# To connect HSMs, declare one [[hsm_instances]] section per device.
# `Trustway Proteccio`, `Trustway Crypt2pay`, `Utimaco General Purpose HSM`,
# `Smartcard HSM`, and `SoftHSM2` are natively supported.
# Other HSMs are supported too; specify `other` and check the documentation.
#
# The first entry gets the routing prefix "hsm::<model>", the second
# "hsm::<model>_1", etc. Object UIDs take the form "<prefix>::<slot>::<key-id>".
#
## [[hsm_instances]]
## hsm_model = "softhsm2" # softhsm2 | utimaco | proteccio | crypt2pay | smartcardhsm | other
## hsm_admin = ["tech@example.com"] # KMS users with admin rights on this HSM
## hsm_slot = [0] # PKCS#11 slot indices (use softhsm2-util --show-slots to list them)
## hsm_password = ["changeme"] # Login passwords (same order as hsm_slot)
#
## [[hsm_instances]]
## hsm_model = "utimaco"
## hsm_admin = ["tech@example.com"]
## hsm_slot = [0, 1]
## hsm_password = ["slot0pass", "slot1pass"]
# Force all newly created and imported keys to be wrapped by the key specified in this field.
# This is most useful to ensure that an HSM key wraps all keys in the KMS database.
# Note: This setting is ignored when a key is imported in JSON TTLV format and is already wrapped.
# key_encryption_key = "kek ID"
# Specifies which KMIP object types should be automatically unwrapped when retrieved.
# Repeat this option to specify multiple object types
# e.g.
# ```sh
# --default-unwrap-type SecretData \
# --default-unwrap-type SymmetricKey
# ```
# default_unwrap_type = ["SecretData", "SymmetricKey"]
# List of users who have the right to create and import Objects
# and grant access rights for Create Kmip Operation.
# privileged_users = ["<user_id_1>", "<user_id_2>"]
# Check the database configuration documentation pages for more information
[db]
# The main database of the KMS server that holds default cryptographic objects and permissions.
# - postgresql: `PostgreSQL`. The database URL must be provided
# - mysql: `MySql` or `MariaDB`. The database URL must be provided
# - sqlite: `SQLite`. The data will be stored at the `sqlite_path` directory
# A key must be supplied on every call
# - redis-findex [non-FIPS]: a Redis database with encrypted data and indexes thanks to Findex.
# The Redis URL must be provided, as well as the redis-master-password and the redis-findex-label
database_type = "sqlite"
# The URL of the database for `Postgres`, `MySQL`, or `Findex-Redis`
# database_url = "<database-url>"
# The directory path of the `SQLite`
# sqlite_path = "<sqlite-path>"
# redis-findex: a master password used to encrypt the Redis data and indexes
# redis_master_password = "<redis master password>"
# Clear the database on start.
# WARNING: This will delete ALL the data in the database
clear_database = false
# When a wrapped object is fetched from the database,
# it is unwrapped and stored in the unwrapped cache.
# This option specifies the maximum age in minutes of the unwrapped objects in the cache
# after its last use.
# The default is 15 minutes.
# About 2/3 of the objects will be evicted after this time; the other 1/3 will be evicted
# after a maximum of 150% of the time.
unwrapped_cache_max_age = 15 # minutes
# TLS configuration of the Socket server and HTTP server
[tls]
# The server's X.509 certificate in PEM format.
# Provide a PEM containing the server leaf certificate,
# optionally followed by intermediate certificates (full chain). When provided along with
# `--tls-key-file`, the servers will start in TLS mode.
# Do not use in combination with `--tls-p12-file`.
# tls_cert_file = "path/to/server.crt"
# The server's private key in PEM format (PKCS#8 or traditional format).
# Must correspond to the certificate in `--tls-cert-file`.
# Do not use in combination with `--tls-p12-file`.
# tls_key_file = "path/to/server.key"
# Optional certificate chain in PEM format (intermediate CAs).
# If not provided, the chain may be appended to `--tls-cert-file` instead.
# Do not use in combination with `--tls-p12-file`.
# tls_chain_file = "path/to/chain.pem"
# The KMS server optional PKCS#12 Certificates and Key file as an alternative
# to providing the key, certificate and chain in PEM format.
# When provided, the Socket and HTTP server will start in TLS Mode.
# tls_p12_file = "[tls p12 file]"
# The password to open the PKCS#12 Certificates and Key file
# tls_p12_password = "[tls p12 password]"
# The server's optional X. 509 certificate in PEM format validates the client certificate presented for authentication.
# If provided, clients must present a certificate signed by this authority for authentication.
# Mandatory to start the socket server.
# clients_ca_cert_file = "[authority cert file]"
# The socket server listens to KMIP binary requests on the IANA-registered 4696 port.
# The socket server will only start if the TLS configuration is provided **and** client certificate authentication
# is enabled.
[socket_server]
# Start the KMIP socket server? If this is set to true, the TLS config must be provided, featuring a server PKCS#12 file and a client certificate authority certificate file
# socket_server_start = false
# The KMS socket server port
# socket_server_port = 5696
# The KMS socket server hostname
# socket_server_hostname = "0.0.0.0"
# The HTTP server listens to KMIP requests on the /kmip and /kmip/2_1 endpoints.
# It also serves the web UI on the /ui endpoint.
# If the TLS configuration is provided, the server will start in HTTPS mode.
[http]
# The KMS HTTP server port
port = 9998
# The KMS HTTP server hostname
hostname = "0.0.0.0"
# An optional API token to use for authentication on the HTTP server.
# api_token_id = "<secret-api-token>"
# Maximum number of requests per second per IP address allowed by the rate limiter.
# When set, the server enforces this limit to mitigate `DoS` and brute-force attacks.
# Requests exceeding the limit receive HTTP 429 Too Many Requests.
# Leave unset (default) to disable rate limiting.
# rate_limit_per_second = 100
# Number of actix-web HTTP worker threads.
# Defaults to the number of logical CPUs. On I/O-heavy workloads (e.g. `PostgreSQL` backend)
# setting this to `2 * <number of CPU cores>` improves throughput by keeping more Tokio
# threads busy while others are waiting on network I/O.
# Can also be set via the `TOKIO_WORKER_THREADS` environment variable (Tokio runtime),
# but this flag controls only the actix-web application workers.
# http_workers = 8
# Comma-separated list of origins allowed to make cross-origin requests to the KMIP API.
# Required for any Web UI deployment: the browser Fetch API sends an `Origin` header on
# every POST request — even when the page is served by the KMS itself — and actix-cors
# rejects it unless the exact origin appears in this list.
# The value must match byte-for-byte what the user types in the browser address bar
# (scheme + hostname + port). The server bind address (`0.0.0.0`) and the server IP
# are not equivalent to a DNS hostname. The Docker image pre-populates loopback
# addresses; add any custom hostname explicitly. Example: `http://kms.example.com:9998`.
# cors_allowed_origins = ["http://localhost:9998", "http://127.0.0.1:9998"]
# If using a forward proxy for outbound JWKS requests,
# set the proxy parameters here.
[proxy]
# The proxy URL:
# - e.g., `https://secure.example` for an HTTP proxy
# - e.g., `socks5://192.168.1.1:9000` for a SOCKS proxy
# proxy_url = "https://proxy.example.com:8080"
# Set the Proxy-Authorization header username using Basic auth.
# proxy_basic_auth_username = "[proxy username]"
# Set the Proxy-Authorization header password using Basic auth.
# proxy_basic_auth_password = "[proxy password]"
# Set the Proxy-Authorization header to a specified value.
# proxy_custom_auth_header = "my_custom_auth_token"
# The No Proxy exclusion list to this Proxy
# proxy_exclusion_list = ["domain1", "domain2"]
# Check the Authenticating Users documentation pages for more information.
[idp_auth]
# JWT authentication provider configuration.
#
# The expected argument is --jwt-auth-provider="`PROVIDER_CONFIG_1`" --jwt-auth-provider="`PROVIDER_CONFIG_2`" ...
# where each `PROVIDER_CONFIG_N` defines one identity provider configuration.
#
# Each provider configuration `PROVIDER_CONFIG_N` should be in the format: "`JWT_ISSUER_URI,JWKS_URI,JWT_AUDIENCE_1,JWT_AUDIENCE_2,...`"
# where:
# - `JWT_ISSUER_URI`: The issuer URI of the JWT token (required)
# - `JWKS_URI`: The JWKS (JSON Web Key Set) URI (optional, defaults to <JWT_ISSUER_URI>/.well-known/jwks.json)
# - `JWT_AUDIENCE_1..N`: One or more audience values for the JWT token (optional)
#
# Examples:
# --jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs, kacls-migration, another-audience"
# --jwt-auth-provider="https://login.microsoftonline.com/612da4de-35c0-42de-ba56-174b69062c96/v2.0,https://login.microsoftonline.com/612da4de-35c0-42de-ba56-174b69062c96/discovery/v2.0/keys"
# --jwt-auth-provider="https://<your-tenant>.<region>.auth0.com/""
# This argument can be repeated to configure multiple identity providers.
# jwt_auth_provider = [
# "https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,my-audience,another_client_id",
# "https://auth0.example.com,,my-app",
# "https://keycloak.example.com/auth/realms/myrealm,,"
# ]
[workspace]
# The root folder where the KMS will store its data A relative path is taken relative to the user's HOME directory
# root_data_path = "./cosmian-kms"
# The folder to store temporary data (non-persistent data readable by no one but the current instance during the current execution)
# tmp_path = "/tmp"
# Check the logging documentation pages for more information
[logging]
# An alternative to setting the `RUST_LOG` environment variable.
# Setting this variable will override the `RUST_LOG` environment variable
rust_log = "info,cosmian_kms=info"
# The OTLP collector URL for gRPC
# (for instance, <https://localhost:4317>)
# If not set, the telemetry system will not be initialized.
# Must use https:// in production.
# Use --otlp-allow-insecure to permit plaintext http:// connections.
# otlp = "http://localhost:4317"
# Do not log to stdout
quiet = false
# Log to syslog
log_to_syslog = false
# The directory for daily rolling logs: <rolling_log_name>.YYYY-MM-DD.
# File logging is disabled unless this option is explicitly set.
# Suggested paths:
# Linux: /var/log/
# Windows: C:\Users\<username>\AppData\Local\Cosmian KMS Server
# macOS: ~/Library/Logs/
#
# WARNING: Windows environment variables (e.g. %LOCALAPPDATA%) are NOT
# expanded. Use the fully-resolved path.
# rolling_log_dir = "/var/log/"
# The name of the rolling log file: <rolling_log_name>.YYYY-MM-DD.
# Defaults to `cosmian_kms` if not set.
# rolling_log_name = "cosmian_kms"
# Enable metering in addition to tracing when telemetry is enabled
# enable_metering = false
# The name of the environment (development, test, production, etc.)
# This will be added to the telemetry data if telemetry is enabled
# environment = "development"
# Enable ANSI colors in the logs to stdout
ansi_colors = false
# Generic configuration to edit the path to static UI application files
# To use the Web UI, ensure the `kms_public_url` is set to the correct public URL above.
[ui_config]
# The UI distribution folder
# ui_index_html_folder = "/usr/local/cosmian/ui/dist"
# Configuration for the handling of authentication with OIDC from the KMS UI.
# This is used to authenticate users when they access the KMS UI.
# The same Identity Provider must **also** be configured in the [idp_auth] section above.
[ui_config.ui_oidc_auth]
# The client ID of the configured OIDC tenant for UI Auth
# ui_oidc_client_id = "<client id>"
# The client secret of the configured OIDC tenant for UI Auth
# ui_oidc_client_secret = "<client secret>" (optional)
# The issuer URI of the configured OIDC tenant for UI Auth
# ui_oidc_issuer_url = "<issuer-url>"
# The logout URI of the configured OIDC tenant for UI Auth
# ui_oidc_logout_url = "<logout-url>"
[google_cse_config]
# This setting turns on endpoints handling Google CSE feature
google_cse_enable = false
# This setting turns off the validation of the tokens used by this server's Google Workspace CSE feature
# google_cse_disable_tokens_validation = false
# This setting contains the list of KACLS server URLs that can access this server for Google CSE migration, through the privilegedunwrap endpoint (used to fetch exposed jwks on server start)
# google_cse_incoming_url_whitelist = ["[kacls_url_1]", "[kacls_url_2]"]
# PEM PKCS8 RSA private key used to ensure consistency of certificate handling and privileged unwrap operations across server restarts and multiple server instances. If not provided, a random key will be generated at server startup
# google_cse_migration_key = "<google_cse_existing_migration_key>"
[azure_ekm_config]
# This setting turns on/off the endpoints handling Azure EKM features
azure_ekm_enable = false
[aws_xks_config]
# This setting turns on endpoints handling the AWS XKS feature
aws_xks_enable = false
[kmip.allowlists]
[notifications.smtp]
# The KMS HTTP server port
port = 0
[jwks_endpoint]
# Enable the `GET /.well-known/jwks.json` endpoint.
#
# When set, the server publicly exposes all active public keys whose
# `CryptographicUsageMask` includes `Verify` as a RFC 7517 JSON Web Key Set.
# The endpoint is **unauthenticated** — no credentials are required to fetch it,
# and no authentication middleware is applied. Defaults to `false`.
jwks_endpoint_enabled = false
# Maximum number of public keys returned in a single JWKS response.
#
# When the server holds more eligible keys than this limit, the response is
# truncated and an `X-JWKS-Truncated: true` header is added to signal consumers.
# Increase this value if your deployment performs frequent key rotation and all
# overlapping verification keys must be simultaneously discoverable.
jwks_endpoint_max_keys = 50
# Automatically tag key pairs created via the REST crypto API for JWKS inclusion.
#
# When `true` (the default), every key pair created via `POST /v1/crypto/keys`
# receives the `"jwks"` tag and immediately appears in
# `GET /.well-known/jwks.json`.
#
# Set to `false` to disable this behaviour globally. Operators must then
# manually tag each public key via `POST /v1/crypto/keys/{kid}/tags` before
# it is published in the JWKS document.
#
# This setting has no effect on keys created directly through the KMIP protocol.
jwks_endpoint_auto_tag = true
CORS configuration
Cross-Origin Resource Sharing (CORS) controls which browser origins are allowed to make requests to the KMS HTTP API.
You must configure cors_allowed_origins for any Web UI deployment
that uses a hostname other than localhost.
When cors_allowed_origins is not set in the configuration file, CLI, or
environment, the binary defaults to loopback origins matching the configured
scheme (HTTP or HTTPS) and port. This covers localhost, 127.0.0.1,
0.0.0.0, [::1], and [::] so the bundled Web UI works out-of-the-box
without any explicit configuration.
Although the KMS serves its own Web UI from the same host and port, the
browser's Fetch API sends an Origin header on every non-GET/HEAD request
(including POST) — even when the request originates from the same page. The
actix-cors middleware compares this header against the explicit allow-list and
returns HTTP 400 if the value is not present. There is no DNS resolution or
network-interface expansion: the comparison is a byte-for-byte string match.
This means cors_allowed_origins must contain the exact URL the user
types in the browser's address bar — scheme, hostname, and port all included.
Configuring 0.0.0.0 (the bind address) or the server's IP address does not
match a hostname-based origin such as http://kms.example.com:9998, and vice
versa.
The binary automatically provides loopback addresses
(localhost, 127.0.0.1, 0.0.0.0, [::1], [::] on the configured port) so that
browser access from the same machine works out-of-the-box. Any other hostname,
IP address, or port must be added explicitly.
CLI clients (ckms, scripts, curl) do not send an Origin header and are
not affected by this setting.
[http]
# Allow a Vite dev-server and a custom front-end to reach the KMIP API.
cors_allowed_origins = ["http://127.0.0.1:5173", "https://app.example.com"]
The same list can be provided via the environment variable
KMS_CORS_ALLOWED_ORIGINS (comma-separated) or the CLI flag
--cors-allowed-origins.
Every origin in cors_allowed_origins can issue authenticated
cross-origin requests to the KMS — session cookies and credentials are
forwarded for each listed origin.
- Only add origins you fully control and trust. A compromised or malicious site listed here can read and manage all cryptographic objects accessible to the authenticated user.
- Never use a wildcard (
*).actix-corsrejects a wildcard whensupports_credentials()is active, and a wildcard CORS policy would expose every user's keys to any website on the internet. - Add every URL users will type in their browser — scheme, hostname,
and port must all match exactly.
0.0.0.0(bind address) and the server's IP address are not interchangeable with the DNS hostname used by the browser. - Security note: while a user is authenticated to the KMS, avoid browsing untrusted sites in the same browser session. CORS is a browser-enforced defense in depth; its effectiveness depends on the browser correctly implementing the same-origin policy, which cannot be guaranteed across all browser versions and configurations.
Enterprise integration scopes are not affected by this setting.
The Google CSE, Microsoft DKE, and AWS XKS endpoints retain their own
permissive CORS policy as required by their respective integration
contracts — cors_allowed_origins has no effect on those routes.
Configuration Examples
This page provides a comprehensive collection of TOML configuration file examples for the Eviden KMS server. Each configuration has been validated and tested to ensure it works correctly with the KMS server.
All configuration examples can be used by:
- Saving the content to a file (e.g.,
kms.toml) - Starting the server with:
cosmian_kms_server -c kms.tomlor using the environment variableCOSMIAN_KMS_CONF=kms.toml
Note on default path: If no
-cflag orCOSMIAN_KMS_CONFvariable is set, the server automatically loads/etc/cosmian/kms.toml(Linux/macOS) orC:\ProgramData\Cosmian\kms.toml(Windows) when it exists. If that file is present and you also pass command-line arguments, the server exits with an error to prevent your arguments from being silently ignored.
For complete documentation on all available configuration options, see the Configuration file reference.
Quick Start Configurations
basic-http
Basic HTTP server configuration with default settings.
# Basic HTTP configuration
[http]
port = 9998
hostname = "0.0.0.0"
cors_allowed_origins = ["http://localhost:9998", "http://127.0.0.1:9998"]
Use case: Development, testing, or internal networks where TLS is not required.
Authentication Configurations
jwt-auth
JWT authentication using Google as the identity provider.
# JWT authentication configuration using idp_auth format
[idp_auth]
# issuer,jwks[,aud1[,aud2...]] (jwks & audiences optional; any-of when multiple)
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,cosmian_kms,another_client_id"]
Use case: Authenticate users with Google Identity tokens, suitable for organizations using Google Workspace.
api-token-auth
API token authentication using a symmetric key.
# API token authentication configuration
[http]
port = 9998
hostname = "0.0.0.0"
cors_allowed_origins = ["http://localhost:9998", "http://127.0.0.1:9998"]
api_token_id = "test-symmetric-key-id"
Use case: Service-to-service authentication or when using a pre-shared symmetric key for authentication.
cors-configuration
Cross-Origin Resource Sharing (CORS) configuration for browser clients.
# CORS configuration for browser-based clients
[http]
port = 9998
hostname = "0.0.0.0"
# Allow the bundled Web UI and any Vite dev server running on the same machine
cors_allowed_origins = ["http://localhost:9998", "http://127.0.0.1:9998"]
Use case: When a browser-based client (e.g. the bundled Web UI or a Vite dev server) runs on a different origin from the KMS server. In production behind a load balancer, set this to your public URL. Leave unset to restrict to same-origin only.
tls-client-cert
TLS client certificate authentication with mutual TLS.
# TLS Client Certificate Authentication
[tls]
# For FIPS mode (default build):
tls_cert_file = "certificates/server.crt"
tls_key_file = "certificates/server.key"
clients_ca_cert_file = "certificates/ca.crt"
# For non-FIPS mode:
# tls_p12_file = "certificates/server.p12"
# tls_p12_password = "password"
# clients_ca_cert_file = "certificates/ca.crt"
Use case: High-security environments requiring mutual TLS authentication with client certificates.
multifactor-tls-jwt
Multi-factor authentication combining TLS client certificates and JWT tokens.
# Multi-factor TLS + JWT authentication (idp_auth format)
[tls]
# For FIPS mode (default build):
# tls_cert_file = "certificates/server.crt"
# tls_key_file = "certificates/server.key"
# clients_ca_cert_file = "certificates/ca.crt"
# For non-FIPS mode:
tls_p12_file = "certificates/server.p12"
tls_p12_password = "password"
clients_ca_cert_file = "certificates/ca.crt"
[idp_auth]
# Empty audience example: no audiences after JWKS URL (audience check skipped)
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"]
Use case: Maximum security environments requiring both certificate and token-based authentication.
multifactor-jwt-api
Multi-factor authentication combining JWT tokens and API token authentication.
# Multi-factor JWT + API token authentication (idp_auth format)
[idp_auth]
# Multiple audiences example (any-of)
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,frontend,cli"]
[http]
port = 9998
hostname = "0.0.0.0"
cors_allowed_origins = ["http://localhost:9998", "http://127.0.0.1:9998"]
api_token_id = "test-symmetric-key-id"
Use case: Flexible authentication allowing both user JWT tokens and service API tokens.
Database Configurations
mysql-database
MySQL database configuration for production deployments.
# MySQL database configuration
[db]
database_type = "mysql"
database_url = "mysql://kms_user:kms_password@mysql-server:3306/kms"
Use case: Production deployments requiring a robust, scalable database backend.
mysql-with-cert
MySQL database with client certificate authentication.
# MySQL database configuration with client certificate
[db]
database_type = "mysql"
database_url = "mysql://mysql_server:3306/kms"
# Note: Configure client certificate via command-line option:
# --mysql-user-cert-file cert.p12
Use case: MySQL deployments requiring certificate-based database authentication.
postgresql-database
PostgreSQL database configuration for production deployments.
# PostgreSQL database configuration
[db]
database_type = "postgresql"
database_url = "postgres://kms_user:kms_password@postgres-server:5432/kms"
Use case: Production deployments requiring strong reliability, advanced SQL features, and horizontal scaling options.
sqlite-database
Lightweight embedded SQLite configuration (default when no DB settings are provided).
# SQLite database configuration (default path)
[db]
database_type = "sqlite"
sqlite_path = "./sqlite-data" # Defaults to ./sqlite-data
# clear_database = false # Set to true to wipe the DB on each start (DANGEROUS)
Use case: Local development, testing, or small single-instance deployments where simplicity outweighs concurrency needs.
redis-findex-database
Redis with Findex encrypted data and searchable indexes (non-FIPS build only).
# Redis Findex database configuration (non-FIPS feature)
[db]
database_type = "redis-findex"
database_url = "redis://redis-server:6379"
redis_master_password = "change_me_master_password" # Master password derives encryption key
Use case: Environments requiring encrypted server-side indexes and low-latency lookups with application-level protection.
Google Workspace CSE Configuration
google-cse
Complete Google Workspace Client-Side Encryption setup.
# Google CSE configuration
kms_public_url = "http://localhost:9998"
# JWT authentication with Google
[idp_auth]
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"]
# Google CSE configuration
[google_cse_config]
google_cse_enable = true
Use case: Enabling Google Workspace Client-Side Encryption for Gmail and Drive.
Logging and Monitoring Configurations
otlp-logging
OpenTelemetry (OTLP) logging configuration with Jaeger integration.
# OTLP logging configuration
[logging]
otlp = "http://localhost:4317"
quiet = true
Use case: Centralized logging and distributed tracing with OpenTelemetry-compatible systems.
file-logging
Rolling file logging configuration.
# Rolling file logging
[logging]
rolling_log_dir = "/var/log/"
rolling_log_name = "kms"
rust_log = "info,cosmian_kms_server=debug"
Use case: Production deployments requiring persistent log files with rotation.
syslog-logging
System logging configuration for Linux systems.
# Syslog logging
[logging]
log_to_syslog = true
quiet = true
rust_log = "warn,cosmian_kms_server=info"
Use case: Integration with system logging infrastructure on Linux servers.
Production Configurations
production-https
Complete production configuration with HTTPS, authentication, and MySQL.
# Production HTTPS configuration
kms_public_url = "https://kms.example.com"
[http]
port = 443
hostname = "0.0.0.0"
cors_allowed_origins = ["https://kms.example.com"]
[tls]
# For FIPS mode (default build):
# tls_cert_file = "/etc/ssl/kms/server.crt"
# tls_key_file = "/etc/ssl/kms/server.key"
# For non-FIPS mode:
tls_p12_file = "/etc/ssl/kms/server.p12"
tls_p12_password = "secure_password"
[idp_auth]
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,kms.example.com"]
[db]
database_type = "mysql"
database_url = "mysql://kms_user:secure_password@mysql.internal:3306/kms"
[logging]
rolling_log_dir = "/var/log/"
rust_log = "warn,cosmian_kms_server=info"
Use case: Full production deployment with security, scalability, and monitoring.
ui-load-balanced
Production configuration exposing the Web UI behind a load balancer, with deterministic session cookies across KMS instances.
# Public URL exposed by the load balancer
kms_public_url = "https://kms-ui.example.com"
[http]
port = 9998
hostname = "0.0.0.0"
cors_allowed_origins = ["https://kms-ui.example.com"]
# UI configuration: static assets served from this folder
[ui_config]
ui_index_html_folder = "./ui/dist"
# Session salt used to derive the UI session cookie encryption key.
# This value MUST be identical across all KMS instances behind the
# same load balancer so any instance can decrypt the UI session cookie.
ui_session_salt = "change-me-and-keep-secret"
[logging]
rust_log = "info,cosmian_kms_server=info"
Use case: Web UI deployments behind a load balancer where UI session cookies must remain valid across all KMS instances.
ha-cluster
High-availability cluster configuration.
# High-availability cluster configuration
kms_public_url = "https://kms-cluster.example.com"
[http]
port = 9998
hostname = "0.0.0.0"
cors_allowed_origins = ["https://kms-cluster.example.com"]
[tls]
# For FIPS mode (default build):
# tls_cert_file = "/etc/ssl/kms/server.crt"
# tls_key_file = "/etc/ssl/kms/server.key"
# For non-FIPS mode:
tls_p12_file = "/etc/ssl/kms/server.p12"
tls_p12_password = "cluster_password"
[db]
database_type = "postgresql"
database_url = "postgres://kms_user:password@postgres-cluster:5432/kms"
[logging]
otlp = "http://jaeger-collector:4317"
rust_log = "info,cosmian_kms_server=info"
Use case: High-availability deployments with load balancing and shared database.
Specialized Configurations
redis-findex
Redis with Findex configuration for encrypted storage.
# Redis with Findex configuration
[db]
database_type = "redis-findex"
database_url = "redis://redis-server:6379"
redis_master_password = "secure_master_password"
[logging]
rust_log = "info,cosmian_kms_server=info,cosmian_findex_client=debug"
Use case: Zero-trust environments with application-level encryption of database contents.
hsm-integration
Hardware Security Module (HSM) integration.
# HSM integration configuration
[hsm]
pkcs11_library = "/usr/lib/libpkcs11.so"
slot_number = 1
pin = "hsm_user_pin"
[logging]
rust_log = "info,cosmian_kms_server=info"
Use case: Hardware-backed key protection using PKCS#11 compatible HSMs.
key-wrapping
Automatic key wrapping with a Key Encryption Key (KEK) and selective automatic unwrapping.
# Key wrapping configuration
# Force all newly created and imported keys to be wrapped by the specified KEK
key_encryption_key = "hsm-kek-id"
# Automatically unwrap specific object types when retrieved
default_unwrap_type = ["SymmetricKey", "SecretData"]
[logging]
rust_log = "info,cosmian_kms_server=info"
Use case: Ensure all keys in the KMS database are wrapped by an HSM key for enhanced security. The server transparently unwraps keys when needed, caching them in memory without storing clear-text keys in the database. Commonly used with HSM integration to protect all KMS keys with a master KEK stored in the HSM. The cache expires after a configurable duration (default 15 minutes).
development-debug
Development configuration with detailed debugging.
# Development debugging configuration
[http]
port = 9998
hostname = "127.0.0.1"
cors_allowed_origins = ["http://localhost:9998", "http://127.0.0.1:9998"]
[logging]
rust_log = "debug,cosmian_kms_server=trace,actix_web=debug"
Use case: Development and troubleshooting with maximum logging detail.
Testing Configurations
integration-test
Configuration for integration testing environments.
# Integration testing configuration
[http]
port = 19998
hostname = "127.0.0.1"
cors_allowed_origins = ["http://localhost:19998", "http://127.0.0.1:19998"]
[db]
database_type = "sqlite"
sqlite_path = "./test-sqlite-data"
cleanup_on_startup = true
[logging]
quiet = true
rust_log = "error"
Use case: Automated testing environments with isolated database and minimal logging.
Related Documentation
- Configuration file reference - Complete parameter documentation
- Command line arguments - CLI options reference
- Authentication - Detailed authentication setup
- Database configuration - Database backend options
- TLS configuration - TLS and certificate setup
- Logging - Logging and monitoring options
- Monitoring - Monitoring and dashboarding
Usage: cosmian_kms [OPTIONS] [KEY_ENCRYPTION_KEY]
Arguments:
[KEY_ENCRYPTION_KEY]
Force all keys imported or created in the KMS, which are not protected by a key encryption key, to be wrapped by the specified key encryption key (KEK)
Options:
-c, --config <COSMIAN_KMS_CONF>
Explicit configuration file path provided via -c / --config. When set, this file takes precedence over the `COSMIAN_KMS_CONF` environment variable and the default system path. All other command line arguments (except `--help` / `--version`) and environment variables are ignored once the configuration file is loaded
--vendor-identification <VENDOR_IDENTIFICATION>
The vendor identification string reported in KMIP `QueryServerInformation` responses
[env: KMS_VENDOR_IDENTIFICATION=]
[default: cosmian]
--default-username <DEFAULT_USERNAME>
The default username to use when no authentication method is provided
[env: KMS_DEFAULT_USERNAME=]
[default: admin]
--force-default-username
When an authentication method is provided, perform the authentication
but always use the default username instead of the one provided by the authentication method
[env: KMS_FORCE_DEFAULT_USERNAME=]
--ms-dke-service-url <MS_DKE_SERVICE_URL>
This setting enables the Microsoft Double Key Encryption service feature of this server.
It should contain the external URL of this server as configured in Azure App Registrations
as the DKE Service (<https://learn.microsoft.com/en-us/purview/double-key-encryption-setup#register-your-key-store>)
The URL should be something like <https://cse.my_domain.com/ms_dke>
[env: KMS_MS_DKE_SERVICE_URL=]
--info
Print the server configuration information and exit
--print-default-config
Serialize the default server configuration as TOML to stdout and exit. This is used to keep the documentation in sync with the Rust struct
--hsm-model <HSM_MODEL>
The HSM model.
`Trustway Proteccio`, `Trustway Crypt2pay`, `Utimaco General Purpose HSM`,
`Smartcard HSM`, and `SoftHSM2` are natively supported.
Other HSMs are supported too; specify `other` and check the documentation
[default: proteccio]
[possible values: proteccio, crypt2pay, utimaco, softhsm2, smartcardhsm, other]
--hsm-admin <HSM_ADMIN>...
List of KMS usernames that are granted HSM admin privileges.
HSM admins can create, destroy, and potentially export objects on the HSM.
Use `"*"` as the only entry to grant all authenticated users admin access.
Repeat the option or use a comma-separated list to specify multiple admins:
`--hsm-admin alice@example.com --hsm-admin bob@example.com`
or set `KMS_HSM_ADMIN=alice@example.com,bob@example.com`
[env: KMS_HSM_ADMIN=]
[default: admin]
--hsm-slot <HSM_SLOT>
HSM slot number. The slots used must be listed.
Repeat this option to specify multiple slots
while specifying a password for each slot (or an empty string for no password)
e.g.
```sh
--hsm-slot 1 --hsm-password password1 \
--hsm-slot 2 --hsm-password password2
```
[env: KMS_HSM_SLOT=]
--hsm-password <HSM_PASSWORD>
Password for the user logging in to the HSM Slot specified with `--hsm_slot`
Provide an empty string for no password
see `--hsm_slot` for more information.
Set `KMS_HSM_PASSWORD` to avoid the password appearing in `ps` output.
[env: KMS_HSM_PASSWORD=]
--default-unwrap-type <DEFAULT_UNWRAP_TYPE>
Specifies which KMIP object types should be automatically unwrapped when retrieved.
Repeat this option to specify multiple object types
e.g.
```sh
--default-unwrap-type SecretData \
--default-unwrap-type SymmetricKey
```
[possible values: All, Certificate, CertificateRequest, OpaqueObject, PGPKey, PrivateKey, PublicKey, SecretData, SplitKey, SymmetricKey]
--kms-public-url <KMS_PUBLIC_URL>
The exposed URL of the KMS - this is required if Google CSE configuration is activated.
If this server is running on the domain `cse.my_domain.com` with this public URL,
The configured URL from Google admin should be something like <https://cse.my_domain.com/google_cse>
The URL is also used during the authentication flow initiated from the KMS UI.
[env: KMS_PUBLIC_URL=]
--database-type <DATABASE_TYPE>
The main database of the KMS server that holds default cryptographic objects and permissions.
- postgresql: `PostgreSQL`. The database URL must be provided
- mysql: `MySql` or `MariaDB`. The database URL must be provided
- sqlite: `SQLite`. The data will be stored at the `sqlite_path` directory
A key must be supplied on every call
- redis-findex [non-FIPS]: a Redis database with encrypted data and indexes thanks to Findex.
The Redis URL must be provided, as well as the redis-master-password and the redis-findex-label
[env: KMS_DATABASE_TYPE=]
[possible values: postgresql, mysql, sqlite, redis-findex]
--database-url <DATABASE_URL>
The URL of the database for `Postgres`, `MySQL`, or `Findex-Redis`
[env: KMS_DATABASE_URL=]
--sqlite-path <SQLITE_PATH>
The directory path of the `SQLite`
[env: KMS_SQLITE_PATH=]
[default: ./sqlite-data]
--redis-master-password <REDIS_MASTER_PASSWORD>
redis-findex: a master password used to encrypt the Redis data and indexes
[env: KMS_REDIS_MASTER_PASSWORD=]
--clear-database
Clear the database on start.
WARNING: This will delete ALL the data in the database
[env: KMS_CLEAR_DATABASE=]
--max-connections <MAX_CONNECTIONS>
Maximum number of connections for the relational database pool. When not provided, falls back to the current defaults: - `PostgreSQL`/`MySQL`: min(10, 2 × CPU cores), fallback 10 - `SQLite`: number of CPUs
[env: KMS_DB_MAX_CONNECTIONS=]
--unwrapped-cache-max-age <UNWRAPPED_CACHE_MAX_AGE>
When a wrapped object is fetched from the database,
it is unwrapped and stored in the unwrapped cache.
This option specifies the maximum age in minutes of the unwrapped objects in the cache
after its last use.
The default is 15 minutes.
About 2/3 of the objects will be evicted after this time; the other 1/3 will be evicted
after a maximum of 150% of the time.
[env: KMS_UNWRAPPED_CACHE_MAX_AGE=]
[default: 15]
--unwrapped-cache-max-size <UNWRAPPED_CACHE_MAX_SIZE>
Maximum number of entries in the unwrapped key cache.
When the cache is full, the least-recently-used entry is evicted.
Set this above the number of distinct wrapped keys in your deployment
to avoid LRU thrashing. The default is 1000.
[env: KMS_UNWRAPPED_CACHE_MAX_SIZE=]
[default: 1000]
--unwrapped-cache-max-ttl <UNWRAPPED_CACHE_MAX_TTL>
Absolute time-to-live in minutes for entries in the unwrapped key cache.
When set, a cached unwrapped key is evicted at most this many minutes after
it was first inserted, regardless of how frequently it is accessed.
This caps plaintext key residency for continuously-used (hot) keys and
satisfies compliance policies that require a hard upper bound on in-memory
key material exposure.
When not set (the default), only the time-to-idle window applies and hot
keys may remain cached indefinitely.
When set, value must be ≥ `unwrapped-cache-max-age`.
[env: KMS_UNWRAPPED_CACHE_MAX_TTL=]
--disable-unwrapped-cache
Disable the unwrapped key cache entirely.
When set, every operation that needs plaintext key material will perform
a full KEK-unwrap (or HSM call) on every request instead of serving the
key from memory.
Use this in high-security environments where no plaintext key material
should persist in process memory beyond a single operation.
Disabling the cache significantly increases CPU and HSM load.
[env: KMS_DISABLE_UNWRAPPED_CACHE=]
--socket-server-start
Start the KMIP socket server? If this is set to true, the TLS config must be provided, featuring a server PKCS#12 file and a client certificate authority certificate file
[env: KMS_SOCKET_SERVER_START=]
--socket-server-port <SOCKET_SERVER_PORT>
The KMS socket server port
[env: KMS_SOCKET_SERVER_PORT=]
[default: 5696]
--socket-server-hostname <SOCKET_SERVER_HOSTNAME>
The KMS socket server hostname
[env: KMS_SOCKET_SERVER_HOSTNAME=]
[default: 0.0.0.0]
--tls-p12-file <TLS_P12_FILE>
The KMS server optional PKCS#12 Certificates and Key file as an alternative
to providing the key, certificate and chain in PEM format.
When provided, the Socket and HTTP server will start in TLS Mode.
[env: KMS_TLS_P12_FILE=]
--tls-p12-password <TLS_P12_PASSWORD>
The password to open the PKCS#12 Certificates and Key file
[env: KMS_TLS_P12_PASSWORD=]
--tls-cert-file <TLS_CERT_FILE>
The server's X.509 certificate in PEM format.
Provide a PEM containing the server leaf certificate,
optionally followed by intermediate certificates (full chain). When provided along with
`--tls-key-file`, the servers will start in TLS mode.
Do not use in combination with `--tls-p12-file`.
[env: KMS_TLS_CERT_FILE=]
--tls-key-file <TLS_KEY_FILE>
The server's private key in PEM format (PKCS#8 or traditional format).
Must correspond to the certificate in `--tls-cert-file`.
Do not use in combination with `--tls-p12-file`.
[env: KMS_TLS_KEY_FILE=]
--tls-chain-file <TLS_CHAIN_FILE>
Optional certificate chain in PEM format (intermediate CAs).
If not provided, the chain may be appended to `--tls-cert-file` instead.
Do not use in combination with `--tls-p12-file`.
[env: KMS_TLS_CHAIN_FILE=]
--clients-ca-cert-file <CLIENTS_CA_CERT_FILE>
The server's optional X. 509 certificate in PEM format validates the client certificate presented for authentication.
If provided, clients must present a certificate signed by this authority for authentication.
Mandatory to start the socket server.
[env: KMS_CLIENTS_CA_CERT_FILE=]
--tls-cipher-suites <TLS_CIPHER_SUITES>
Colon-separated list of TLS cipher suites to enable:
Example: --tls-cipher-suites `"TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"`
If not specified, OpenSSL default cipher suites will be used:
ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\
DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\
ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\
ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\
EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
AES256-SHA:DES-CBC3-SHA:!DSS"
Otherwise, the ANSSI TLS 1.2 guide recommends prioritizing AEAD suites using ECDHE
key exchange, with AES-GCM/AES-CCM (preferred) and ChaCha20-Poly1305 as an acceptable
alternative.
Example (TLS 1.2):
`TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_CCM:TLS_ECDHE_ECDSA_WITH_AES_128_CCM:TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256`
[env: KMS_TLS_CIPHER_SUITES=]
--port <PORT>
The KMS HTTP server port
[env: KMS_PORT=]
[default: 9998]
--hostname <HOSTNAME>
The KMS HTTP server hostname
[env: KMS_HOSTNAME=]
[default: 0.0.0.0]
--api-token-id <API_TOKEN_ID>
An optional API token to use for authentication on the HTTP server.
[env: KMS_API_TOKEN=]
--rate-limit-per-second <RATE_LIMIT_PER_SECOND>
Maximum number of requests per second per IP address allowed by the rate limiter.
When set, the server enforces this limit to mitigate `DoS` and brute-force attacks.
Requests exceeding the limit receive HTTP 429 Too Many Requests.
Leave unset (default) to disable rate limiting.
[env: KMS_RATE_LIMIT_PER_SECOND=]
--cors-allowed-origins <CORS_ALLOWED_ORIGINS>
Comma-separated list of origins allowed to make cross-origin requests to the KMIP API.
Required for any Web UI deployment: the browser Fetch API sends an `Origin` header on
every POST request — even when the page is served by the KMS itself — and actix-cors
rejects it unless the exact origin appears in this list.
The value must match byte-for-byte what the user types in the browser address bar
(scheme + hostname + port). The server bind address (`0.0.0.0`) and the server IP
are not equivalent to a DNS hostname. The Docker image pre-populates loopback
addresses; add any custom hostname explicitly. Example: `http://kms.example.com:9998`.
[env: KMS_CORS_ALLOWED_ORIGINS=]
--http-workers <HTTP_WORKERS>
Number of actix-web HTTP worker threads.
Defaults to the number of logical CPUs. On I/O-heavy workloads (e.g. `PostgreSQL` backend)
setting this to `2 * <number of CPU cores>` improves throughput by keeping more Tokio
threads busy while others are waiting on network I/O.
Can also be set via the `TOKIO_WORKER_THREADS` environment variable (Tokio runtime),
but this flag controls only the actix-web application workers.
[env: KMS_HTTP_WORKERS=]
--jwks-enabled
Enable the `GET /.well-known/jwks.json` endpoint.
When set, the server exposes all public keys with the `Verify` usage mask as a
RFC 7517 JSON Web Key Set. Defaults to `false`; set to `true` to enable public key
discovery for JWT verification.
[env: KMS_JWKS_ENABLED=]
--proxy-url <PROXY_URL>
The proxy URL:
- e.g., `https://secure.example` for an HTTP proxy
- e.g., `socks5://192.168.1.1:9000` for a SOCKS proxy
[env: KMS_PROXY_URL=]
--proxy-basic-auth-username <PROXY_BASIC_AUTH_USERNAME>
Set the Proxy-Authorization header username using Basic auth.
[env: KMS_PROXY_BASIC_AUTH_USERNAME=]
--proxy-basic-auth-password <PROXY_BASIC_AUTH_PASSWORD>
Set the Proxy-Authorization header password using Basic auth.
[env: KMS_PROXY_BASIC_AUTH_PASSWORD=]
--proxy-custom-auth-header <PROXY_CUSTOM_AUTH_HEADER>
Set the Proxy-Authorization header to a specified value.
[env: KMS_PROXY_CUSTOM_AUTH_HEADER=]
--proxy-exclusion-list <PROXY_EXCLUSION_LIST>
The No Proxy exclusion list to this Proxy
[env: KMS_PROXY_NO_PROXY=]
--jwt-auth-provider <JWT_AUTH_PROVIDER>
JWT authentication provider configuration.
The expected argument is --jwt-auth-provider="`PROVIDER_CONFIG_1`" --jwt-auth-provider="`PROVIDER_CONFIG_2`" ...
where each `PROVIDER_CONFIG_N` defines one identity provider configuration.
Each provider configuration `PROVIDER_CONFIG_N` should be in the format: "`JWT_ISSUER_URI,JWKS_URI,JWT_AUDIENCE_1,JWT_AUDIENCE_2,...`"
where:
- `JWT_ISSUER_URI`: The issuer URI of the JWT token (required)
- `JWKS_URI`: The JWKS (JSON Web Key Set) URI (optional, defaults to <JWT_ISSUER_URI>/.well-known/jwks.json)
- `JWT_AUDIENCE_1..N`: One or more audience values for the JWT token (optional)
Examples:
--jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs, kacls-migration, another-audience"
--jwt-auth-provider="https://login.microsoftonline.com/612da4de-35c0-42de-ba56-174b69062c96/v2.0,https://login.microsoftonline.com/612da4de-35c0-42de-ba56-174b69062c96/discovery/v2.0/keys"
--jwt-auth-provider="https://<your-tenant>.<region>.auth0.com/""
This argument can be repeated to configure multiple identity providers.
[env: KMS_JWT_AUTH_PROVIDER=]
--enable
Disable the embedded web UI. When set to false, the UI HTML assets are not served and all `/ui/` routes return 404
[env: KMS_UI_ENABLE=]
-u, --ui-index-html-folder <UI_INDEX_HTML_FOLDER>
The UI distribution folder
[env: COSMIAN_UI_DIST_PATH=]
--ui-session-salt <UI_SESSION_SALT>
A secret salt used to derive the session cookie encryption key.
This MUST be identical across all KMS instances behind the same load balancer.
This should only be provided when `ui_index_html_folder` is explicitly defined.
[env: KMS_SESSION_SALT=]
--ui-oidc-client-id <UI_OIDC_CLIENT_ID>
The client ID of the configured OIDC tenant for UI Auth
[env: UI_OIDC_CLIENT_ID=]
--ui-oidc-client-secret <UI_OIDC_CLIENT_SECRET>
The client secret of the configured OIDC tenant for UI Auth
[env: UI_OIDC_CLIENT_SECRET=]
--ui-oidc-issuer-url <UI_OIDC_ISSUER_URL>
The issuer URI of the configured OIDC tenant for UI Auth
[env: UI_OIDC_ISSUER_URL=]
--ui-oidc-logout-url <UI_OIDC_LOGOUT_URL>
The logout URI of the configured OIDC tenant for UI Auth
[env: UI_OIDC_LOGOUT_URL=]
--google-cse-enable
This setting turns on endpoints handling Google CSE feature
[env: KMS_GOOGLE_CSE_ENABLE=]
--google-cse-disable-tokens-validation
This setting turns off the validation of the tokens used by this server's Google Workspace CSE feature
[env: KMS_GOOGLE_CSE_DISABLE_TOKENS_VALIDATION=]
--google-cse-incoming-url-whitelist <GOOGLE_CSE_INCOMING_URL_WHITELIST>
This setting contains the list of KACLS server URLs that can access this server for Google CSE migration, through the privilegedunwrap endpoint (used to fetch exposed jwks on server start)
[env: KMS_GOOGLE_CSE_INCOMING_URL_WHITELIST=]
--google-cse-migration-key <GOOGLE_CSE_MIGRATION_KEY>
PEM PKCS8 RSA private key used to ensure consistency of certificate handling and privileged unwrap operations across server restarts and multiple server instances. If not provided, a random key will be generated at server startup
[env: KMS_GOOGLE_CSE_MIGRATION_KEY=]
--azure-ekm-enable
This setting turns on/off the endpoints handling Azure EKM features
[env: KMS_AZURE_EKM_ENABLE=]
--azure-ekm-path-prefix <AZURE_EKM_PATH_PREFIX>
Optional path prefix set within Managed HSM during EKM configuration.
Enables multi-customer use or isolation of different MHSM pools using the same proxy.
Must be max 64 characters: letters (a-z, A-Z), numbers (0-9), slashes (/), dashes (-).
[env: KMS_AZURE_EKM_PATH_PREFIX=]
--azure-ekm-disable-client-auth
WARNING: This bypasses mTLS authentication entirely. Only use for testing!
[env: KMS_AZURE_EKM_DISABLE_CLIENT_AUTH=]
--azure-ekm-proxy-vendor <AZURE_EKM_PROXY_VENDOR>
Proxy vendor name to report in /info endpoint
[env: KMS_AZURE_EKM_PROXY_VENDOR=]
[default: Cosmian]
--azure-ekm-proxy-name <AZURE_EKM_PROXY_NAME>
Proxy name to report in /info endpoint
[env: KMS_AZURE_EKM_PROXY_NAME=]
[default: "EKM Proxy Service"]
--azure-ekm-ekm-vendor <AZURE_EKM_EKM_VENDOR>
EKMS vendor name report in the /info endpoint
[env: KMS_AZURE_EKM_VENDOR=]
[default: Cosmian]
--azure-ekm-ekm-product <AZURE_EKM_EKM_PRODUCT>
Product Name and Version of the EKMS to report in the /info endpoint
[env: KMS_AZURE_EKM_PRODUCT=]
[default: "Cosmian KMS v5.25.0"]
--root-data-path <ROOT_DATA_PATH>
The root folder where the KMS will store its data A relative path is taken relative to the user's HOME directory
[env: KMS_ROOT_DATA_PATH=]
[default: ./cosmian-kms]
--tmp-path <TMP_PATH>
The folder to store temporary data (non-persistent data readable by no one but the current instance during the current execution)
[env: KMS_TMP_PATH=]
[default: /tmp]
--rust-log <RUST_LOG>
An alternative to setting the `RUST_LOG` environment variable.
Setting this variable will override the `RUST_LOG` environment variable
[env: KMS_RUST_LOG=]
--otlp <OTLP>
The OTLP collector URL for gRPC
(for instance, <https://localhost:4317>)
If not set, the telemetry system will not be initialized.
Must use https:// in production.
Use --otlp-allow-insecure to permit plaintext http:// connections.
[env: KMS_OTLP_URL=]
--otlp-allow-insecure
Allow insecure (plaintext HTTP) OTLP connections. WARNING: Enabling this exposes telemetry data (including encryption operation metadata) over an unencrypted channel. Only use for development or when the collector is on localhost
[env: KMS_OTLP_ALLOW_INSECURE=]
--quiet
Do not log to stdout
[env: KMS_LOG_QUIET=]
--log-to-syslog
Log to syslog
[env: KMS_LOG_TO_SYSLOG=]
--rolling-log-dir <ROLLING_LOG_DIR>
The directory for daily rolling logs: <rolling_log_name>.YYYY-MM-DD.
File logging is disabled unless this option is explicitly set.
Suggested paths:
Linux: /var/log/
Windows: C:\Users\<username>\AppData\Local\Cosmian KMS Server
macOS: ~/Library/Logs/
WARNING: Windows environment variables (e.g. %LOCALAPPDATA%) are NOT
expanded. Use the fully-resolved path.
[env: KMS_ROLLING_LOG_DIR=]
--rolling-log-name <ROLLING_LOG_NAME>
The name of the rolling log file: <rolling_log_name>.YYYY-MM-DD.
Defaults to `cosmian_kms` if not set.
[env: KMS_ROLLING_LOG_NAME=]
--enable-metering
Enable metering in addition to tracing when telemetry is enabled
[env: KMS_ENABLE_METERING=]
--environment <ENVIRONMENT>
The name of the environment (development, test, production, etc.)
This will be added to the telemetry data if telemetry is enabled
[env: KMS_ENVIRONMENT=]
[default: development]
--ansi-colors
Enable ANSI colors in the logs to stdout
[env: KMS_ANSI_COLORS=]
--privileged-users <PRIVILEGED_USERS>
List of users who have the right to create and import Objects
and grant access rights for Create Kmip Operation.
--aws-xks-enable
This setting turns on endpoints handling the AWS XKS feature
[env: KMS_AWS_XKS_ENABLE=]
--aws-xks-region <AWS_XKS_REGION>
The AWS XKS region to use for signing requests (sigv4)
[env: KMS_AWS_XKS_REGION=]
--aws-xks-service <AWS_XKS_SERVICE>
The AWS XKS service name to use for signing requests (sigv4)
[env: KMS_AWS_XKS_SERVICE=]
--aws-xks-sigv4-access-key-id <AWS_XKS_SIGV4_ACCESS_KEY_ID>
The AWS XKS `SigV4` access key ID used to sign requests
[env: KMS_AWS_XKS_SIGV4_ACCESS_KEY_ID=]
--aws-xks-sigv4-secret-access-key <AWS_XKS_SIGV4_SECRET_ACCESS_KEY>
[env: KMS_AWS_XKS_SIGV4_SECRET_ACCESS_KEY=]
--kmip-policy-id <POLICY_ID>
KMIP algorithm policy selector.
Accepted values (case-insensitive):
- `DEFAULT`: enforce the built-in conservative allowlists (aligned with ANSSI/NIST/FIPS).
- `CUSTOM`: enforce the allowlists provided under `[kmip.allowlists]`.
[env: KMS_POLICY_ID=]
--auto-rotation-check-interval-secs <AUTO_ROTATION_CHECK_INTERVAL_SECS>
Interval in seconds between background auto-rotation checks.
Set to 0 (default) to disable the auto-rotation background task.
When enabled, must be at least 60 seconds to avoid excessive database churn.
[default: 0]
--keyset-warn-depth <KEYSET_WARN_DEPTH>
Depth at which a successful keyset chain decryption triggers a server-side warning.
Keyset chain traversal is unbounded (stopped only by cycle detection);
this threshold emits a warning log so operators can flag stale ciphertexts.
Default: 5.
[default: 5]
--backend <BACKEND>
Possible values:
- vault: `HashiCorp` Vault KV-v2. Path format: `secret://<mount>/<path>[#<field>]`
- aws-ssm: AWS Systems Manager Parameter Store. Path format: `secret://<region>/<parameter-name>`
- azure-kv: Azure Key Vault. Path format: `secret://<vault-name>/secrets/<name>[/<version>]`
- cosmian-kms: Another Cosmian KMS server (KMIP Get). Path format: `secret://<host>[:<port>]/<object-id>`
[env: KMS_SECRET_BACKEND=]
--vault-addr <VAULT_ADDR>
[env: VAULT_ADDR=]
[default: http://127.0.0.1:8200]
--vault-token <VAULT_TOKEN>
[env: VAULT_TOKEN=]
[default: ""]
--aws-access-key-id <AWS_ACCESS_KEY_ID>
[env: AWS_ACCESS_KEY_ID=]
[default: ""]
--aws-secret-access-key <AWS_SECRET_ACCESS_KEY>
[env: AWS_SECRET_ACCESS_KEY=]
[default: ""]
--aws-session-token <AWS_SESSION_TOKEN>
[env: AWS_SESSION_TOKEN=]
--azure-tenant-id <AZURE_TENANT_ID>
[env: AZURE_TENANT_ID=]
[default: ""]
--azure-client-id <AZURE_CLIENT_ID>
[env: AZURE_CLIENT_ID=]
[default: ""]
--azure-client-secret <AZURE_CLIENT_SECRET>
[env: AZURE_CLIENT_SECRET=]
[default: ""]
--cosmian-kms-secret-token <COSMIAN_KMS_SECRET_TOKEN>
[env: COSMIAN_KMS_SECRET_TOKEN=]
--cosmian-kms-insecure-certs
[env: COSMIAN_KMS_INSECURE_CERTS=]
--jwks-endpoint-enabled
Enable the `GET /.well-known/jwks.json` endpoint.
When set, the server publicly exposes all active public keys whose
`CryptographicUsageMask` includes `Verify` as a RFC 7517 JSON Web Key Set.
The endpoint is **unauthenticated** — no credentials are required to fetch it,
and no authentication middleware is applied. Defaults to `false`.
[env: KMS_JWKS_ENDPOINT_ENABLED=]
--jwks-endpoint-max-keys <JWKS_ENDPOINT_MAX_KEYS>
Maximum number of public keys returned in a single JWKS response.
When the server holds more eligible keys than this limit, the response is
truncated and an `X-JWKS-Truncated: true` header is added to signal consumers.
Increase this value if your deployment performs frequent key rotation and all
overlapping verification keys must be simultaneously discoverable.
[env: KMS_JWKS_ENDPOINT_MAX_KEYS=]
[default: 50]
--jwks-endpoint-auto-tag
Automatically tag key pairs created via the REST crypto API for JWKS inclusion.
When `true` (the default), every key pair created via `POST /v1/crypto/keys`
receives the `"jwks"` tag and immediately appears in
`GET /.well-known/jwks.json`.
Set to `false` to disable this behaviour globally. Operators must then
manually tag each public key via `POST /v1/crypto/keys/{kid}/tags` before
it is published in the JWKS document.
This setting has no effect on keys created directly through the KMIP protocol.
[env: KMS_JWKS_ENDPOINT_AUTO_TAG=]
-h, --help
Print help (see a summary with '-h')
-V, --version
Print version
By default, the server runs using a SQLite database, but it can be configured to use a choice of databases: SQLite encrypted, PostgreSQL, MariaDB, MySQL, and Percona XtraDB Cluster, as well as Redis, using the Redis-with-Findex configuration.
Selecting the database
All databases, except SQLite, can be used in a high-availability setup.
The SQLite database can serve high loads and millions of objects, and is very suitable for scenarios that do not demand high availability.
Redis with Findex
Redis with Findex offers the ability to use Redis as a database with application-level encryption: all data is encrypted (using AES 256 GCM) by the KMS servers before being sent to Redis. Findex is an Eviden cryptographic algorithm used to build encrypted indexes on encrypted data, also stored in Redis. This allows the KMS to perform fast encrypted queries on encrypted data. Redis with Findex offers post-quantum resistance on encrypted data and encrypted indexes.
Redis-with-Findex is most useful when:
- KMS servers are run inside a confidential VM or an enclave. In this case, the secret used to encrypt the Redis data and indexes, is protected by the VM or enclave and cannot be recovered at runtime by inspecting the KMS servers' memory.
- KMS servers are run by a trusted party but the Redis backend is managed by an untrusted third party.
Redis-with-Findex is the database selected to run the Eviden KMS in the cloud or any other zero-trust environment.
Configuring the database
The database parameters may be configured either:
- the TOML configuration file
- or the arguments passed to the server on the command line.
SQLite
This is the default configuration. To use SQLite, no additional configuration is needed.
[db]
database_type = "sqlite"
sqlite_path = "./sqlite-data"
--database-type=sqlite \
--sqlite-path="./sqlite-data"
PostgreSQL
[db]
database_type = "postgresql"
database_url = "postgres://kms_user:kms_password@pgsql-server:5432/kms"
--database-type=postgresql \
--database-url=postgres://kms_user:kms_password@pgsql-server:5432/kms
!!!info "Setting up a PostgreSQL database"
Before running the server, a dedicated database with a dedicated user should be created on the PostgreSQL instance.
These sample instructions create a database called kms owned by a user kms_user with password kms_password:
-
Connect to psql under user
postgressudo -u postgres psql # or `psql -U postgres` -
Create user
kms_userwith passwordkms_passwordcreate user kms_user with encrypted password 'kms_password'; -
Create database
kmsunder ownerkms_usercreate database kms owner=kms_user;
PostgreSQL High-Availability (multi-host)
The KMS supports multi-host PostgreSQL connection strings for high-availability deployments
(streaming replication, Patroni, pgBouncer clusters, etc.). The database-url value is treated
as a raw string so that host1:port,host2:port syntax — which the standard URL parser cannot
handle — is passed directly to the PostgreSQL driver.
Use the target_session_attrs query parameter to control which node the driver connects to:
| Value | Behaviour |
|---|---|
read-write | Connect only to the primary (default for HA) |
any | Connect to any available node (suitable for read replicas) |
read-only | Connect only to a standby |
Example — two-node HA cluster:
[db]
database_type = "postgresql"
database_url = "postgresql://kms_user:kms_password@primary:5432,standby:5432/kms?target_session_attrs=read-write"
--database-type=postgresql \
--database-url="postgresql://kms_user:kms_password@primary:5432,standby:5432/kms?target_session_attrs=read-write"
The URL must start with postgresql:// or postgres://; any other scheme is rejected at
startup.
PostgreSQL failover retry
When a PostgreSQL primary fails over, the driver may return transient connection errors before the new primary is ready. The KMS automatically retries failed queries with exponential backoff for the following PostgreSQL SQLSTATE codes:
| SQLSTATE | Meaning |
|---|---|
08001 | sqlclient_unable_to_establish_sqlconnection |
08004 | sqlserver_rejected_establishment_of_sqlconnection |
57P02 | crash_shutdown |
57P03 | cannot_connect_now |
No additional configuration is required; the retry behaviour is enabled automatically for all PostgreSQL connections.
MySQL, MariaDB, or Percona XtraDB Cluster
The KMS supports MySQL-compatible databases including MySQL, MariaDB, and Percona XtraDB Cluster.
All use the same configuration with database-type=mysql.
!!! note Clustering Support As of version 5.13.0, the KMS schema includes PRIMARY KEY constraints on all tables, making it fully compatible with:
- **Percona XtraDB Cluster** (with `pxc_strict_mode=ENFORCING`)
- **MariaDB Galera Cluster**
- Any MySQL clustering solution requiring PRIMARY KEYs for replication
[db]
database_type = "mysql"
database_url = "mysql://kms_user:kms_password@mysql-server:3306/kms"
--database-type=mysql \
--database-url=mysql://kms_user:kms_password@mysql-server:3306/kms
!!!info "Using a certificate to authenticate to MySQL or MariaDB"
Use a certificate to authenticate to MySQL or MariaDB with the `mysql-user-cert-file` option to
specify the certificate file name.
**Example context**: say the certificate is called `cert.p12`
and is in a directory called `/certificate` on the host disk.
docker run --rm -p 9998:9998 \
--name kms ghcr.io/cosmian/kms:latest \
-v /certificate/cert.p12:/root/cosmian-kms/cert.p12 \
--database-type=mysql \
--database-url=mysql://mysql_server:3306/kms \
--mysql-user-cert-file=cert.p12
[db]
database_type = "mysql"
database_url = "mysql://mysql_server:3306/kms"
# Note: if client certificate authentication is required for MySQL,
# configure it via command-line option `--mysql-user-cert-file` for now.
# A dedicated TOML key may not be available in this version.
Redis with Findex
For Redis with Findex, the --redis-master-password and --redis-findex-label options must also be specified:
- The
redis-master-passwordis the password from which keys will be derived (using Argon 2) to encrypt the Redis data and indexes. - The
redis-findex-labelis a public, arbitrary label that can be changed to rotate the Findex ciphertexts without changing the password/key.
[db]
database_type = "redis-findex"
database_url = "redis://localhost:6379"
redis_master_password = "password"
redis_findex_label = "label"
--database-type=redis-findex \
--database-url=redis://localhost:6379 \
--redis-master-password=password \
--redis-findex-label=label
- Redis (with-Findex), use:
Securing database connections with TLS / mTLS
The KMS supports TLS-encrypted connections and mutual TLS (mTLS) client-certificate authentication
for PostgreSQL and MySQL-compatible databases. All TLS parameters are configured directly in the
database-url as query parameters — no extra CLI flags or TOML keys are needed.
PostgreSQL TLS / mTLS
PostgreSQL TLS is configured using the standard libpq-style query parameters in the connection URL.
| Parameter | Description |
|---|---|
sslmode | TLS mode: disable, prefer (default), require, verify-ca, verify-full |
sslrootcert | Path to the CA certificate (PEM) used to verify the server |
sslcert | Path to the client certificate (PEM) for mTLS |
sslkey | Path to the client private key (PEM) for mTLS |
Server-authenticated TLS only (encrypt the connection and verify the server certificate):
[db]
database_type = "postgresql"
database_url = "postgres://kms:kms@pgsql-server:5432/kms?sslmode=verify-ca&sslrootcert=/path/to/ca.crt"
--database-type=postgresql \
--database-url="postgres://kms:kms@pgsql-server:5432/kms?sslmode=verify-ca&sslrootcert=/path/to/ca.crt"
Mutual TLS (mTLS) (encrypt + verify server certificate + present a client certificate):
[db]
database_type = "postgresql"
database_url = "postgres://kms:kms@pgsql-server:5432/kms?sslmode=verify-full&sslrootcert=/path/to/ca.crt&sslcert=/path/to/client.crt&sslkey=/path/to/client.key"
--database-type=postgresql \
--database-url="postgres://kms:kms@pgsql-server:5432/kms?sslmode=verify-full&sslrootcert=/path/to/ca.crt&sslcert=/path/to/client.crt&sslkey=/path/to/client.key"
disable– no TLS at all.prefer(default) /require– TLS is used but the server certificate is not verified.verify-ca– the server certificate is verified against the CA but the hostname is not checked.verify-full– the server certificate is verified against the CA and the hostname must match.
All certificates must be in PEM format.
MySQL / MariaDB TLS / mTLS
MySQL TLS is configured using query parameters in the connection URL.
Both dash (ssl-mode) and underscore (ssl_mode) variants are accepted.
| Parameter | Description |
|---|---|
ssl-mode | TLS mode: DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY |
ssl-ca | Path to the CA certificate (PEM) for server verification |
ssl-client-identity | Path to the client PKCS#12 (.p12) bundle for mTLS |
ssl-client-identity-password | Password protecting the PKCS#12 bundle |
Server-authenticated TLS only (encrypt the connection and verify the server certificate):
[db]
database_type = "mysql"
database_url = "mysql://kms:kms@mysql-server:3306/kms?ssl-mode=VERIFY_CA&ssl-ca=/path/to/ca.crt"
--database-type=mysql \
--database-url="mysql://kms:kms@mysql-server:3306/kms?ssl-mode=VERIFY_CA&ssl-ca=/path/to/ca.crt"
Mutual TLS (mTLS) (encrypt + verify server certificate + present a client certificate):
[db]
database_type = "mysql"
database_url = "mysql://kms:kms@mysql-server:3306/kms?ssl-mode=VERIFY_CA&ssl-ca=/path/to/ca.crt&ssl-client-identity=/path/to/client.p12&ssl-client-identity-password=secret"
--database-type=mysql \
--database-url="mysql://kms:kms@mysql-server:3306/kms?ssl-mode=VERIFY_CA&ssl-ca=/path/to/ca.crt&ssl-client-identity=/path/to/client.p12&ssl-client-identity-password=secret"
DISABLED– no TLS at all.PREFERRED/REQUIRED– TLS is used but the server certificate is not verified.VERIFY_CA– the server certificate is verified against the CA.VERIFY_IDENTITY– the server certificate is verified against the CA and the hostname must match.
MySQL client-certificate authentication requires the certificate and private key bundled as a
PKCS#12 (.p12) file — PEM files are not supported.
You can create the bundle using OpenSSL:
openssl pkcs12 -export \
-in client.crt -inkey client.key \
-out client.p12 -passout pass:secret
PKCS#12 client identity (ssl-client-identity) is not available in FIPS mode.
MySQL mTLS with client certificates requires the non-fips feature.
Clearing the database
The KMS server can be configured to clear the database on restart automatically.
The cleanup operation will delete all objects and keys stored in the database.
[db]
clear_database = true
--clear-database
Database migration
Depending on the KMS database evolution, a migration can happen between 2 versions of the KMS server. It will be clearly written in the CHANGELOG.md. In that case, a generic database upgrade mechanism is run on startup.
At first, the table context is responsible for storing the software run's version and the database's state.
The state can be one of the following:
ready: the database is ready to be usedupgrading: the database is being upgraded
On startup, the server checks if the software version is greater than the last version run:
-
if no, it simply starts;
-
If yes:
- it looks for all upgrades to apply in order from the last version run to this version;
- if there is any to run, it sets an upgrading flag on the db state field in the context table;
- it runs all the upgrades in order.
- it sets the flag from upgrading to ready;
On every call to the database, a check is performed on the db state field to check if the database is upgrading. If yes, calls fail.
Upgrades resist being interrupted in the middle and resumed from the start if that happens.
MySQL schema update (5.13.0)
As of version 5.13.0, the MySQL schema was updated to include PRIMARY KEY constraints on the tags and read_access tables to ensure compatibility with MySQL clustering solutions (e.g., Percona XtraDB Cluster with pxc_strict_mode=ENFORCING, MariaDB Galera).
New installations of 5.13.0+ automatically create the corrected tables.
Existing installations upgrading to 5.13.0 will keep the old table definitions if those tables already exist. If you rely on clustering/replication that requires PRIMARY KEYs, apply the following manual migration before starting the KMS:
-- Fix tags table
ALTER TABLE tags
DROP INDEX id,
MODIFY id VARCHAR(128) NOT NULL,
MODIFY tag VARCHAR(255) NOT NULL,
ADD PRIMARY KEY (id, tag);
-- Fix read_access table
ALTER TABLE read_access
DROP INDEX id,
MODIFY id VARCHAR(128) NOT NULL,
MODIFY userid VARCHAR(255) NOT NULL,
ADD PRIMARY KEY (id, userid);
Notes:
- Run these statements using a privileged MySQL user (e.g.,
root). - Ensure application access is paused during the migration.
- No data loss occurs; this operation converts UNIQUE constraints to PRIMARY KEYs and enforces NOT NULL.
The Unwrapped Objects Cache
For the full technical reference on the KMS in-memory caches — architecture, public API, configuration options, and security trade-offs — see Object Cache and Unwrapped Cache.
The unwrapped cache is a memory cache, and it is not persistent. The unwrapped cache is used to store unwrapped objects that are fetched from the database.
When a wrapped object is fetched from the database, it is unwrapped and stored in the unwrapped cache. Further calls to the same object will use the unwrapped object from the cache until the cache expires.
The time in minutes after which an unused object is evicted from the cache is configurable
using the unwrapped_cache_max_age setting. The default is 15 minutes.
When HSM keys wrap objects, a long expiration time will reduce the number of calls made to HSM to unwrap the object. However, increasing the cache time will increase the memory used by the KMS server and expose the key in clear text in the memory for a longer time.
Object Cache and Unwrapped Cache
The KMS server uses two in-memory caches backed by
moka::future::Cache,
a lock-free concurrent hash map. Both caches use sharding so multiple
Actix-web worker threads can read simultaneously without serialization.
Architecture overview
graph TD
CALLER[Caller]
CALLER -->|retrieve_object| DB[Database]
CALLER -->|get_unwrapped| GU[get_unwrapped]
DB -->|get| OC[ObjectCache]
OC -->|miss| BS[(Backing Store<br/>SQLite / Postgres)]
GU -->|peek| UC[UnwrappedCache]
UC -->|miss| CRYPTO[unwrap_object<br/>KEK unwrap]
OC -->|stores| OC_VAL["wrapped ObjectWithMetadata<br/>+ fingerprint"]
UC -->|stores| UC_VAL["unwrapped key material<br/>+ fingerprint of wrapped"]
style BS fill:#f9f,stroke:#333
style CRYPTO fill:#f99,stroke:#333
style OC fill:#9f9,stroke:#333
style UC fill:#9f9,stroke:#333
| Cache | Key | Value | Miss path |
|---|---|---|---|
| ObjectCache | UID string | Arc<ObjectWithMetadata> (wrapped) + fingerprint | DB fetch → insert → return |
| UnwrappedCache | UID string | unwrapped Object + fingerprint of wrapped | Crypto unwrap → insert → return |
ObjectCache
Source: crate/server_database/src/core/object_cache.rs
Caches full ObjectWithMetadata as read from the database to eliminate repeated
DB round-trips on the hot path.
Public API
| Method | Returns | Description |
|---|---|---|
get(uid) | Option<Arc<ObjectWithMetadata>> | Lock-free lookup. Returns cheap Arc clone. |
insert(uid, owm) | DbResult<()> | Store with fingerprint of owm.object(). |
insert_arc(uid, arc_owm) | DbResult<()> | Store from existing Arc (saves one allocation). |
invalidate(uid) | — | Remove entry. |
validate_cache(uid, current) | DbResult<()> | Compare fingerprints; invalidate on mismatch. |
Callers
Database::retrieve_object()—get()on hot path,insert()on missDatabase::retrieve_object_arc()—get(),insert_arc()on missDatabase::update_object()—invalidate()on writeDatabase::validate_cache()—validate_cache()after forced re-fetch
Scenarios
S1 — Cold start (first access)
sequenceDiagram
participant C as Caller
participant DB as Database
participant OC as ObjectCache
participant BS as Backing Store
C->>DB: retrieve_object("key-1")
DB->>OC: get("key-1")
OC-->>DB: None
DB->>BS: retrieve("key-1")
BS-->>DB: ObjectWithMetadata (wrapped)
DB->>OC: insert("key-1", owm)
DB-->>C: owm
S2 — Hot path (cache hit)
sequenceDiagram
participant C as Caller
participant DB as Database
participant OC as ObjectCache
C->>DB: retrieve_object("key-1")
DB->>OC: get("key-1")
OC-->>DB: cached entry found
DB-->>C: owm via Arc unwrap_or_clone
S3 — retrieve_object_arc (zero-copy Arc path)
sequenceDiagram
participant C as Caller
participant DB as Database
participant OC as ObjectCache
participant BS as Backing Store
C->>DB: retrieve_object_arc("key-1")
DB->>OC: get("key-1")
alt Cache hit
OC-->>DB: cached Arc found
DB-->>C: Arc clone (pointer bump)
else Cache miss
OC-->>DB: None
DB->>BS: retrieve("key-1")
BS-->>DB: owm
DB->>OC: insert_arc("key-1", Arc.new(owm))
DB-->>C: Arc
end
S4 — Out-of-band mutation detected
sequenceDiagram
participant DB as Database
participant OC as ObjectCache
Note over DB: Another process mutated "key-1"
DB->>OC: validate_cache("key-1", current_db_object)
OC->>OC: fingerprint(cached) != fingerprint(current)?
OC->>OC: invalidate("key-1")
Note over OC: Next get() triggers fresh DB fetch
S5 — Object update invalidates cache
sequenceDiagram
participant C as Caller
participant DB as Database
participant OC as ObjectCache
C->>DB: update_object("key-1", new_obj, new_attrs)
DB->>OC: invalidate("key-1")
DB->>DB: persist to backing store
Note over OC: Entry removed, next get() is miss
S6 — Eviction (automatic)
moka eviction requires no explicit call:
| Policy | Trigger | Effect |
|---|---|---|
| LRU | max_capacity exceeded | Least-recently-used entry evicted |
| TTL | time_to_idle elapsed without access | Entry evicted |
UnwrappedCache
Source: crate/server_database/src/core/unwrapped_cache.rs
Caches unwrapped key material to avoid repeated KEK-unwrap cryptographic operations. The fingerprint of the wrapped object is stored alongside the unwrapped payload so stale entries (after key re-wrapping or KEK rotation) are silently rejected.
Public API
| Method | Returns | Description |
|---|---|---|
peek(uid, wrapped) | DbResult<Option<Object>> | Returns unwrapped object if fingerprint matches. |
insert(uid, wrapped, unwrapped) | DbResult<()> | Stores unwrapped with wrapped fingerprint. |
clear_cache(uid) | — | Removes entry. |
validate_cache(uid, object) | DbResult<()> | Fingerprint check; invalidate on mismatch. |
Security guard: insert returns Err if wrapped == unwrapped (defense-in-depth
against plaintext-persistence bugs).
Callers
KMS::get_unwrapped()—peek()+insert()on miss- KMIP ReKey / ReKeyKeyPair —
clear_cache()after rotation Database::validate_cache()chain —validate_cache()for defense-in-depth
Scenarios
U1 — First unwrap (cold)
sequenceDiagram
participant G as get_unwrapped()
participant UC as UnwrappedCache
participant CR as Crypto
G->>UC: peek("key-1", wrapped_obj)
UC-->>G: None (no entry)
G->>CR: unwrap_object(wrapped_obj)
Note over CR: KEK unwrap
CR-->>G: unwrapped Object
G->>UC: insert("key-1", wrapped_obj, unwrapped_obj)
Note over UC: Stores fingerprint(wrapped) + unwrapped
G-->>G: return unwrapped
U2 — Subsequent unwrap (hot, zero crypto)
sequenceDiagram
participant G as get_unwrapped()
participant UC as UnwrappedCache
G->>UC: peek("key-1", wrapped_obj)
UC->>UC: fingerprint matches?
UC-->>G: Some(unwrapped_obj)
Note over G: No cryptographic operation
G-->>G: return unwrapped
U3 — Key re-wrapped (KEK rotation)
sequenceDiagram
participant G as get_unwrapped()
participant UC as UnwrappedCache
participant CR as Crypto
Note over G: wrapped_obj changed (new KEK after rotation)
G->>UC: peek("key-1", new_wrapped_obj)
UC->>UC: fingerprint mismatch
UC-->>G: None (stale entry rejected)
G->>CR: unwrap_object(new_wrapped_obj)
CR-->>G: unwrapped Object
G->>UC: insert("key-1", new_wrapped_obj, unwrapped)
Note over UC: New fingerprint replaces old entry
G-->>G: return unwrapped
U4 — Security guard (wrapped == unwrapped)
sequenceDiagram
participant G as get_unwrapped()
participant UC as UnwrappedCache
Note over G: Bug: caller passes already-unwrapped object
G->>UC: insert("key-1", obj, obj)
UC->>UC: wrapped == unwrapped?
UC-->>G: Err("wrapped and unwrapped objects should be different")
Note over UC: Prevents plaintext-persistence bugs
U5 — Explicit invalidation on key rotation
sequenceDiagram
participant R as ReKey / Rekeyer
participant UC as UnwrappedCache
R->>UC: clear_cache("key-1")
Note over UC: Entry removed
Note over UC: Next get_unwrapped() triggers crypto unwrap
U6 — Concurrent workers (double-unwrap acceptable)
sequenceDiagram
participant W1 as Worker 1
participant W2 as Worker 2
participant UC as UnwrappedCache
participant CR as Crypto
W1->>UC: peek("key-1", wrapped)
UC-->>W1: None (cold)
W2->>UC: peek("key-1", wrapped)
UC-->>W2: None (W1 has not inserted yet)
W1->>CR: unwrap_object(...)
CR-->>W1: unwrapped
W1->>UC: insert("key-1", wrapped, unwrapped)
Note over W2: Received None, must also unwrap
W2->>CR: unwrap_object(...)
CR-->>W2: unwrapped
W2->>UC: insert("key-1", wrapped, unwrapped)
Note over UC: Double unwrap on cold start is acceptable
End-to-end: JOSE decrypt
Full trace of POST /v1/crypto/decrypt with alg: RSA-OAEP. The RSA wrapping
key (persistent DB object, identified by kid) passes through both caches.
The CEK (ephemeral, from the JWE encrypted_key field) is never cached.
sequenceDiagram
participant J as JOSE /decrypt
participant RF as retrieve_object_for_operation
participant DB as Database
participant OC as ObjectCache
participant GU as get_unwrapped()
participant UC as UnwrappedCache
participant CR as Crypto
participant OS as OpenSSL
J->>RF: retrieve_object_for_operation(kid, Decrypt)
RF->>DB: retrieve_objects(kid)
alt ObjectCache hit
DB->>OC: get(kid)
OC-->>DB: cached (wrapped)
else ObjectCache miss
DB->>OC: get(kid)
OC-->>DB: None
DB->>DB: fetch from SQLite or Postgres
DB->>OC: insert(kid, owm)
end
DB-->>RF: owm (wrapped)
RF->>GU: get_unwrapped(kid, wrapped_obj, user)
alt UnwrappedCache hit
GU->>UC: peek(kid, wrapped_obj)
UC-->>GU: Some(unwrapped_obj)
Note over GU: No crypto
else UnwrappedCache miss
GU->>UC: peek(kid, wrapped_obj)
UC-->>GU: None
GU->>CR: unwrap_object(wrapped_obj)
Note over CR: KEK unwrap
CR-->>GU: unwrapped Object
GU->>UC: insert(kid, wrapped_obj, unwrapped_obj)
end
GU-->>RF: unwrapped Object
RF->>RF: owm.set_object(unwrapped)
RF-->>J: owm with plaintext key
J->>OS: kmip_private_key_to_openssl(owm.object())
OS-->>J: OpenSSL PKey Private
J->>OS: RSA private decrypt(encrypted_key)
OS-->>J: CEK (Content Encryption Key)
J->>OS: AES-GCM decrypt(ciphertext, CEK)
OS-->>J: plaintext
J->>UC: insert_cek(sha256(encrypted_key), cek)
Note over J,UC: CEK cached in UnwrappedCache for subsequent decrypt calls
Per-scenario cache behavior
| Scenario | ObjectCache | UnwrappedCache | DB round-trip | Crypto unwrap |
|---|---|---|---|---|
| 1st access, cold | miss → DB → insert | miss → crypto → insert | ✓ | ✓ |
| 2nd access, hot | hit | hit | — | — |
| Key re-wrapped (new KEK) | hit (wrapped) | miss → crypto → insert | — | ✓ |
| Cache evicted (TTL / LRU) | miss → DB → insert | miss → crypto → insert | ✓ | ✓ |
| Object updated in DB | invalidated → miss → DB | still valid (fingerprint unchanged) | ✓ | — |
| KEK rotated (Rekey) | invalidated | clear_cache() called explicitly | ✓ | ✓ (next access) |
JOSE CEK Cache (RSA-OAEP path)
The /v1/crypto/encrypt and /v1/crypto/decrypt endpoints support a
RSA-OAEP / RSA-OAEP-256 key-management algorithm (RFC 7516). Each
decryption requires an RSA private-key operation to unwrap the ephemeral
Content Encryption Key (CEK). When the same JWE token is decrypted
repeatedly, this operation is repeated on every call.
The CEK is stored in UnwrappedCache after the first successful unwrap so
subsequent requests for the same token skip the RSA operation entirely.
Cache key
"jose_cek_{SHA-256-hex(encrypted_key_bytes)}"
The JWE encrypted_key field (the RSA-OAEP ciphertext of the CEK) uniquely
identifies a token because RSA-OAEP encryption is randomised. SHA-256 keeps the
map key compact: 64 hex chars regardless of RSA key size.
Fingerprint source
The RSA private-key KMIP Object is passed as the fingerprint source at
insert() and peek() time. If the key is re-imported or re-wrapped (its
serialised form changes), the fingerprint stored in the cache entry no longer
matches and peek() returns None, forcing a fresh RSA-OAEP unwrap and
re-population.
/encrypt → /decrypt cross-path caching
When /encrypt is called, the freshly generated CEK is inserted into the cache
immediately after wrapping, keyed by the encrypted_key returned in the JWE
response. The first /decrypt call for that token will get a cache hit if both
calls share the same server instance and the key has not changed.
If /encrypt uses a public-key KMIP object while /decrypt uses the linked
private-key KMIP object, the fingerprints differ. In that case the first decrypt
call replaces the stale entry with a correctly fingerprinted one; all subsequent
decrypts hit the cache.
TTL and sizing
CEK cache entries share the same UnwrappedCache TTL and LRU capacity as
wrapped KMS keys:
| Parameter | CLI flag | Description |
|---|---|---|
| Max entries | --unwrapped-cache-max-size | Default 1000. Increase for workloads with many concurrent JWE tokens. |
| Time-to-idle | --unwrapped-cache-max-age | Entries evicted after this idle period. |
RFC 7516 §11.5 — implicit rejection preserved
Only genuinely unwrapped CEKs are inserted. The random substitute key generated
when RSA-OAEP decryption fails (padding oracle countermeasure) is never
cached. This preserves the constant-time rejection guarantee: an attacker
submitting an invalid encrypted_key still causes AES-GCM to fail at tag
verification, and no cache entry is written.
dir mode
The dir key-management algorithm uses a KMS-stored symmetric key directly.
That path delegates to the KMIP Encrypt/Decrypt pipeline which already
passes through UnwrappedCache via get_unwrapped(). No additional caching is
required.
Configuration
Both caches are configured via the server configuration file or CLI flags:
| Parameter | CLI flag | Default | Description |
|---|---|---|---|
object_cache_max_size | --cache-max-size | 1000 | Max entries in ObjectCache before LRU eviction |
object_cache_max_age | --cache-max-age | 15 s | Time-to-idle: entry evicted after this idle period (seconds) |
unwrapped_cache_max_size | --unwrapped-cache-max-size | 1000 | Max entries in UnwrappedCache |
unwrapped_cache_max_age | --unwrapped-cache-max-age | 15 s | Time-to-idle for UnwrappedCache entries (seconds) |
unwrapped_cache_max_ttl | --unwrapped-cache-max-ttl | (none) | Absolute time-to-live ceiling (seconds). When set, every entry is evicted at min(TTI, TTL) regardless of access frequency. See Security considerations. |
disable_unwrapped_cache | --disable-unwrapped-cache | false | Completely bypass the UnwrappedCache. Every operation performs a full KEK unwrap. See Disabling the UnwrappedCache. |
TTL vs TTI:
max_age(time-to-idle) resets on every cache hit. A frequently accessed key is never evicted by TTI alone.max_ttlis an absolute ceiling independent of access frequency. For compliance environments that require a maximum plaintext-key exposure window, always setmax_ttl.
Security considerations
-
ObjectCache never stores plaintext keys. It mirrors the database: objects are stored as-retrieved (wrapped). All callers provide the DB state.
-
UnwrappedCache validates against wrapped fingerprint.
peek()compares the caller'swrapped_objectfingerprint against the stored fingerprint. If the wrapped object changed (re-wrapped, corrupted), the entry is silently rejected. -
Security guard rejects
wrapped == unwrapped.insert()returns an error if the caller passes an already-unwrapped object as the wrapped argument. This is defense-in-depth against plaintext-persistence bugs. -
UnwrappedCache does NOT participate in persistence. Unlike ObjectCache (checked by
retrieve_objectbefore every DB read), UnwrappedCache is only consulted byget_unwrapped(). Objects from UnwrappedCache are consumed in-memory for cryptographic operations and never written back to the database. -
Concurrent cold-start double-unwrap is acceptable. If two workers call
get_unwrapped()simultaneously for a cold key, both perform the cryptographic unwrap. The secondinsert()overwrites the first. This wastes one unwrap but avoids lock contention — a tradeoff favoring throughput. -
TTI amplifies plaintext exposure window. With the default 15-second time-to-idle, a continuously accessed key's plaintext material stays resident indefinitely. For compliance environments with a bounded key-exposure requirement (e.g. FIPS operational security policies, PCI-DSS, or NIS2), set
--unwrapped-cache-max-ttlto enforce an absolute ceiling:cosmian_kms --unwrapped-cache-max-ttl 60 # evict plaintext after at most 60 s -
Memory-zeroization on eviction. When an entry is evicted from
UnwrappedCache, the plaintextObjectis explicitly zeroized before deallocation. AllZeroizing<Vec<u8>>byte buffers (symmetric keys, private-key components) andSafeBigIntfields are overwritten with zeroes. This reduces the window during which sensitive key material could be recovered from freed memory pages. -
CPU-level side-channel risk (CacheFX / Prime+Probe). Plaintext key material held in the
UnwrappedCacheoccupies resident DRAM pages. Modern CPU microarchitectural attacks (Prime+Probe, Flush+Reload) can potentially exfiltrate AES round-key material and RSA/EC private-key bits from shared L3 cache lines. These attacks require local code execution on the same physical host. Mitigations:- Keep
--unwrapped-cache-max-ttllow (≤ 60 s) to limit the attack window. - Use
--disable-unwrapped-cachein high-security deployments where KEK unwrap latency is acceptable. - Run the KMS on dedicated (non-shared) hardware or inside a hardware-enforced enclave (SEV-SNP, TDX) to eliminate co-tenant cache-sharing.
- Keep
Disabling the UnwrappedCache
The UnwrappedCache trades security for performance: every cache hit saves a
full KEK-unwrap operation but keeps plaintext key material in process memory
between calls.
To disable it entirely — so that every operation performs a fresh cryptographic unwrap and no plaintext key material is ever cached — use:
# CLI flag
cosmian_kms --disable-unwrapped-cache
# Environment variable
KMS_DISABLE_UNWRAPPED_CACHE=true cosmian_kms
# Configuration file (kms.toml / server.toml)
disable_unwrapped_cache = true
When disabled:
peek()always returnsNone, causing everyget_unwrapped()to perform the full KEK-unwrap cryptographic operation.insert()is a no-op; plaintext key material is never stored in the cache.- The
ObjectCache(wrapped objects) is not affected: database round-trips are still cached for performance.
Trade-off: Disabling the UnwrappedCache increases per-operation latency by one full asymmetric-key operation (RSA-OAEP or ECDH unwrap). For a 2048-bit RSA KEK on a modern server, this is typically 0.5–2 ms per call. For symmetric KEKs (AES-256 key-wrap), the overhead is under 0.1 ms.
The ObjectCache can be configured to very short TTI or very small capacity to
reduce wrapped-object retention, but it cannot be disabled via a flag — set
--cache-max-age 1 --cache-max-size 1 to minimise its footprint if needed.
Authentication
The KMS server offers flexible authentication options, supporting multiple authentication methods that can operate independently or in combination with each other, providing multi-factor authentication capabilities.
Authentication Modes
Non-authenticated Mode (Default)
By default, if no authentication methods are configured, the server operates in non-authenticated mode. All requests are mapped to the default user, which can be configured using:
--default-username <DEFAULT_USERNAME>
The default username to use when no authentication is configured
[env: KMS_DEFAULT_USERNAME=]
[default: admin]
Authenticated Mode
When one or more authentication methods are enabled, the server requires successful authentication for all requests. The authentication mechanism works in a cascading fashion, attempting each configured method until one succeeds.
Available Authentication Methods
The KMS server supports three primary authentication methods:
- TLS Client Certificates: Authentication based on X.509 client certificates
- JWT Tokens: Authentication with OpenID-compliant JWT access tokens
- API Tokens: Authentication using a pre-shared API token
These methods can be used individually or in combination for enhanced security.
Authentication Flow
When multiple authentication methods are configured, the server follows this process:
- If TLS Client Certificate authentication is enabled and a valid certificate is presented, the user is authenticated
- If JWT authentication is enabled and a valid JWT token is presented, the user is authenticated
- If API Token authentication is enabled and a valid token is presented, the user is authenticated
- If all configured authentication methods fail, access is denied with a 401 Unauthorized response
A successful authentication at any step will grant access and subsequent authentication methods will be skipped.
Configuring Authentication Methods
TLS Client Certificate Authentication
To enable certificate-based authentication, the server must be started with TLS and a certificate authority (CA) for client verification:
# For FIPS mode (default build):
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms-fips:latest \
--tls-cert-file server.crt \
--tls-key-file server.key \
--clients-ca-cert-file client_ca.cert.pem
# For non-FIPS mode:
# docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest \
# --tls-p12-file kms.server.p12 \
# --tls-p12-password password \
# --clients-ca-cert-file client_ca.cert.pem
[tls]
# For FIPS mode (default build):
tls_cert_file = "server.crt"
tls_key_file = "server.key"
clients_ca_cert_file = "client_ca.cert.pem"
# For non-FIPS mode:
# tls_p12_file = "kms.server.p12"
# tls_p12_password = "password"
# clients_ca_cert_file = "client_ca.cert.pem"
The server extracts the username from the certificate's Subject Common Name (CN) field. Specifically, the Common Name of the client certificate subject is used directly as the username for authentication purposes. If the certificate is valid but does not contain a Common Name, authentication will fail.
Example of a subject with a CN field:
C=FR, ST=Ile-de-France, L=Paris, O=Cosmian Tech, CN=john.doe@example.com
In this example, john.doe@example.com would become the authenticated username.
Clients must present a valid certificate signed by the specified authority.
JWT Token Authentication
The server supports JWT tokens compatible with OpenID Connect. Configure JWT authentication with:
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest \
--jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,cosmian_kms"
[idp_auth]
# issuer,jwks[,aud1[,aud2...]] (jwks & audiences optional; any-of match when multiple)
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,cosmian_kms,another_client_id"]
The JWT authentication provider configuration uses the format: "JWT_ISSUER_URI,JWKS_URI,JWT_AUDIENCE_1,JWT_AUDIENCE_2,..." where:
- JWT_ISSUER_URI: The issuer URI of the JWT token (required)
- JWKS_URI: The JWKS (JSON Web Key Set) URI (optional, defaults to
<JWT_ISSUER_URI>/.well-known/jwks.json) - JWT_AUDIENCE_n: Zero or more allowed audiences (optional). If multiple are provided, validation succeeds if the token
audcontains any of them (any-of). If omitted, audience validation is skipped.
Examples:
"https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,my-audience""https://auth0.example.com,,my-app"(JWKS URI will default)"https://keycloak.example.com/auth/realms/myrealm,,"(no audience, JWKS URI will default)"https://issuer.example.com,https://issuer.example.com/jwks.json,frontend,cli"(multi-audience)
JWT tokens must be passed in the HTTP Authorization header:
Authorization: Bearer <JWT_TOKEN>
The server extracts the username from the token's email claim.
Supported Signing Algorithms
The KMS server automatically detects the signing algorithm from the JWT header (alg claim) and validates accordingly. The following signing algorithms from the jsonwebtoken library are supported; tokens using the none algorithm (for example, Algorithm::None / alg: "none") are explicitly rejected:
| Category | Algorithms |
|---|---|
| HMAC (symmetric) | HS256, HS384, HS512 |
| RSA PKCS#1 | RS256, RS384, RS512 |
| RSA-PSS | PS256, PS384, PS512 |
| ECDSA | ES256, ES384 |
| EdDSA | EdDSA (Ed25519) |
The algorithm is picked up from the token's alg header — no server-side configuration is required. The signing key must be published in the JWKS endpoint and matched by its kid claim.
PKCE Support
The KMS supports PKCE (Proof Key for Code Exchange) in two complementary ways:
- CLI / API clients (
ckmsand direct API usage): PKCE is used to obtain JWT tokens from the IDP. The client secret is optional — PKCE provides the security guarantee instead. - KMS Web UI: PKCE is mandatory. The browser login flow always sends
code_challenge_method=S256. The IDP application must be configured accordingly (see the PKCE Authentication guide for per-provider instructions).
For detailed information including required IDP settings, provider-specific examples, and troubleshooting, see the PKCE Authentication guide.
Multiple Identity Providers
To support multiple identity providers, repeat the JWT authentication provider parameter:
--jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,cosmian_kms,another_client_id" \
--jwt-auth-provider="https://login.microsoftonline.com/<TENANT_ID>/v2.0,https://login.microsoftonline.com/<TENANT_ID>/discovery/v2.0/keys,<CLIENT_ID>"
API Token Authentication
API Token authentication uses a symmetric key stored in the KMS as the authentication token:
-
Generate a symmetric key and note its ID:
ckms sym keys create -
Export the key in base64 format:
ckms sym keys export -k <SYMMETRIC_KEY_ID> -f base64 api_token.base64 -
Start the server with the API token ID:
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest \
--api-token-id <SYMMETRIC_KEY_ID>
[http]
api_token_id = "<SYMMETRIC_KEY_ID>"
-
Configure the client to use the API token:
Authorization: Bearer <BASE64_TOKEN>
When using API token authentication, the authenticated user will be the default username.
Force Default Username
If you want to enforce a consistent username regardless of the authentication method, use:
--force-default-username <true|false>
Force using the default username regardless of the authentication method
[env: KMS_FORCE_DEFAULT_USERNAME=]
[default: false]
When enabled, the server still performs the authentication validation to ensure the client has valid credentials, but it ignores the username that would normally be extracted (such as the certificate's Common Name or JWT email claim) and instead maps all authenticated requests to the default username.
This feature is particularly useful in scenarios where:
- You want consistent user identity across all requests regardless of authentication method
- You prefer to manage access control independently from the authentication credentials
- You're transitioning between authentication methods but need to maintain consistent audit trails
When force-default-username is enabled with multiple authentication methods, the server will still cascade through the authentication methods, but always use the default username upon successful authentication.
Multi-Factor Authentication Examples
Example 1: Client Certificate and JWT Authentication
# For FIPS mode (default build):
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms-fips:latest \
--tls-cert-file server.crt \
--tls-key-file server.key \
--clients-ca-cert-file client_ca.cert.pem \
--jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"
# For non-FIPS mode:
# docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest \
# --tls-p12-file kms.server.p12 \
# --tls-p12-password password \
# --clients-ca-cert-file client_ca.cert.pem \
# --jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"
[tls]
# For FIPS mode (default build):
tls_cert_file = "server.crt"
tls_key_file = "server.key"
clients_ca_cert_file = "client_ca.cert.pem"
# For non-FIPS mode:
# tls_p12_file = "kms.server.p12"
# tls_p12_password = "password"
# clients_ca_cert_file = "client_ca.cert.pem"
[idp_auth]
# Empty audience example: leave trailing comma after jwks URL
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"]
In this configuration:
- Clients can authenticate using either a valid client certificate or a valid JWT token
- If both are provided, the certificate is checked first
Example 2: JWT and API Token Authentication
docker run -p 9998:9998 --name kms ghcr.io/cosmian/kms:latest \
--jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs," \
--api-token-id <SYMMETRIC_KEY_ID>
[idp_auth]
jwt_auth_provider = ["https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"]
[http]
api_token_id = "<SYMMETRIC_KEY_ID>"
- Clients can authenticate using either a valid JWT token or the API token
- JWT authentication is attempted first, followed by API token verification
Common Identity Provider Configurations
Google ID Tokens
--jwt-auth-provider="https://accounts.google.com,https://www.googleapis.com/oauth2/v3/certs,"
Auth0
--jwt-auth-provider="https://<your-tenant>.<region>.auth0.com/,,"
Note: the trailing / is required in the issuer URI. The JWKS URI will default to the well-known endpoint.
Microsoft Entra ID (Azure AD)
--jwt-auth-provider="https://login.microsoftonline.com/<TENANT_ID>/v2.0,https://login.microsoftonline.com/<TENANT_ID>/discovery/v2.0/keys,<CLIENT_ID>"
Okta
--jwt-auth-provider="https://<OKTA_TENANT_NAME>.com,https://<OKTA_TENANT_NAME>.com/oauth2/v1/keys,<OKTA_CLIENT_ID>"
Using PKCE Authentication with KMS
This document covers PKCE (Proof Key for Code Exchange) authentication with the Eviden KMS, for two distinct contexts:
- CLI / API clients — the
ckmscommand-line tool and any direct API client uses PKCE to authenticate against the KMS server. Client secrets are optional in this flow. - KMS Web UI — the browser-based UI uses PKCE to log users in through an OIDC Identity Provider (IDP). PKCE is mandatory for the web UI flow and cannot be disabled.
Overview
PKCE enhances the security of OAuth 2.0 authentication flows by eliminating the need for client secrets. This makes it particularly valuable for:
- Public clients that cannot securely store client secrets
- Mobile applications
- Single-page applications
- Desktop applications
- CLI tools
Benefits of PKCE
- Improved Security: Eliminates the need to store and manage client secrets
- Simplified Deployment: Reduces configuration complexity for public clients
- Protection Against CSRF & Authorization Code Interception: The code verifier provides additional security
- Standards Compliance: Follows OAuth 2.0 and OpenID Connect standards
How PKCE Works
-
Authorization Request:
- Client generates a random code verifier and derives a SHA-256 code challenge from it
- Client requests authorization with the code challenge (
code_challenge_method=S256) - User authenticates and the IDP issues an authorization code
-
Token Exchange:
- Client sends the authorization code and the original code verifier to the token endpoint
- The IDP verifies that the code verifier matches the previously received challenge
- The IDP issues access and ID tokens upon successful verification
Web UI — Configuring Your Identity Provider
The KMS web UI login flow is a strict OIDC Authorization Code + PKCE flow. Every parameter listed below is hardcoded by the server; your IDP application must be configured to match them exactly.
Mandatory IDP Application Settings
| Requirement | Value the KMS sends | What to configure in the IDP |
|---|---|---|
| Grant type | grant_type=authorization_code | Enable the Authorization Code grant on the IDP application |
| Token endpoint auth method | Client credentials are sent as form body fields (client_id + optional client_secret) | Set the token endpoint authentication method to client_secret_post — not client_secret_basic (HTTP Basic), which is the default in many IDPs |
| PKCE | code_challenge_method=S256 with a 32-byte random verifier | Enable PKCE on the application; S256 must be supported (plain is not accepted) |
| Response type | response_type=code | Ensure the Authorization Code response type is allowed |
| Scopes | scope=openid email | Allow both openid and email scopes; the email claim must be included in the returned ID token — without it the KMS cannot identify the user |
Audience (aud) claim | Validated against the configured client_id (exact match) | The ID token's aud claim must exactly equal the client_id string. Some IDPs (e.g. Keycloak) add extra audience values or service-account names by default — disable this or add an audience mapper that restricts aud to the client_id only |
| Redirect URI | <KMS_PUBLIC_URL>/ui/callback | Register this exact URI as an allowed redirect/callback URI in the IDP application |
Client Secret
The client secret is optional. If configured, it is sent as a client_secret form field alongside the other token exchange parameters (client_secret_post method). If your IDP requires a client secret, set it via:
[oidc]
ui_oidc_client_secret = "your-secret-here"
Provider-Specific Notes
Auth0
- In the Auth0 dashboard, set Token Endpoint Authentication Method to
POST(this corresponds toclient_secret_post). - Enable PKCE on the application (Applications → Settings → Advanced → Grant Types → tick Authorization Code).
- Under Advanced Settings → OAuth, set OIDC Conformant to ON.
- The
audclaim in Auth0 ID tokens equals theclient_idby default — no extra configuration needed.
Microsoft Entra ID (Azure AD)
- Register a Single-Page Application (SPA) or Web application. Entra ID enables PKCE automatically for SPA registrations.
- The
audclaim in Entra ID ID tokens equals the Application (client) ID — this matches the KMS expectation. - Entra ID uses
client_secret_postby default for web applications that have a secret; for SPA applications no secret is used. - Required scopes:
openid,email(orprofileifemailis provided via Microsoft Graph).
Keycloak
- In Client Settings, set Access Type to confidential (if using a secret) or public (secret-less).
- Standard Flow Enabled: ON.
- Proof Key for Code Exchange Code Challenge Method: S256.
- Client Authentication → set Client Authenticator to Client Id and Secret and Token Endpoint Auth Method to POST (
client_secret_post). - Audience: by default Keycloak may add the Keycloak-internal service account to the
audclaim. Add a Hardcoded audience mapper (or Audience resolve mapper restricted to the client ID) to ensureaudcontains only theclient_id.
- Google's OAuth2 endpoints officially support PKCE but still require a client secret.
- The ID token's
audequals the OAuth2 client ID. - Required scopes:
openid,email.
CLI / API Client — PKCE with Optional Client Secret
The KMS CLI (ckms) and API clients use PKCE to authenticate against the KMS server. The client secret is optional in this flow.
Example: Entra ID
-
CLI configuration
[http_config.oauth2_conf] client_id = "f052524e-7518-40e7-2579-219c0b48b125" authorize_url = "https://login.microsoftonline.com/612da4de-35c0-42de-ba56-174c4e562c96/oauth2/authorize" token_url = "https://login.microsoftonline.com/612da4de-35c0-42de-f3c6-174b69062c96/oauth2/token" scopes = [ "email", "openid", ] # client_secret = <-- Not Set -
KMS Server Configuration
Important: on Entra ID, configure the redirect URL (
http://localhost:17899/authorization) as Native/Desktop (not Single Page Application).[idp_auth] # issuer,jwks,audience (audience omitted) jwt_auth_provider = ["https://login.microsoftonline.com/612da4de-35c0-42de-f3c6-174b69062c96/v2.0,https://login.microsoftonline.com/612da4de-35c0-42de-f3c6-174b69062c96/discovery/v2.0/keys,"]
Example: Auth0
-
CLI configuration
[http_config.oauth2_conf] client_id = "OUfH4FuzDAW99Ck3R4Rb7ROziOZEalIH" authorize_url = "https://acme.eu.auth0.com/authorize" token_url = "https://acme.eu.auth0.com/oauth/token" scopes = [ "email", "openid", ] # client_secret = <-- Not SetNote: Google's IdP officially supports PKCE but still requires a client secret.
-
KMS Server Configuration
[idp_auth] jwt_auth_provider = ["https://acme.eu.auth0.com/,https://acme.eu.auth0.com/.well-known/jwks.json,"]
The client handles:
- Code challenge generation using SHA-256
- Automatic inclusion of PKCE parameters in authorization requests
- Code verifier inclusion during token exchange
Server-Side Handling
The KMS server validates JWT tokens using JWKS (JSON Web Key Sets), which is compatible with PKCE-obtained tokens. The server:
- Extracts the JWT token from the
Authorization: Bearerheader - Validates the token's signature using the JWKS endpoint
- Verifies the token's claims (issuer, audience, expiration, etc.)
- Extracts the user's identity from the
emailclaim
Transitioning from Client Secret to PKCE
- Update your client code to use the PKCE-enabled client library
- Configure your identity provider to support PKCE (see provider notes above)
- Remove client secrets from your configuration (CLI flow only — the web UI always uses
client_secret_postif a secret is present)
The server-side JWT validation remains unchanged.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Token exchange returns 401 | IDP requires client_secret_basic but the KMS sends client_secret_post — change the IDP application's token endpoint auth method |
Token validation failed: InvalidAudience | The ID token aud does not exactly match client_id — see the Keycloak or provider-specific notes above |
Missing email claim / user ID is empty | The IDP application does not include email in the ID token — enable the email scope and/or add an email claim mapper |
| IDP rejects the authorization request | The IDP application does not support response_type=code or PKCE with code_challenge_method=S256 — enable these in the IDP application settings |
Missing PKCE verifier on callback | The browser session was lost (e.g. the session cookie expired or the server restarted between login and callback) |
References
The authorization system in the Eviden Key Management Service (KMS) operates based on two fundamental principles:
-
Ownership: Every cryptographic object has an assigned owner. The ownership is established when an object is created using any of the following KMIP operations:
Create,CreateKeyPair, orImport. As an owner, a user holds the privilege to carry out all supported KMIP operations on their objects. -
Access rights delegation: owners can grant access rights, allowing one or more users to perform certain KMIP operations on an object. When granted such rights, a user can invoke the corresponding KMIP operation on the KMS for that particular object. The owner retains the authority to withdraw these access rights at any given time.
Delegable KMIP operations
Owners can delegate the following KMIP operations to other users via the grant and revoke endpoints (or the CLI commands ckms access-rights grant / ckms access-rights revoke):
| Operation | Description |
|---|---|
create | Create new cryptographic objects (symmetric keys, key pairs, …) |
certify | Issue or renew X.509 certificates |
decrypt | Decrypt ciphertext using a managed key |
derive_key | Derive a new key from an existing key |
destroy | Permanently destroy an object |
encrypt | Encrypt plaintext using a managed key |
export | Export an object (key material + metadata) from the KMS |
get | Retrieve an object — this is a super-privilege (see below) |
get_attributes | Read the KMIP attributes of an object |
hash | Compute a cryptographic hash |
import | Import an external object into the KMS |
locate | Search for objects matching given attributes |
mac | Compute a Message Authentication Code |
revoke | Revoke (deactivate) an object |
rekey | Re-key an existing symmetric key |
sign | Generate a digital signature |
signature_verify | Verify a digital signature |
validate | Validate a certificate chain |
set_attribute | Set (replace) an attribute on an object |
modify_attribute | Modify an existing attribute on an object |
add_attribute | Add a new attribute value to an object |
delete_attribute | Remove an attribute from an object |
Multiple operations can be granted or revoked in a single call. For example, using the CLI:
# Grant encrypt and decrypt to user "alice"
ckms access-rights grant alice -i <object-uid> encrypt decrypt
# Revoke the get privilege from user "bob"
ckms access-rights revoke bob -i <object-uid> get
The Get super-privilege
The Get operation has a special role in the permission model: it acts as a super-privilege that implies every other
object-level operation.
When checking whether a user is authorized to perform a given operation on an object, the KMS evaluates the following rules in order:
- Owner check — if the requesting user is the owner of the object, access is always granted.
- Explicit permission — if the user has been explicitly granted the requested operation (e.g.
encrypt), access is granted. Getfallback — if the user holds theGetpermission on the object, access is granted regardless of the specific operation requested.
In other words, granting Get to a user on an object is equivalent to granting that user encrypt, decrypt,
export, sign, derive_key, and every other object-level operation — except lifecycle operations (revoke,
destroy) which still require their own explicit grant.
This design allows owners to share full read/use access to an object with a single permission, without individually enumerating every operation.
!!! warning Security implication
Because Get implies all other operation-level permissions, it should be granted with care.
If you only need a user to encrypt data with a key, grant encrypt — not get.
Practical example
| Granted permissions | Can the user encrypt? | Can the user export? | Can the user destroy? |
|---|---|---|---|
encrypt | Yes | No | No |
get | Yes | Yes | No |
encrypt, destroy | Yes | No | Yes |
get, destroy | Yes | Yes | Yes |
The destroy and revoke operations are never implied by get. They must always be granted explicitly
because they are irreversible lifecycle transitions.
Special handling of the Create permission
The Create operation is not bound to a specific object — it controls whether a user is allowed to create new objects
in the KMS. Internally it is stored against the wildcard object identifier *.
- When granting or revoking
create, no object UID is required. Createcan be combined with object-level operations in the same request; the server will separate and process them accordingly.
Privileged users
By default, all users are allowed to create or import objects in the KMS.
However, when the KMS server is configured with a list of privileged users, object creation rights are restricted as follows:
- Privileged users can create or import objects and are authorized to grant or revoke object creation permissions for other users.
- Regular users cannot create or import objects unless they have explicitly been granted permission by a privileged user.
- Regular users cannot grant or revoke creation permissions for others.
- Privileged users cannot revoke object creation permissions from other privileged users.
Operations gated by the privileged-user restriction
Because the following operations all result in a new cryptographic object being created in the KMS, they are all subject to the same privileged-user check:
| Operation | Reason |
|---|---|
Create | Creates a new symmetric key or secret data object |
CreateKeyPair | Creates a new asymmetric key pair |
Import | Imports an external object into the KMS |
Register | Registers an externally-generated object |
Certify | May create a new key pair when issuing a certificate |
ReKey | Creates a new replacement symmetric key |
ReKeyKeyPair | Creates a new replacement asymmetric key pair |
ReKey and ReKeyKeyPair also require the caller to hold the Rekey permission on the existing key being
re-keyed. Both conditions must be satisfied: the user must be allowed to create new objects and be allowed
to rekey the specific existing key.
The wildcard user *
In addition to regular users, a special user called * (the wildcard user) can be used to grant access rights on
objects to all users. When a permission is granted to *, every authenticated user benefits from that permission
on the targeted object. Individual per-user grants are merged with the wildcard grants when evaluating access.
HSM keys and authorization
Keys stored in an HSM follow a stricter permission model than regular KMS keys. Authorization metadata (owner, grants) is still managed by the KMS, but two important differences apply.
Comparison with regular KMS keys
| Aspect | KMS keys | HSM keys |
|---|---|---|
| Key material stored in | KMS database (encrypted) | HSM hardware |
Get is a super-privilege | Yes — implies all operations | No — each operation must be granted explicitly |
Get ↔ Export equivalence | No | Yes — holding either grants both |
Destroy / Revoke delegable | Yes | No — blocked; admin-only |
Create | Any user (or privileged users if configured) | HSM admin only |
Locate visibility | All owned / granted objects | Non-admins see only keys with ≥ 1 explicit grant |
Who is an HSM admin?
Users listed in the server's hsm_admin configuration for a given HSM instance are
its admins. Admins bypass all permission checks for that HSM — they can create,
destroy, and perform any operation on its keys.
Permission evaluation for HSM keys
Request arrives for operation OP on key hsm::<model>::<slot>::<id>
│
├─ Is the user an HSM admin for this instance? ──▶ YES → Granted
│
├─ Does the user have OP explicitly granted? ──────▶ YES → Granted
│
├─ Is OP = Export and user has Get? ───────────────▶ YES → Granted
├─ Is OP = Get and user has Export? ─────────────▶ YES → Granted
│
└─ Otherwise ──────────────────────────────────────────────▶ Denied
What can and cannot be delegated
| Operation | Delegable via grant? | Notes |
|---|---|---|
encrypt, decrypt, sign, mac | Yes | All standard cryptographic operations |
get | Yes | Also implies export (equivalence) |
export | Yes | Also implies get (equivalence) |
get_attributes, locate | Yes | |
set_attribute, modify_attribute, add_attribute, delete_attribute | Yes | Operate on KMS metadata only; do not access HSM hardware |
create | Yes (admin to another admin) | Non-admin cannot receive create on HSM |
destroy | No | Blocked — admin-only, cannot be delegated |
revoke | No | Blocked — HSM objects do not use KMIP lifecycle states |
Unlike regular KMS keys, granting Get on an HSM key does not imply encrypt,
decrypt, sign, or any other operation. Each operation must be granted
individually.
See the HSM operations page for HSM admin configuration details.
Authentication vs. authorization
It is important to distinguish authentication from authorization:
- Authentication determines who the user is. The KMS supports TLS client certificates, JWT tokens, and API tokens. See the Authentication page for details on how to configure these methods and how user identities are established.
- Authorization determines what an authenticated user is allowed to do with a given cryptographic object. This is the permission model described on this page.
An API token (used for authentication) is not the same thing as a symmetric key stored in the KMS. The API token proves the user's identity; the symmetric key is a cryptographic object the user may or may not have permission to use.
Typical workflow: per-user keys with limited permissions
The kms.toml configuration file controls server-level settings only (authentication methods, database backend,
TLS, privileged users, etc.). It does not contain any user-to-key permission mapping.
Per-object access rights are managed dynamically at runtime through the REST API (/access/grant, /access/revoke)
or the CLI (ckms access-rights grant / ckms access-rights revoke).
The only authorization-related setting in kms.toml is privileged_users, which restricts who can create or import
new objects (see Privileged users above).
A common deployment pattern is to have an administrator create one symmetric key per user and grant only the
operations each user needs (e.g. encrypt and decrypt).
Step 1 — Create the key (as admin/owner)
# The admin creates a 256-bit AES key and tags it for easy lookup
ckms sym keys create --algorithm aes --number-of-bits 256 --tag user-alice-key
The command returns the key's unique identifier, for example a]b2c3d4-....
Step 2 — Grant limited permissions
# Grant only encrypt and decrypt to alice (identified by her authenticated username)
ckms access-rights grant alice@example.com -i a]b2c3d4-... encrypt decrypt
Alice can now encrypt and decrypt using this key, but she cannot export it, destroy it, or perform any other operation on it.
Step 3 — Alice uses the key
Alice authenticates to the KMS (via her client certificate, JWT token, or API token) and calls the encrypt/decrypt
endpoints referencing the key UID. The server verifies she holds the encrypt / decrypt permission before
proceeding.
Step 4 — Revoke access (if needed)
ckms access-rights revoke alice@example.com -i a]b2c3d4-... encrypt decrypt
Do not grant get if you only want to allow encrypt/decrypt — get is a super-privilege that implies all
object-level operations (see above).
Access management endpoints
The KMS exposes the following REST endpoints to manage access rights:
| Method | Endpoint | Description |
|---|---|---|
| POST | /access/grant | Grant operations on an object to a user |
| POST | /access/revoke | Revoke operations on an object from a user |
| GET | /access/list/{object_id} | List all access rights granted on an object (owner only) |
| GET | /access/owned | List all objects owned by the authenticated user |
| GET | /access/obtained | List all access rights obtained by the authenticated user |
| GET | /access/create | Check whether the authenticated user can create objects |
| GET | /access/privileged | Check whether the authenticated user is privileged |
Authorization rules summary
| Scenario | Access granted? |
|---|---|
| User is the object owner | Always |
| User has the exact requested operation granted | Yes |
User has Get granted (any operation except lifecycle) | Yes |
| User has no matching permission | Denied |
| User tries to grant/revoke their own permissions | Denied |
| Non-owner tries to grant permissions | Denied |
The KMS activates two internal listeners: a socket server and an HTTP server.
The socket server listens to KMIP binary requests on the IANA-registered 5696 port. The socket server will only start if the TLS configuration is provided and client certificate authentication is enabled.
The HTTP server listens to KMIP requests on the /kmip and /kmip/2_1 endpoints.
It also serves the web UI on the /ui endpoint.
The HTTP server is always started, even if the TLS configuration is not provided.
The KMS server should be started using HTTPS when running in a zero-trust environment. Check the running in a zero-trust environment section for more information.
To enable TLS, one can provide certificates on the command line interface.
Providing certificates
The KMS server supports two certificate formats depending on the build variant:
FIPS mode (default build): Requires PEM-formatted certificates and keys.
- Server certificate in PEM format (may include full chain)
- Private key in PEM format (PKCS#8 or traditional format)
- Optional separate chain file for intermediate CAs
Non-FIPS mode: Supports PKCS#12 format.
- Key and full certificate chain in PKCS#12 format
- Password to open the PKCS#12 file
When enabling client certificate authentication, the server's authority X509 certificate in PEM format must also be provided (for both modes). Multiple CA certificates can be concatenated in a single PEM file to support different certificate authorities.
Configuration using the TOML configuration file
Certificate information must be provided in the [tls] section of the TOML configuration file.
For FIPS mode (default build):
# TLS configuration of the Socket server and HTTP server
[tls]
# The server's X.509 certificate in PEM format.
# Provide a PEM containing the server leaf certificate,
# optionally followed by intermediate certificates (full chain).
tls_cert_file = "path/to/server.crt"
# The server's private key in PEM format (PKCS#8 or traditional format).
tls_key_file = "path/to/server.key"
# Optional certificate chain in PEM format (intermediate CAs).
# If not provided, the chain may be appended to tls_cert_file instead.
tls_chain_file = "path/to/chain.pem"
For non-FIPS mode:
# TLS configuration of the Socket server and HTTP server
[tls]
# The KMS server's optional PKCS#12 Certificates and Key file.
# If provided, this will start the server in HTTPS mode.
tls_p12_file = "path/to/server.p12"
# The password to open the PKCS#12 Certificates and Key file.
tls_p12_password = "your_password"
# The server's optional authority X509 certificate in PEM format
# used to validate the client certificate presented for authentication.
# If provided, clients must present a certificate signed by this authority for authentication.
# The server must run in TLS mode for this to be used.
# Multiple CA certificates can be concatenated in a single PEM file.
clients_ca_cert_file = "[authority cert file]"
# Optional colon-separated list of TLS cipher suites to enable.
# If not specified, OpenSSL default cipher suites will be used.
# Example: "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"
# ANSSI-recommended cipher suites:
# - For TLS 1.3 (preferred): TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256
# - For TLS 1.2 (compatibility): TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
tls_cipher_suites = "[cipher suites]"
Configuring using the command line
Certificate information can be provided using the command line interface.
# The KMS server's optional PKCS#12 Certificates and Key file.
# If provided, this will start the server in HTTPS mode.
--tls-p12-file "[tls p12 file]"
# The password to open the PKCS#12 Certificates and Key file.
--tls-p12-password "[tls p12 password]"
# The server's optional authority X509 certificate in PEM format
# used to validate the client certificate presented for authentication.
# If provided, clients must present a certificate signed by this authority for authentication.
# The server must run in TLS mode for this to be used.
# Multiple CA certificates can be concatenated in a single PEM file.
--clients-ca-cert-file "[authority cert file]"
# Optional colon-separated list of TLS cipher suites to enable.
# If not specified, OpenSSL default cipher suites will be used.
# Example: "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"
--tls-cipher-suites "[cipher suites]"
!!!info "Generate a PKCS#12 from PEM files"
To generate a PKCS12 from PEM files, you can use openssl:
openssl pkcs12 -export \
-in server.mydomain.com.fullchain.pem \
-inkey server.mydomain.com.privkey.pem \
-out server.mydomain.com.p12
Advanced TLS Configuration
TLS Protocol Versions
By default, the KMS server accepts both TLS 1.2 and TLS 1.3 connections.
Internally it uses the OpenSSL mozilla_intermediate_v5 profile, which sets TLS 1.2 as
the minimum protocol version and TLS 1.3 as the maximum.
The active protocol version range is automatically derived from the cipher suites you configure (see TLS Cipher Suites Selection below):
--tls-cipher-suites value | minimum TLS version | maximum TLS version |
|---|---|---|
| (not set — default) | TLS 1.2 | TLS 1.3 |
| Only TLS 1.3 suites | TLS 1.3 | TLS 1.3 |
| Only TLS 1.2 suites | TLS 1.2 | TLS 1.3 |
| Mixed TLS 1.2 + TLS 1.3 suites | TLS 1.2 | TLS 1.3 |
Enforce TLS 1.3 only — specify at least one TLS 1.3 cipher suite and no TLS 1.2 suites:
--tls-cipher-suites "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"
Keep TLS 1.2 compatibility — either leave --tls-cipher-suites unset (default), or include
at least one TLS 1.2 cipher suite:
--tls-cipher-suites "TLS_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
!!!warning "TLS 1.2 security considerations" TLS 1.2 is still considered secure when used with AEAD cipher suites (GCM/ChaCha20), but TLS 1.3 is preferred. Avoid enabling TLS 1.2 unless required for legacy client compatibility.
TLS Cipher Suites Selection
The KMS server supports custom TLS cipher suite configuration to meet specific security requirements. You can specify which cipher suites to enable using a colon-separated list.
The cipher suites are automatically categorized into TLS 1.3 and TLS 1.2 suites:
- TLS 1.3 cipher suites (preferred):
TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_CCM_SHA256,TLS_AES_128_CCM_8_SHA256 - TLS 1.2 cipher suites (for compatibility):
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
If only TLS 1.3 cipher suites are specified, the server will enforce TLS 1.3 minimum protocol version. If only TLS 1.2 cipher suites are specified, the server will support TLS 1.2 and above.
Example configurations:
# ANSSI-recommended TLS 1.3 only configuration
--tls-cipher-suites "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256"
# Mixed TLS 1.2/1.3 configuration for compatibility
--tls-cipher-suites "TLS_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
Multiple Certificate Authorities
The KMS server supports multiple certificate authorities for client certificate validation. You can concatenate multiple CA certificates in PEM format into a single file.
Example of multiple CA certificates in one file:
-----BEGIN CERTIFICATE-----
[First CA Certificate]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[Second CA Certificate]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[Third CA Certificate]
-----END CERTIFICATE-----
This allows clients with certificates issued by any of the specified CAs to authenticate successfully. The server will validate client certificates against all provided CA certificates.
Telemetry & Observability
By default, the Eviden KMS server outputs logs to the console with a log level of INFO.
Beyond console logging, the server supports OpenTelemetry (OTLP) export, which unlocks a full
observability stack: distributed traces, RED metrics, and long-term dashboards via Grafana.
Log call-site directory
For a full listing of every log call-site across all components — grouped by domain
(KMS server, CLI, PKCS#11 provider, CNG module), with per-level counts and the
RUST_LOG filter name for each crate — see the
Log Call-Site Directory.
Adjusting the log level
The log level can be adjusted by setting either:
- the
RUST_LOGenvironment variable, - the
rust_logsetting in the TOML configuration file in the[logging]section, - the
--rust-logcommand line argument.
Available levels: trace, debug, info, warn, error. The default is info.
Example:
RUST_LOG=info,cosmian=info,cosmian_kms_server=info,actix_web=info,mysql=info
The first info sets the default log level for all crates. Individual crates can be overridden:
- To get detailed logs of user requests, set
cosmian_kms_servertodebug:
RUST_LOG=info,cosmian=info,cosmian_kms_server=debug,actix_web=info,mysql=info
- To debug HTTP issues, set
actix_webtodebug:
RUST_LOG=info,cosmian=info,cosmian_kms_server=info,actix_web=debug,mysql=info
⚠️ WARNING: Setting the log level to
debugortracemay leak sensitive information in the logs.
Console and syslog logging
Logging to the console is enabled by default. It can be disabled via:
- the
quietparameter in the TOML configuration file in the[logging]section, - the
--quietcommand line argument, - the
KMS_LOG_QUIETenvironment variable set totrue.
On Linux, logs can be redirected to syslog instead of stdout by setting:
- the
log_to_syslogparameter in the TOML configuration file in the[logging]section, - the
--log-to-syslogcommand line argument, - the
KMS_LOG_TO_SYSLOGenvironment variable set totrue.
Rolling log files
The server can write daily rolling log files. File logging is disabled unless
rolling_log_dir is explicitly configured (via --rolling-log-dir, the
KMS_ROLLING_LOG_DIR environment variable, or the TOML configuration).
Log files are named <name>.YYYY-MM-DD, where <name> defaults to kms.
When rolling_log_dir is set without specifying a path (e.g. via the
configuration wizard), the recommended platform-specific defaults are:
| Platform | Default directory |
|---|---|
| Linux | /var/log/ |
| Windows | C:\Users\<username>\AppData\Local\Cosmian KMS Server |
| macOS | ~/Library/Logs/ |
Warning (Windows): The server does not expand Windows environment variables such as
%LOCALAPPDATA%in configuration files. If you overriderolling_log_dirinkms.toml, you must use the fully-expanded path, for example:rolling_log_dir = "C:\\Users\\<username>\\AppData\\Local\\Cosmian KMS Server"When
rolling_log_diris not set, the server resolves theLOCALAPPDATAenvironment variable at runtime and defaults toC:\Users\<username>\AppData\Local\Cosmian KMS Server. When running as a Windows service under LocalSystem, the variable may not be set; the server then falls back toC:\ProgramData\Cosmian KMS Server.Note (macOS): The server defaults to
~/Library/Logs/which is the standard per-user log directory on macOS and is writable without root. If you run the server as a LaunchDaemon (root), you may override this with--rolling-log-dir /Library/Logs/.Graceful fallback: If the configured rolling log directory does not exist and cannot be created, or is not writable by the current process, the server disables file logging with a warning message on stderr and continues operating normally. This prevents the server from panicking due to inaccessible log paths.
The directory and file name can be overridden via:
- the
rolling_log_dir/rolling_log_nameentries in the TOML configuration file ([logging]section), - the
--rolling-log-dir/--rolling-log-namecommand line arguments, - the
KMS_ROLLING_LOG_DIR/KMS_ROLLING_LOG_NAMEenvironment variables.
OTLP telemetry
The KMS server can export traces and metering events to any OpenTelemetry collector that supports the OTLP protocol.
To enable OTLP export, set one of:
- the
otlpparameter in the TOML configuration file in the[logging]section, - the
--otlpcommand line argument, - the
KMS_OTLP_URLenvironment variable.
KMS_OTLP_URL="http://localhost:4317"
What the traces contain
Traces produced by the KMS include:
- The start configuration of the KMS server
- KMIP requests (content adjusted by the log level)
- Access rights management requests
- Metering events (when
--enable-meteringis active)
Enabling metering
Metering events are emitted as OTLP spans and converted to Prometheus metrics downstream. Enable the feature with:
- the
--enable-meteringcommand line argument, - or the equivalent TOML key in the
[logging]section.
For the full list of emitted metrics, their types, and label sets, see the Metrics reference.
Observability stack (OTel Collector + VictoriaMetrics + Grafana)
For production-grade observability, a pre-configured Docker Compose stack is provided. It replaces the Jaeger quick-test setup with a persistent metrics pipeline and Grafana dashboards.
Architecture
KMS ──OTLP gRPC──► OTel Collector ──remote_write──► VictoriaMetrics ◄── Grafana
│
└──prometheus scrape :8888──► VictoriaMetrics
| Component | Role |
|---|---|
| OTel Collector | Receives OTLP, enriches with metadata, generates RED metrics from traces, exports to VictoriaMetrics |
| VictoriaMetrics | Long-term metrics storage (configurable retention) |
| Grafana | Dashboard UI — queries VictoriaMetrics via PromQL |
Quick start
The stack is configured via a single .env file. Two deployment modes are available:
Mode kms-local — KMS container included in the stack:
# .env
COMPOSE_PROFILES=kms-local
KMS_MODE=local
# Generate a demo TLS certificate (RSA 4096, self-signed, 10 years)
bash generate-demo-cert.sh
# Start everything
docker compose up -d
Mode external — existing KMS, stack only:
# .env
COMPOSE_PROFILES=
KMS_MODE=external
docker compose up -d
In external mode, configure your KMS to send OTLP data to the collector:
# gRPC (recommended)
KMS_OTLP_URL=http://<collector-host>:4317
# or HTTP
KMS_OTLP_URL=http://<collector-host>:4318
.env reference
| Variable | Default | Description |
|---|---|---|
COMPOSE_PROFILES | kms-local | kms-local to include the KMS container, empty for external mode |
KMS_MODE | local | local or external — propagated as label in all metrics/traces |
KMS_CLUSTER | cosmian-kms-local | Logical cluster name — kms.cluster label in dashboards |
KMS_VERSION | latest | Docker image tag for the KMS |
ENVIRONMENT | production | Deployment environment (production, staging, …) |
GRAFANA_ADMIN_PASSWORD | password | Grafana admin user password |
METRICS_RETENTION_MONTHS | 12 | VictoriaMetrics retention period (months) |
OTel Collector pipeline
The collector enriches every span and metric with the following resource attributes:
| Attribute | Source |
|---|---|
deployment.environment | ENVIRONMENT from .env |
service.name | hardcoded cosmian-kms |
service.version | KMS_VERSION from .env |
kms.mode | KMS_MODE from .env |
kms.cluster | KMS_CLUSTER from .env |
kms.node | host.name of the KMS container |
RED metrics from traces are automatically generated by the spanmetrics connector with the
following latency buckets: 10ms, 50ms, 100ms, 250ms, 500ms, 1s, 2s, 5s, 10s, 30s.
Exposed ports
| Service | Port | Protocol | Usage |
|---|---|---|---|
| KMS | 9998 | HTTPS | KMS API (local mode only) |
| OTel Collector | 4317 | gRPC | OTLP traces & metrics ingestion |
| OTel Collector | 4318 | HTTP | OTLP traces & metrics ingestion |
| OTel Collector | 8888 | HTTP | Collector self-metrics (Prometheus) |
| OTel Collector | 13133 | HTTP | Health check |
| VictoriaMetrics | 8428 | HTTP | PromQL API + remote_write endpoint |
| Grafana | 3000 | HTTP | Dashboard UI |
Access Grafana at http://localhost:3000 with user admin.
Quick test with Jaeger
To quickly validate that OTLP export works without the full stack:
docker run -p 16686:16686 -p 4317:4317 \
-e COLLECTOR_OTLP_ENABLED=true \
jaegertracing/all-in-one:latest
[logging]
otlp = "http://localhost:4317"
quiet = true
Then start the KMS locally:
./cosmian_kms_server --otlp http://localhost:4317 --quiet
Open http://localhost:16686 to browse traces in the Jaeger UI.
For production use, replace Jaeger with the full OTel Collector + VictoriaMetrics + Grafana stack described above.
Log Call-Site Directory
This page lists every production log call-site across all Cosmian KMS components, grouped by domain and crate.
It is not listed in the navigation menu but is accessible via It is not listed in the navigation menu but is accessible via Logging and telemetry.
How to read this page
The index is organised by usage-domains. Within each domain, each table covers one crate (the UI section is an exception). All tables, ui included, have 5 columns:
| Column | Meaning |
|---|---|
| Level | error warn info debug trace |
| Message | Constant log string; interpolated values shown as {name} |
| File | Source file relative to the crate root |
| Variables | Each {name} — description; — when none |
| Notes | Reserved for security flags and operator guidance |
Rows are ordered by severity (error → warn → info → debug → trace), then
alphabetically by message. Test files are excluded.
Tip: The level filter defaults to
error. Switching toallortracereveals hundreds of rows and the page will become long.
Domain: KMS Server
cosmian_kms_server
Crate path: crate/server
RUST_LOG target: cosmian_kms_server
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
error | Authentication method configured, but no authentication provided | src/middlewares/ensure_auth.rs | - | Returns 401. Check middleware stack - auth is configured but no bearer/cert/API-token was sent. |
error | AWS XKS Sigv4 middleware should not be enabled if the aws_xks_params are not set | src/routes/aws_xks/sigv4_middleware.rs | - | Server misconfiguration - enable XKS routes only when aws_xks_params is set. |
error | Error handling socket client: {} | src/socket_server.rs | - | Unix socket handler crashed. The server continues running. |
error | Failed to open index.html: {e:?} | src/start_kms_server.rs | e: caught error | UI not served - verify ui_index_html_folder points to a built UI artifact. |
error | Socket server failed to acquire write lock for stop request: {} | src/socket_server.rs | - | Internal threading issue on shutdown. Server may need SIGTERM if it hangs. |
error | Socket server failed to connect to itself: {} | src/socket_server.rs | - | Internal stop-signal socket unreachable. Port may be in use by another process. |
error | Socket server failed to get local address for stop signal | src/socket_server.rs | - | Network/IPC failure. Check connectivity and port availability. |
error | Socket server failed to write stop request | src/socket_server.rs | - | Network/IPC failure. Check connectivity and port availability. |
error | Socket server stop signal contained error: {} | src/socket_server.rs | - | Stop channel returned an error. Inspect the formatted error value. |
error | Windows service failed: {e} | src/windows_service.rs | e: caught error | Fatal Windows service error. Check Windows Event Log for the full stack trace. |
error | {:?} {} 401 unauthorized: Client and server authentication tokens mismatch | src/middlewares/api_token/api_token_auth.rs | - | API token mismatch - rotate the kms_api_token_id / kms_api_token config values. |
error | {status_code} - {message} | src/routes/mod.rs | status_code: HTTP status codemessage: human-readable message text | Unhandled HTTP error response emitted to the client. |
error | {} | src/start_kms_server.rs | - | Catch-all error log. Inspect the formatted value for the actual error. |
warn | Activate: object {} is already Active, rejecting | src/core/operations/activate.rs | - | - |
warn | AWS XKS create: key {uid} already exists (ignoring creation). | src/routes/aws_xks/key_metadata.rs | uid: KMIP object UID | - |
warn | Azure EKM client authentication is disabled, this should only be done in tests, and won't work for production environments. | src/start_kms_server.rs | - | - |
warn | Could not insert: certificate: AKI: {}, SKI: {} | src/core/operations/validate.rs | - | - |
warn | Failed to persist auto-activation of object {}: {} | src/core/retrieve_object_utils.rs | - | - |
warn | Fetch JWKS: {e} | src/middlewares/jwt/jwks.rs | e: caught error | - |
warn | SigV4 failure: {signature_error} | src/routes/aws_xks/sigv4_middleware.rs | signature_error: SigV4 signature validation error | - |
warn | Socket server: connection failed: {e} | src/socket_server.rs | e: caught error | - |
warn | UI folder invalid or Linux default detected, falling back to: {fallback:#?} | src/config/params/server_params.rs | fallback: fallback UI folder path | - |
warn | {:?} {} 401 unauthorized, no email in JWT | src/middlewares/jwt/jwt_token_auth.rs | - | - |
warn | {:?} {} 401 unauthorized: bad JWT | src/middlewares/jwt/jwt_token_auth.rs | - | - |
warn | {error:?} | src/middlewares/jwt/jwt_token_auth.rs | error: error detail | - |
warn | {status_code} - {message} | src/routes/mod.rs | status_code: HTTP status codemessage: human-readable message text | - |
warn | {status} - {} | src/routes/jose/error.rs | status: HTTP response status | - |
info | AUTHENTICATION token: {:?} | src/routes/google_cse/jwt.rs | - | - |
info | AUTHORIZATION token headers: {:?} | src/routes/google_cse/jwt.rs | - | - |
info | AUTHORIZATION token: {:?} | src/routes/google_cse/jwt.rs | - | - |
info | azure EKM API enabled at {} | src/start_kms_server.rs | - | - |
info | Command line / file config: {clap_config:#?} | src/main.rs | clap_config: parsed CLI configuration | - |
info | Created Key Pair with cryptographic algorithm {:?} | src/core/operations/create_key_pair.rs | - | - |
info | Created Object of type {:?} | src/core/operations/create.rs | - | - |
info | Creating key pair for certification - private key: {sk_uid}, public key: {pk_uid} | src/core/operations/certify/resolve_subject.rs | sk_uid: private key UIDpk_uid: public key UID | - |
info | Destroyed object | src/core/operations/destroy.rs | - | - |
info | Encrypted Data : {encrypted_data:?} | src/routes/ms_dke/mod.rs | encrypted_data: encrypted data payload | - |
info | Exported object of type: {} | src/core/operations/export_get.rs | - | - |
info | Extracted IDP Configs: {:#?} | src/config/command_line/idp_auth_config.rs | - | - |
info | Feature Test enabled | src/main.rs | - | - |
info | Found Google CSE migration key, importing it. | src/start_kms_server.rs | - | - |
info | GET /access/list/{object_id} {user} | src/routes/access.rs | object_id: KMIP object UIDuser: authenticated user identity | - |
info | GET /access/obtained {user} | src/routes/access.rs | user: authenticated user identity | - |
info | GET /access/owned {user} | src/routes/access.rs | user: authenticated user identity | - |
info | GET /certs | src/routes/google_cse/mod.rs | - | - |
info | GET /download-cli {} | src/routes/mod.rs | - | - |
info | GET /google_cse/status {} | src/routes/google_cse/mod.rs | - | - |
info | GET /health {} | src/routes/health.rs | - | - |
info | GET /hsm/status {} | src/routes/mod.rs | - | - |
info | GET /me {user} | src/routes/access.rs | user: authenticated user identity | - |
info | GET /server-info {} | src/routes/mod.rs | - | - |
info | GET /version {} | src/routes/mod.rs | - | - |
info | GET /version {} | src/routes/ms_dke/mod.rs | - | - |
info | Key pair created for certification | src/core/operations/certify/resolve_subject.rs | - | - |
info | KMIP Request message with {} operation(s): {:?} | src/core/operations/message.rs | - | - |
info | KMS Server configuration: {server_params:#?} | src/start_kms_server.rs | server_params: server configuration (debug display) | - |
info | Load default provider | src/openssl_providers.rs | - | - |
info | Load FIPS provider | src/openssl_providers.rs | - | - |
info | Load legacy provider | src/openssl_providers.rs | - | - |
info | No migration key found, creating new RSA keypair. | src/start_kms_server.rs | - | - |
info | OpenSSL version: {ossl_version}, in {ossl_dir}, number: {ossl_number:x} | src/main.rs | ossl_version: OpenSSL version stringossl_dir: OpenSSL modules directoryossl_number: OpenSSL version number (hex) | - |
info | POST /access/grant | src/routes/access.rs | - | - |
info | POST /access/revoke | src/routes/access.rs | - | - |
info | POST /aws/kms/xks/v1/health - request id {} - operation {} | src/routes/aws_xks/health_status.rs | - | - |
info | POST /ekm/info api-version={} user={} | src/routes/azure_ekm/mod.rs | - | - |
info | POST /ekm/{}/metadata api-version={} user={} | src/routes/azure_ekm/mod.rs | - | - |
info | POST /ekm/{}/unwrapkey alg={:?} api-version={} user={} | src/routes/azure_ekm/mod.rs | - | - |
info | POST /ekm/{}/wrapkey alg={:?} api-version={} user={} | src/routes/azure_ekm/mod.rs | - | - |
info | POST /google_cse/delegate: not implemented yet | src/routes/google_cse/mod.rs | - | - |
info | POST /google_cse/wrapprivatekey: not implemented yet | src/routes/google_cse/mod.rs | - | - |
info | POST /google_cse/{info_msg} | src/routes/google_cse/mod.rs | info_msg: route info message | - |
info | POST /kms/xks/v1/keys/{key_id}/decrypt - operation: {} - id: {} - user: {} | src/routes/aws_xks/encrypt_decrypt/decrypt_.rs | key_id: XKS key identifier | - |
info | POST /kms/xks/v1/keys/{key_id}/encrypt - operation: {} - id: {} - user: {} | src/routes/aws_xks/encrypt_decrypt/encrypt_.rs | key_id: XKS key identifier | - |
info | POST /kms/xks/v1/keys/{key_id}/metadata - operation: {} - id: {} - user: {} | src/routes/aws_xks/key_metadata.rs | key_id: XKS key identifier | - |
info | Refreshing JWKS | src/middlewares/jwt/jwks.rs | - | - |
info | Response TTLV: {ttlv:?} | src/routes/kmip.rs | ttlv: TTLV-encoded response | - |
info | Revoked object type: {} | src/core/operations/revoke.rs | - | - |
info | RSA Keypair for Google CSE already exists (detected by UNIQUE constraint). Continuing without error. | src/start_kms_server.rs | - | - |
info | RSA Keypair for Google CSE already exists (pre-check). | src/start_kms_server.rs | - | - |
info | RSA Keypair for Google CSE already exists. | src/start_kms_server.rs | - | - |
info | RSA Keypair for Google CSE created. | src/start_kms_server.rs | - | - |
info | Server started with --info. Exiting | src/main.rs | - | - |
info | Serving index.html from {} | src/start_kms_server.rs | - | - |
info | Serving UI from {} | src/start_kms_server.rs | - | - |
info | Socket server listening on {} | src/socket_server.rs | - | - |
info | Socket server shutting down due to stop request | src/socket_server.rs | - | - |
info | Socket server stop signal sent | src/socket_server.rs | - | - |
info | Starting Cosmian KMS server version {} | src/main.rs | - | - |
info | Starting the HTTPS KMS server... | src/start_kms_server.rs | - | - |
info | Windows service received Stop signal, shutting down... | src/windows_service.rs | - | - |
info | Windows service reporting Running to SCM | src/windows_service.rs | - | - |
info | XKS Decrypt internal error: {:?} | src/routes/aws_xks/encrypt_decrypt/decrypt_.rs | - | - |
info | XKS Encrypt internal error: {:?} | src/routes/aws_xks/encrypt_decrypt/encrypt_.rs | - | - |
info | {} | src/main.rs | - | - |
debug | <== encrypted {} ciphertexts | src/core/operations/encrypt.rs | - | - |
debug | ==> encrypting {} clear texts | src/core/operations/encrypt.rs | - | - |
debug | [metrics-cron] Failed to build runtime: {} | src/cron.rs | - | - |
debug | [metrics-cron] Shutdown signal received; stopping cron thread | src/cron.rs | - | - |
debug | [OK] base64 of encrypted_dek has been removed | src/routes/google_cse/operations.rs | - | - |
debug | [OK] recovered private_key DER bytes (len: {}). Perform RSA decryption | src/routes/google_cse/operations.rs | - | - |
debug | [{idx}] Certificate carries id-ce-noRevAvail (RFC 9608): skipping CRL check | src/core/operations/validate.rs | idx: certificate index in validation chain | - |
debug | [{idx}] Verifying certificate: subject: {:?} | src/core/operations/validate.rs | idx: certificate index in validation chain | - |
debug | Access granted on {} | src/routes/access.rs | - | - |
debug | Access revoke for {} | src/routes/access.rs | - | - |
debug | Activate: object {} current state = {:?} | src/core/operations/activate.rs | - | - |
debug | Add Attribute: {} | src/core/operations/attributes/add.rs | - | - |
debug | AES-GCM decryption failed (expected for implicit rejection): {e} | src/routes/jose/aes_gcm.rs | e: caught error | - |
debug | after getting CRL: url: {url} | src/core/operations/validate.rs | url: URL | - |
debug | algorithm: {ca:?}, ciphertext length: {} | src/core/operations/encrypt.rs | ca: cryptographic algorithm | - |
debug | allocation_size: {allocation_size} | src/routes/google_cse/operations.rs | allocation_size: allocated buffer size | ×2 in this file |
debug | API token authentication failed: {e:?} | src/middlewares/api_token/api_token_middleware.rs | e: caught error | - |
debug | Authentication token check: validation disabled | src/routes/google_cse/operations.rs | - | - |
debug | Building and signing certificate | src/core/operations/certify/build_certificate.rs | - | - |
debug | check algorithm | src/routes/google_cse/operations.rs | - | - |
debug | Client certificate authentication failed: {e:?} | src/middlewares/tls_auth.rs | e: caught error | - |
debug | computing resource_key_hash | src/routes/google_cse/operations.rs | - | - |
debug | Configuration TOML: {conf_str} | src/config/command_line/clap_config.rs | conf_str: configuration TOML string | ×2 in this file |
debug | Create key pair: {request} | src/core/operations/create_key_pair.rs | request: KMIP request (debug display) | - |
debug | create_user_decryption_key_: Access Policy: {access_policy:?} | src/core/cover_crypt/create_user_decryption_key.rs | access_policy: Covercrypt access policy expression | - |
debug | Created secret data with attributes: {} | src/core/kms/other_kms_methods.rs | - | - |
debug | Created symmetric key with attributes: {} | src/core/kms/other_kms_methods.rs | - | - |
debug | Creating SecretData object | src/core/operations/derive_key.rs | - | - |
debug | CRL list already contains key: {path} | src/core/operations/validate.rs | path: filesystem path | - |
debug | CRL list already contains key: {url} | src/core/operations/validate.rs | url: URL | - |
debug | CSE Error: {:?} | src/routes/google_cse/mod.rs | - | - |
debug | decode encrypted_dek | src/routes/google_cse/operations.rs | - | - |
debug | decrypt private key | src/routes/google_cse/operations.rs | - | - |
debug | decrypt request: {:?} | src/routes/aws_xks/encrypt_decrypt/decrypt_.rs | - | - |
debug | decrypt_bulk: ==> decrypted {} plaintexts | src/core/operations/decrypt.rs | - | - |
debug | decrypt_bulk: ==> decrypting {} ciphertexts | src/core/operations/decrypt.rs | - | - |
debug | Decryption Oracle for prefix: {prefix}, total ciphertext is {} bytes long | src/core/operations/decrypt.rs | prefix: decryption oracle prefix bytes | - |
debug | DeriveKey operation completed successfully | src/core/operations/derive_key.rs | - | - |
debug | DeriveKey operation starting | src/core/operations/derive_key.rs | - | - |
debug | DeriveKey: activation_date={:?} <= now, setting state to Active | src/core/operations/derive_key.rs | - | - |
debug | DeriveKey: no activation_date or future date, setting state to PreActive | src/core/operations/derive_key.rs | - | - |
debug | DeriveKey: No derivation data (info) provided for HKDF | src/core/operations/derive_key.rs | - | - |
debug | DeriveKey: No iteration count provided for PBKDF2, using default | src/core/operations/derive_key.rs | - | - |
debug | EKM Error: {:?} | src/routes/azure_ekm/error.rs | - | - |
debug | Enable Google CSE JWT Authorization: {enable_google_cse_authentication} | src/start_kms_server.rs | enable_google_cse_authentication: whether Google CSE JWT auth is on | - |
debug | encode base64 wrapped_dek | src/routes/google_cse/operations.rs | - | - |
debug | encrypt request: {:?} | src/routes/aws_xks/encrypt_decrypt/encrypt_.rs | - | - |
debug | encrypting with RSA {algorithm:?} {padding:?} hashing_fn:{hashing_fn:?} mgf1:{mgf1_hash_fn:?} label_len:{} | src/core/operations/encrypt.rs | algorithm: cryptographic algorithmpadding: asymmetric padding schemehashing_fn: hash functionmgf1_hash_fn: MGF1 hash function | - |
debug | entering | src/routes/google_cse/jwt.rs | - | - |
debug | entering | src/routes/google_cse/operations.rs | - | ×9 in this file |
debug | exiting with success | src/routes/google_cse/operations.rs | - | ×4 in this file |
debug | exiting with success: decrypt_size: {decrypt_size} | src/routes/google_cse/operations.rs | decrypt_size: decrypted payload length | ×2 in this file |
debug | exiting with success: {} | src/routes/google_cse/operations.rs | - | - |
debug | exporting private key with format: {:?} | src/core/operations/export_get.rs | - | - |
debug | fetching {jwks_uri} | src/middlewares/jwt/jwks.rs | jwks_uri: JWKS endpoint URL | - |
debug | from_rsa | src/routes/google_cse/operations.rs | - | - |
debug | Generated JWT for original KACLS: {jwt:?} | src/routes/google_cse/operations.rs | jwt: JWT token (debug display) | - |
debug | Get Attributes: available vendor attributes: [{}] | src/core/operations/attributes/get.rs | - | - |
debug | Get Attributes: fallback vendor attribute match {}:{} from object attributes | src/core/operations/attributes/get.rs | - | - |
debug | Get Attributes: no vendor attributes present on object | src/core/operations/attributes/get.rs | - | - |
debug | Get Attributes: requested vendor attribute not found {}:{} | src/core/operations/attributes/get.rs | - | - |
debug | Get Attributes: returning vendor attribute match {}:{} | src/core/operations/attributes/get.rs | - | - |
debug | Get input certificates as bytes | src/core/operations/validate.rs | - | - |
debug | get metadata request: {:?} | src/routes/aws_xks/key_metadata.rs | - | - |
debug | get rsa public key on {current_kacls_url} | src/routes/google_cse/operations.rs | current_kacls_url: current KACLS server URL | - |
debug | get_crl_bytes: exiting in success with {} CRLs | src/core/operations/validate.rs | - | - |
debug | get_status | src/routes/google_cse/operations.rs | - | - |
debug | Google CSE request authorized for user {authentication_email} | src/routes/google_cse/jwt.rs | authentication_email: email from the authentication token | - |
debug | Import: activation_date={:?} <= now, setting state to Active | src/core/operations/import.rs | - | - |
debug | Import: no activation_date or future date, setting state to PreActive | src/core/operations/import.rs | - | - |
debug | Imported object with uid: {} | src/core/operations/import.rs | - | - |
debug | Importing leaf certificate with attributes: {} | src/core/operations/import.rs | - | - |
debug | Importing PKCS12: private_key_id={:?}, leaf_certificate_id={:?}, chain={:?} | src/core/operations/import.rs | - | - |
debug | JWT Access granted to {email}! | src/middlewares/jwt/jwt_token_auth.rs | email: user email address | - |
debug | JWT authentication failed: {e:?} | src/middlewares/jwt/jwt_middleware.rs | e: caught error | - |
debug | Key successfully unwrapped with wrapping key: {} | src/core/wrapping/unwrap.rs | - | - |
debug | Key wrap type: {:?} | src/core/operations/export_get.rs | - | - |
debug | Key wrapped successfully by key {} | src/core/wrapping/wrap.rs | - | - |
debug | ModifyAttribute: persisting attributes for {} | src/core/operations/attributes/modify.rs | - | - |
debug | no token validation | src/routes/google_cse/operations.rs | - | - |
debug | Number of certificates in chain: {certificates_number} | src/core/operations/validate.rs | certificates_number: number of certificates in chain | - |
debug | object is not wrapped, no need to unwrap | src/core/wrapping/unwrap.rs | - | - |
debug | Object type: {}, with unique identifier: {}, destroyed by user {} | src/core/operations/destroy.rs | - | - |
debug | Object with unique identifier: {} destroyed | src/core/operations/destroy.rs | - | - |
debug | Object with unique identifier: {} revoked | src/core/operations/revoke.rs | - | - |
debug | Object with unique identifier: {} revoked by user {} | src/core/operations/revoke.rs | - | - |
debug | OpenSSL Extensions: {} | src/core/operations/certify/build_certificate.rs | - | - |
debug | Parent CRL verification: revocation status: {res:?} | src/core/operations/validate.rs | res: result (debug display) | - |
debug | proxy_config: {config:#?} | src/config/params/proxy_params.rs | config: configuration (debug display) | - |
debug | re-wrapping key with current KMS | src/routes/google_cse/operations.rs | - | - |
debug | reading full bytes of CRL: url: {url} | src/core/operations/validate.rs | url: URL | - |
debug | Register: activation_date={:?} <= now, setting state to Active | src/core/operations/register.rs | - | - |
debug | Register: no activation_date or future date, setting state to PreActive | src/core/operations/register.rs | - | - |
debug | Registered object with uid: {} | src/core/operations/register.rs | - | - |
debug | Request already authenticated, skipping Ensure Auth middleware | src/middlewares/ensure_auth.rs | - | - |
debug | request.encrypted_data_encryption_key: {} | src/routes/google_cse/operations.rs | - | - |
debug | Retrieved Attributes for {} {}, tags {:?} | src/core/operations/attributes/get.rs | - | - |
debug | retrieving RSA private key from KMS | src/routes/google_cse/operations.rs | - | - |
debug | Revocation status: result: {res:?} | src/core/operations/validate.rs | res: result (debug display) | - |
debug | RSA key pair generation: size in bits: {key_size_in_bits} | src/core/operations/create_key_pair.rs | key_size_in_bits: RSA key size in bits | - |
debug | RSA-OAEP encrypt: wrapped CEK ({} bytes) with {} ({} bit key) | src/routes/jose/encrypt.rs | - | - |
debug | RSA-OAEP unwrap failed or CEK size mismatch — using implicit rejection | src/routes/jose/decrypt.rs | - | - |
debug | Set Attribute: {} | src/core/operations/attributes/set.rs | - | - |
debug | Set Object Attribute: {} | src/core/operations/attributes/add.rs | - | - |
debug | Set Object Attribute: {} | src/core/operations/attributes/set.rs | - | - |
debug | Setting key_wrap_type to NotWrapped due to default_unwrap_types | src/core/operations/export_get.rs | - | - |
debug | Signature verification result: {validity_indicator:?} | src/core/operations/signature_verify.rs | validity_indicator: signature validity result | - |
debug | signature_verify: effective CP => alg={:?} pad={:?} hash={:?} dsa={:?} mgf1_hash={:?} | src/core/operations/signature_verify.rs | - | - |
debug | Sigv4 Middleware - Adding missing HOST header: {} | src/routes/aws_xks/sigv4_middleware.rs | - | - |
debug | Skipping non-HTTP CRL URI: {url} | src/core/operations/validate.rs | url: URL | - |
debug | Socket server received stop signal: {result:?} | src/socket_server.rs | result: operation result | - |
debug | socket server: client connected from {} | src/socket_server.rs | - | - |
debug | socket server: client {} disconnected | src/socket_server.rs | - | - |
debug | socket server: received request: {} | src/socket_server.rs | - | - |
debug | success | src/routes/google_cse/operations.rs | - | - |
debug | The wrapping key {wrapping_key_uid} is itself wrapped, unwrapping it first | src/core/wrapping/wrap.rs | wrapping_key_uid: UID of the wrapping key | - |
debug | tls_config: {config:#?} | src/config/params/tls_params.rs | config: configuration (debug display) | - |
debug | Token authentication successful | src/middlewares/api_token/api_token_auth.rs | - | - |
debug | unwrap key | src/routes/google_cse/operations.rs | - | ×2 in this file |
debug | Unwrapped cache hit | src/core/kms/other_kms_methods.rs | - | - |
debug | Unwrapped cache miss. Calling unwrap | src/core/kms/other_kms_methods.rs | - | - |
debug | user signed data via crypto oracle using: {uid} | src/core/operations/sign.rs | uid: KMIP object UID | - |
debug | validate_tokens | src/routes/google_cse/operations.rs | - | - |
debug | wrap dek | src/routes/google_cse/operations.rs | - | ×2 in this file |
debug | Xks Error: {:?} | src/routes/aws_xks/error.rs | - | - |
debug | XKS Proxy - Path not found: {} | src/routes/aws_xks/error.rs | - | - |
debug | {conf:#?} | src/config/params/server_params.rs | conf: configuration (debug display) | - |
debug | {request} | src/core/operations/attributes/modify.rs | request: KMIP request (debug display) | - |
debug | {request} | src/core/operations/attributes/set.rs | request: KMIP request (debug display) | - |
debug | {res:#?} | src/config/params/server_params.rs | res: result (debug display) | - |
debug | {ui_index_html_folder:#?} | src/config/params/server_params.rs | ui_index_html_folder: configured UI folder path | ×2 in this file |
debug | {wrap_request:?} | src/routes/google_cse/jwt.rs | wrap_request: CSE wrap request (debug display) | - |
debug | {} identifiers | src/core/operations/validate.rs | - | - |
trace | : | src/core/operations/attributes/dispatch_macros.rs | — | — |
trace | : {:?} | src/core/operations/attributes/dispatch_macros.rs | — | — |
trace | [api_token_auth] Authorization header received (length: {} chars) | src/middlewares/api_token/api_token_auth.rs | — | — |
trace | [api_token_auth] comparing client token ({} chars) with server token | src/middlewares/api_token/api_token_auth.rs | — | — |
trace | [destroy-core] certificate zeroization uid={unique_identifier} | src/core/operations/destroy.rs | unique_identifier — … | — |
trace | [destroy-core] opaque object zeroization uid={unique_identifier} len={} | src/core/operations/destroy.rs | unique_identifier — … | — |
trace | [destroy-core] uid={unique_identifier} type={:?} pre-state={:?} object={object} | src/core/operations/destroy.rs | unique_identifier — …object — … | — |
trace | [destroy] DENY revoke-before-destroy (explicitly activated) uid={} type={:?} state={:?} activation_date={:?} initial_date={:?} | src/core/operations/destroy.rs | — | — |
trace | [destroy] Failed to destroy linked private key {}: {:?}. Continuing with public key destruction. | src/core/operations/destroy.rs | — | — |
trace | [destroy] policy-eval uid={} type={:?} db_state={:?} attr_state={:?} effective_state={:?} activation_date={:?} policy_state={:?} remove={} | src/core/operations/destroy.rs | — | — |
trace | [revoke] proceed-destroyed uid={uid} state={:?} | src/core/operations/revoke.rs | uid — … | — |
trace | [revoke] skip uid={uid} reason=state-not-revocable state={:?} | src/core/operations/revoke.rs | uid — … | — |
trace | algorithm: {:?}, padding: {:?}, hashing_fn: {:?} | src/core/operations/decrypt.rs | — | — |
trace | algorithm={:?}, data_len={} | src/core/operations/hash.rs | — | — |
trace | All certificates have been sorted | src/core/operations/validate.rs | — | ×2 in this file |
trace | Already an unwrapped key | src/core/kms/other_kms_methods.rs | — | — |
trace | Attribute: Object type {:?} does not have attributes (nor key block) | src/core/operations/attributes/add.rs | — | — |
trace | authentication token validated for {authentication_email} | src/routes/google_cse/jwt.rs | authentication_email — … | — |
trace | authorization token validated successfully | src/routes/google_cse/jwt.rs | — | — |
trace | Auto-activating object {} (activation_date {} <= now {}) | src/core/retrieve_object_utils.rs | — | — |
trace | build_pkcs12_for_private_key: {} with format: {:?} | src/core/operations/export_get.rs | — | — |
trace | building chain from leaf certificate: {} | src/core/operations/export_get.rs | — | — |
trace | building the PKCS12 | src/core/operations/export_get.rs | — | — |
trace | Certificate attribute link: {} | src/core/operations/certify/certify_op.rs | — | — |
trace | Certificate attributes links: None | src/core/operations/certify/certify_op.rs | — | — |
trace | certificate parent id is: {} | src/core/operations/export_get.rs | — | — |
trace | Certificate parent id is: {parent_id} | src/core/operations/export_get.rs | parent_id — … | — |
trace | Certify KeypairAndSubjectName:{unique_identifier} : keypair data: {keypair_data} | src/core/operations/certify/certify_op.rs | unique_identifier — …keypair_data — … | — |
trace | Certify X509Req or Certificate:{unique_identifier} | src/core/operations/certify/certify_op.rs | unique_identifier — … | — |
trace | Checking key with ID: {} | src/core/retrieve_object_utils.rs | — | — |
trace | Checking permissions to wrap with key {wrapping_key_uid} | src/core/wrapping/wrap.rs | wrapping_key_uid — … | — |
trace | Checking usage mask for wrapping key {wrapping_key_uid} | src/core/wrapping/wrap.rs | wrapping_key_uid — … | — |
trace | ciphertext (ECB): {ciphertext:?}, aad: {aad:?}, padding_method: {padding_method:?} | src/core/operations/decrypt.rs | ciphertext — …aad — …padding_method — … | — |
trace | Client certificate common name: {} | src/middlewares/tls_auth.rs | — | — |
trace | configure_cipher_suites: Enable default cipher suites (mozilla_intermediate_v5) | src/tls_config.rs | — | — |
trace | configure_cipher_suites: Setting custom cipher string: {suites} | src/tls_config.rs | suites — … | — |
trace | Configuring client certificate verification for {} | src/tls_config.rs | — | — |
trace | converting the private key {} to openssl pkey | src/core/operations/export_get.rs | — | — |
trace | create_base_openssl_acceptor: creating OpenSSL SslAcceptorBuilder for {server_type} | src/tls_config.rs | server_type — … | — |
trace | Creating object of type {:?} with UID {} and attributes {} | src/core/operations/create.rs | — | — |
trace | Creating OpenSSL SslAcceptor for socket server | src/socket_server.rs | — | — |
trace | Creating OpenSSL SslAcceptorBuilder with TLS parameters | src/start_kms_server.rs | — | — |
trace | CRL deserialized OK: {crl_path} | src/core/operations/validate.rs | crl_path — … | ×2 in this file |
trace | cryptographic_algorithm: {cryptographic_algorithm} | src/core/operations/create_key_pair.rs | cryptographic_algorithm — … | — |
trace | curve: {curve} | src/core/operations/create_key_pair.rs | curve — … | — |
trace | Decrypt: uid={:?}, data_len={} | src/core/operations/decrypt.rs | — | — |
trace | DELETE /v1/crypto/keys/{kid} | src/routes/jose/keys.rs | kid — … | — |
trace | Description: {:?} | src/core/operations/attributes/add.rs | — | — |
trace | Discover versions: {} | src/core/operations/discover_versions.rs | — | — |
trace | ECB encrypt result: ciphertext_len={} | src/core/operations/encrypt.rs | — | — |
trace | ECB encrypt: plaintext_len={}, padding_method={padding_method:?} | src/core/operations/encrypt.rs | padding_method — … | — |
trace | effective RSA CP -> padding={:?} hashing={:?} mgf1={:?} label_len={} | src/core/operations/decrypt.rs | — | — |
trace | encrypt result: ciphertext_len={}, tag_len={} | src/core/operations/encrypt.rs | — | — |
trace | entering | src/routes/google_cse/jwt.rs | — | — |
trace | Entering get_key_and_cipher | src/core/operations/encrypt.rs | — | — |
trace | Entering import KMIP operation: uid={}, object_type={} | src/core/operations/import.rs | — | — |
trace | Entering message KMIP operation: {request} | src/core/operations/message.rs | request — … | — |
trace | entering. owm: {} | src/core/operations/encrypt.rs | — | — |
trace | export_get_private_key: {} for operation: {} | src/core/operations/export_get.rs | — | — |
trace | Extracting key block for decryption to identify key format type... | src/core/operations/decrypt.rs | — | — |
trace | Fetching public key: {public_key_name} and attempting to extract RSA modulus and public exponent from key material | src/routes/utils.rs | public_key_name — … | — |
trace | Found CRL URI: {crl_uri} | src/core/operations/validate.rs | crl_uri — … | — |
trace | found link to certificate: {} | src/core/certificate/find.rs | — | — |
trace | found link to public key: {}. Will get certificate link from there | src/core/certificate/find.rs | — | — |
trace | Found uid: {}, attributes: {} | src/core/operations/locate.rs | — | — |
trace | function={:?} | src/core/operations/pkcs11.rs | — | — |
trace | Get Attributes: Attributes: {} | src/core/operations/attributes/get.rs | — | — |
trace | Get Attributes: computing LinkType set | src/core/operations/attributes/get.rs | — | — |
trace | Get Attributes: Requested attributes: {req_attributes:?} | src/core/operations/attributes/get.rs | req_attributes — … | — |
trace | Get Attributes: Response: {} | src/core/operations/attributes/get.rs | — | — |
trace | Get Attributes: Retrieved object for get attributes: {} | src/core/operations/attributes/get.rs | — | — |
trace | GET KEY /{} {:?} | src/routes/ms_dke/mod.rs | — | — |
trace | Get: {} | src/core/operations/get.rs | — | — |
trace | get_crl_bytes: entering: uri_list: {uri_list:?} | src/core/operations/validate.rs | uri_list — … | — |
trace | got key bytes of length: {}, aead: {:?}. Proceeding to get the nonce... | src/core/operations/decrypt.rs | — | — |
trace | HMAC computed: {} bytes | src/core/operations/mac.rs | — | — |
trace | HSM get_key_type probe for '{uid}' failed: {e}; proceeding with destroy | src/core/operations/destroy.rs | uid — …e — … | — |
trace | Ignoring tag {x:?} which does not match to an attribute | src/core/operations/attributes/get.rs | x — … | — |
trace | import opaque_object: uid={} | src/core/operations/import.rs | — | — |
trace | import secret_data: uid={} | src/core/operations/import.rs | — | — |
trace | Internal create key pair | src/core/operations/create_key_pair.rs | — | — |
trace | Internal create private key | src/core/kms/other_kms_methods.rs | — | — |
trace | Internal create private key (FIPS build) | src/core/kms/other_kms_methods.rs | — | — |
trace | Internal rekey key pair Covercrypt | src/core/cover_crypt/rekey_keys.rs | — | — |
trace | Issuer certificate id: {} | src/core/operations/certify/resolve_issuer.rs | — | — |
trace | Issuer private key id: {} | src/core/operations/certify/resolve_issuer.rs | — | — |
trace | Issuer Subject name: {:?} | src/core/operations/certify/certify_op.rs | — | — |
trace | iv_counter_nonce: {}, ciphertext: {}, authenticated_tag: {} | src/routes/google_cse/operations.rs | — | — |
trace | JWT Authentication... | src/middlewares/jwt/jwt_token_auth.rs | — | — |
trace | key id {} | src/core/operations/decrypt.rs | — | — |
trace | key_format_type: {key_format_type:?} | src/core/operations/export_get.rs | key_format_type — … | — |
trace | key_material key format: {:?} | src/core/operations/digest.rs | — | — |
trace | Leaf certificate extracted from PKCS12 | src/core/operations/import.rs | — | — |
trace | Link: {} | src/core/operations/attributes/add.rs | — | — |
trace | Locate: filtering out HSM key {uid_str} — user {user} has no grants | src/core/operations/locate.rs | uid_str — …user — … | — |
trace | Mac: algorithm: {algorithm:?} | src/core/operations/mac.rs | algorithm — … | — |
trace | Mac: data len: {} | src/core/operations/mac.rs | — | — |
trace | matching on key format type: {:?} | src/core/operations/encrypt.rs | — | — |
trace | matching on key format type: {:?} | src/core/operations/sign.rs | — | — |
trace | matching on public key format type: {:?} | src/core/operations/decrypt.rs | — | — |
trace | ModifyAttribute: ActivationDate: {:?} | src/core/operations/attributes/modify.rs | — | — |
trace | ModifyAttribute: Link: {} | src/core/operations/attributes/modify.rs | — | — |
trace | ModifyAttribute: Name: {} | src/core/operations/attributes/modify.rs | — | — |
trace | ModifyAttribute: retrieved target object {} | src/core/operations/attributes/modify.rs | — | — |
trace | ModifyAttribute: VendorAttribute: {} | src/core/operations/attributes/modify.rs | — | — |
trace | Name: {name} | src/core/operations/attributes/add.rs | name — … | — |
trace | no effective cryptographic parameters; defaults will apply | src/core/operations/decrypt.rs | — | — |
trace | No issuer certificate id provided | src/core/operations/certify/resolve_issuer.rs | — | — |
trace | No issuer private key id provided | src/core/operations/certify/resolve_issuer.rs | — | — |
trace | No UI folder containing index.html found at {} | src/start_kms_server.rs | — | — |
trace | Non revocable keys detected: won't be revoked {non_revocable_key_id:?} | src/core/operations/revoke.rs | non_revocable_key_id — … | — |
trace | Not using Client Certificate Authentication with OpenSSL | src/start_kms_server.rs | — | — |
trace | OpenSSL Private Key instantiated before signing | src/core/operations/sign.rs | — | — |
trace | OpenSSL Public Key instantiated before encryption | src/core/operations/encrypt.rs | — | — |
trace | Operation processed successfully: {op} | src/core/operations/message.rs | op — … | — |
trace | Operation processing failed: {e} | src/core/operations/message.rs | e — … | — |
trace | params: {server_params:?} | src/core/kms/mod.rs | server_params — … | — |
trace | PKCS12 parsed successfully | src/core/operations/import.rs | — | — |
trace | plaintext length: {} bytes | src/core/operations/decrypt.rs | — | — |
trace | plaintext_len={}, nonce_len={}, aad_len={}, padding_method={padding_method:?} | src/core/operations/encrypt.rs | padding_method — … | — |
trace | POST /v1/crypto/decrypt | src/routes/jose/decrypt.rs | — | — |
trace | POST /v1/crypto/encrypt kid={} alg={} | src/routes/jose/encrypt.rs | — | — |
trace | POST /v1/crypto/keys kty={} | src/routes/jose/keys.rs | — | — |
trace | POST /v1/crypto/keys/unwrap | src/routes/jose/unwrap.rs | — | — |
trace | POST /v1/crypto/mac kid={} | src/routes/jose/mac.rs | — | — |
trace | POST /v1/crypto/sign kid={} | src/routes/jose/sign.rs | — | — |
trace | POST /v1/crypto/verify | src/routes/jose/verify.rs | — | — |
trace | POST /{key_name}/{key_id}/Decrypt {encrypted_data:?} | src/routes/ms_dke/mod.rs | key_name — …key_id — …encrypted_data — … | — |
trace | post_process_private_key: operation type: {operation_type:?} | src/core/operations/export_get.rs | operation_type — … | — |
trace | Private key attributes after lifecycle update: {} | src/core/operations/create_key_pair.rs | — | — |
trace | Private key extracted from PKCS12 | src/core/operations/import.rs | — | — |
trace | Private key linked to leaf certificate | src/core/operations/import.rs | — | — |
trace | Private key operation created | src/core/operations/import.rs | — | — |
trace | Private key wrapped and cached | src/core/operations/import.rs | — | — |
trace | process_secret_data: object_with_metadata: {} | src/core/operations/export_get.rs | — | — |
trace | process_symmetric_key: object_with_metadata: {} | src/core/operations/export_get.rs | — | — |
trace | processing key_value | src/core/operations/digest.rs | — | — |
trace | Processing KMIP operation: {operation_name} with user: {user:?} | src/core/operations/message.rs | operation_name — …user — … | — |
trace | Processing PKCS12 import | src/core/operations/import.rs | — | — |
trace | Public key attributes after lifecycle update: {} | src/core/operations/create_key_pair.rs | — | — |
trace | Public key extracted from PKCS12 | src/core/operations/import.rs | — | — |
trace | ReKey: {} | src/core/operations/rekey/symmetric/mod.rs | — | — |
trace | ReKeyKeyPair: {} | src/core/operations/rekey/keypair/mod.rs | — | — |
trace | Request: {:?} | src/routes/azure_ekm/mod.rs | — | ×4 in this file |
trace | request: {username} {} | src/start_kms_server.rs | username — … | — |
trace | Response message: {response_message} | src/core/operations/message.rs | response_message — … | — |
trace | Response sent to {} | src/socket_server.rs | — | — |
trace | Retrieved certificate: {} for private key: {} | src/core/certificate/find.rs | — | — |
trace | Retrieved object for: {} | src/core/operations/activate.rs | — | — |
trace | Retrieved object for: {} | src/core/operations/attributes/add.rs | — | — |
trace | Retrieved object for: {} | src/core/operations/attributes/delete.rs | — | — |
trace | Retrieving certificate for private key: {} | src/core/certificate/find.rs | — | — |
trace | Retrieving issuer private key and certificate: private_key_id: {:?}, certificate_id: {:?} | src/core/certificate/find.rs | — | — |
trace | Retrieving private key for certificate: certificate_uid_or_tags: {:?} | src/core/certificate/find.rs | — | — |
trace | RNGRetrieve: {} | src/core/operations/rng_retrieve.rs | — | — |
trace | Root and possibly leaf removed from initial certificate list. Left: {} | src/core/operations/validate.rs | — | — |
trace | Sensitive: {:?} | src/core/operations/attributes/add.rs | — | — |
trace | Set Attribute: Link: {} | src/core/operations/attributes/set.rs | — | — |
trace | Set Attribute: Name: {} | src/core/operations/attributes/set.rs | — | — |
trace | Set Attribute: Object type {:?} does not have attributes (nor key block) | src/core/operations/attributes/set.rs | — | — |
trace | Set Attribute: Retrieved target object | src/core/operations/attributes/set.rs | — | — |
trace | Set Attribute: Vendor Attribute: {} | src/core/operations/attributes/set.rs | — | — |
trace | sk_uid: {sk_uid}, pk_uid: {pk_uid} | src/core/operations/create_key_pair.rs | sk_uid — …pk_uid — … | — |
trace | state_allows: {state_allows}: state: {state}, operation_type: {operation_type} | src/core/retrieve_object_utils.rs | state_allows — …state — …operation_type — … | — |
trace | Subject name: {:?} | src/core/operations/certify/certify_op.rs | — | — |
trace | The wrapping key {wrapping_key_uid} is authorized to wrap keys | src/core/wrapping/wrap.rs | wrapping_key_uid — … | — |
trace | TLS Authentication... | src/middlewares/tls_auth.rs | — | — |
trace | TLS Authentication: no peer certificate found | src/middlewares/tls_auth.rs | — | — |
trace | Token authentication using this API token ID: {api_token_id} | src/middlewares/api_token/api_token_auth.rs | api_token_id — … | — |
trace | token decoded with {app_name} jwt config | src/routes/google_cse/jwt.rs | app_name — … | — |
trace | Try to validate token from issuer: {issuer_uri:?} | src/routes/google_cse/jwt.rs | issuer_uri — … | — |
trace | UID: {:?}, State: {:?}, Attributes: {} | src/core/operations/locate.rs | — | ×2 in this file |
trace | uid={:?} | src/core/operations/mac.rs | — | — |
trace | uid={:?}, data_len={} | src/core/operations/encrypt.rs | — | — |
trace | uid={} | src/core/operations/mac.rs | — | — |
trace | uid={} remove={} cascade={} | src/core/operations/destroy.rs | — | — |
trace | UIDs count (post-truncate): {} | src/core/operations/locate.rs | — | — |
trace | updated_master_secret_key_bytes len: {} | src/core/cover_crypt/create_user_decryption_key.rs | — | — |
trace | User {user} does not have permission for operation {operation_type:?} on object {} | src/core/retrieve_object_utils.rs | user — …operation_type — … | — |
trace | User {user} has permission for operation {operation_type:?} on object {} | src/core/retrieve_object_utils.rs | user — …operation_type — … | — |
trace | Using Client Certificate Authentication with OpenSSL | src/start_kms_server.rs | — | — |
trace | valid_jwt headers: {:?} | src/routes/google_cse/jwt.rs | — | — |
trace | valid_jwt user claims: {:?} | src/routes/google_cse/jwt.rs | — | — |
trace | validate token: KACLS URL {google_cse_kacls_url} | src/routes/google_cse/jwt.rs | google_cse_kacls_url — … | — |
trace | Validate: {} | src/core/operations/validate.rs | — | — |
trace | validate_cse_authorization_token: KACLS URL {google_cse_kacls_url} | src/routes/google_cse/jwt.rs | google_cse_kacls_url — … | — |
trace | validating authentication token, expected JWT issuer: {} | src/middlewares/jwt/jwt_config.rs | — | — |
trace | validating CSE authorization token, expected issuer : {} | src/routes/google_cse/jwt.rs | — | — |
trace | Vendor Attribute: {} | src/core/operations/attributes/add.rs | — | — |
trace | verify_chain_signature: entering: number of certificates: {} | src/core/operations/validate.rs | — | — |
trace | verify_crls: exiting in success | src/core/operations/validate.rs | — | — |
trace | Waiting for test socket server to start... | src/socket_server.rs | — | — |
trace | wrapped_key length: {} chars | src/routes/google_cse/operations.rs | — | — |
trace | Wrapping key retrieved successfully: {wrapping_key} | src/core/wrapping/wrap.rs | wrapping_key — … | — |
trace | Wrapping key with id: {wrapping_key_id} | src/core/wrapping/wrap.rs | wrapping_key_id — … | — |
trace | {debug_msg}. Certificate: subject: {:?}, AKI: {:?}, SKI: {:?} | src/core/operations/validate.rs | debug_msg — … | — |
trace | {info_msg} request received | src/routes/google_cse/mod.rs | info_msg — … | — |
trace | {jwt_authorization_config:#?} | src/routes/google_cse/jwt.rs | jwt_authorization_config — … | — |
trace | {request} | src/core/operations/attributes/get.rs | request — … | — |
trace | {request} | src/core/operations/check.rs | request — … | — |
trace | {request} | src/core/operations/create.rs | request — … | — |
trace | {request} | src/core/operations/destroy.rs | request — … | — |
trace | {request} | src/core/operations/export.rs | request — … | — |
trace | {request} | src/core/operations/query.rs | request — … | — |
trace | {request} | src/core/operations/register.rs | request — … | — |
trace | {request} | src/core/operations/revoke.rs | request — … | — |
trace | {request} | src/core/operations/rng_seed.rs | request — … | — |
trace | {request} | src/core/operations/sign.rs | request — … | — |
trace | {request} | src/core/operations/signature_verify.rs | request — … | — |
trace | {} | src/core/operations/activate.rs | — | — |
trace | {} | src/core/operations/attributes/add.rs | — | — |
trace | {} | src/core/operations/attributes/delete.rs | — | — |
trace | {} | src/core/operations/certify/certify_op.rs | — | — |
trace | {} | src/core/operations/locate.rs | — | — |
error | Failed to convert response message to TTLV: {} | src/routes/kmip.rs | — | ×2 in this file |
error | Failed to find KMIP version | src/routes/kmip.rs | — | — |
error | Failed to parse RequestMessage: {} | src/routes/kmip.rs | — | — |
error | Failed to process request: {} | src/routes/kmip.rs | — | ×2 in this file |
error | OpenSSL does not appear to be available (version number is 0). Please verify that OpenSSL is correctly installed and accessible. | src/main.rs | — | — |
warn | An Edwards Keypair on curve 25519 should not be requested to perform ECDH. Creating anyway. | src/core/operations/create_key_pair.rs | — | — |
warn | An Edwards Keypair on curve 448 should not be requested to perform ECDH. Creating anyway. | src/core/operations/create_key_pair.rs | — | — |
warn | CRL signature could not be verified against chain issuers; issuer: {:?}. Continuing with status checks. | src/core/operations/validate.rs | — | — |
warn | Import: CRL check could not be completed ({e}), proceeding with {desired_state:?} state | src/core/operations/import.rs | e, desired_state | — |
warn | The UI index HTML folder does not contain an index.html file: {ui_index_html_folder:#?} | src/config/params/server_params.rs | ui_index_html_folder | — |
warn | Unsupported Block Cipher Mode for AES: {x:?}. The Authenticated Encryption Tag will NOT be extracted. | src/routes/kmip.rs | x | — |
warn | User-supplied keyUsage in extension config overrides the RFC-mandated PQC keyUsage extension (RFC 9881/9909/9935) | src/core/operations/certify/build_certificate.rs | — | — |
debug | ...unwrapping the key block with key uid: {unwrapping_key_uid} using an encryption oracle, user: {user} | src/core/wrapping/unwrap.rs | unwrapping_key_uid, user | — |
debug | ...unwrapping the key block with key uid: {unwrapping_key_uid} using the KMS, user: {user} | src/core/wrapping/unwrap.rs | unwrapping_key_uid, user | — |
debug | ...wrapping the key block with key uid: {wrapping_key_uid} using an encryption oracle, user: {user} | src/core/wrapping/wrap.rs | wrapping_key_uid, user | — |
debug | ...wrapping the key block with key uid: {wrapping_key_uid} using the KMS, user: {user} | src/core/wrapping/wrap.rs | wrapping_key_uid, user | — |
debug | [kms-init] Failed to seed kms.keys.active.count: {e} | src/core/kms/mod.rs | e | — |
debug | [kms-init] Failed to seed kms.objects.total: {e} | src/core/kms/mod.rs | e | — |
debug | [metrics-cron] Failed to sync kms.keys.active.count: {} | src/cron.rs | — | — |
debug | [metrics-cron] Failed to sync kms.objects.total: {} | src/cron.rs | — | — |
debug | [metrics-cron] kms.keys.active.count synced to {} | src/cron.rs | — | — |
debug | [metrics-cron] kms.objects.total synced to {} | src/cron.rs | — | — |
debug | [metrics-cron] reconcile_all_object_counts failed: {} | src/cron.rs | — | — |
debug | API Token Middleware: An authenticated user was found; there is no need to authenticate twice... | src/middlewares/api_token/api_token_middleware.rs | — | — |
debug | DeriveKey: No derivation data provided - this may be acceptable if a Secret Data object identifier is provided | src/core/operations/derive_key.rs | — | — |
debug | Import: certificate is revoked per CRL check, setting state to Compromised | src/core/operations/import.rs | — | — |
debug | JWT: An authenticated user was found; there is no need to authenticate twice... | src/middlewares/jwt/jwt_middleware.rs | — | — |
debug | Request bytes: {} | src/routes/kmip.rs | — | — |
debug | Request TTLV: {ttlv:#?} | src/routes/kmip.rs | ttlv | — |
debug | Response Message Bytes: {} | src/routes/kmip.rs | — | — |
debug | Response Message TTLV: {response_ttlv:#?} | src/routes/kmip.rs | response_ttlv | — |
debug | The user: {user}, is authorized to wrap with the key {wrapping_key_uid}. Encoding: {:?}, format: {} | src/core/wrapping/wrap.rs | user, wrapping_key_uid | — |
debug | This is a {major}.{minor} Decrypt message. Extracting Authenticated Encryption Tag of length {len} from Data field | src/routes/kmip.rs | major, minor, len | — |
trace | Certify PublicKeyAndSubjectName:{unique_identifier}: public key: {from_public_key} | src/core/operations/certify/certify_op.rs | unique_identifier, from_public_key | — |
trace | ciphertext: {ciphertext:?}, nonce: {nonce:?}, aad: {aad:?}, tag: {tag:?}, padding_method: {padding_method:?} | src/core/operations/decrypt.rs | ciphertext, nonce, aad, tag, padding_method | — |
trace | enter export_get op={:?} req={} | src/core/operations/export_get.rs | — | ×2 in this file |
trace | get_attribute_list uid={} refs=[{}] | src/core/operations/attributes/get_list.rs | — | — |
trace | post-process symmetric key uid={} final_format={:?} | src/core/operations/export_get.rs | — | — |
trace | process_symmetric_key enter uid={} requested_format={:?} wrap_type={:?} | src/core/operations/export_get.rs | — | — |
trace | process_symmetric_key exit uid={} final_format={:?} | src/core/operations/export_get.rs | — | — |
trace | process_symmetric_key key_block initial format={:?} wrapped={} uid={} | src/core/operations/export_get.rs | — | — |
trace | process_symmetric_key missing key_value structure uid={} | src/core/operations/export_get.rs | — | — |
trace | process_symmetric_key set Raw uid={} | src/core/operations/export_get.rs | — | — |
trace | process_symmetric_key set TransparentSymmetricKey uid={} | src/core/operations/export_get.rs | — | — |
trace | processing symmetric key uid={} state={:?} requested_format={:?} | src/core/operations/export_get.rs | — | — |
trace | Request Message: {request_message} | src/routes/kmip.rs | request_message | — |
trace | Response Message: {response_message} | src/routes/kmip.rs | response_message | — |
trace | retrieved object uid={} type={:?} state={:?} key_fmt={:?} | src/core/operations/export_get.rs | — | — |
trace | uid_or_tags: {uid_or_tags:?}, user: {user}, operation_type: {operation_type:?} | src/core/retrieve_object_utils.rs | uid_or_tags, user, operation_type | — |
error | Failed to convert Response TTLV to bytes: {}: TTLV:\n{:#?} | src/routes/kmip.rs | — | — |
warn | Failed to process request:\n{response_message} | src/routes/kmip.rs | response_message | — |
info | \n{:?} | src/routes/kmip.rs | — | — |
trace | JWK has been found:\n{jwk:?} | src/middlewares/jwt/jwt_config.rs | jwk | — |
trace | JWK has been found:\n{jwk:?} | src/routes/google_cse/jwt.rs | jwk | — |
warn | Failed to persist auto-deactivation of object {}: {} | src/core/retrieve_object_utils.rs | - | ×2 in this file |
warn | failed to re-wrap dependant {dep_uid} with new key: {e}, skipping | src/core/operations/rekey/common.rs | dep_uid, e | - |
warn | failed to unwrap dependant {dep_uid}: {e}, skipping | src/core/operations/rekey/common.rs | dep_uid, e | - |
warn | skipping re-wrap of dependant {dep_uid}: owned by '{}', not by '{owner}' | src/core/operations/rekey/common.rs | dep_uid, owner | - |
warn | wrapped dependant {dep_uid} not found, skipping | src/core/operations/rekey/common.rs | dep_uid | - |
warn | {}: keyset chain depth {} ≥ warn threshold {} for uid {}; consider re-encrypting with the latest key | src/core/operations/key_ops/crypto_op.rs | - | - |
info | Rekey finalized: old={} → new={}, user={user} | src/core/operations/rekey/common.rs | user | - |
debug | [auto-rotate-cron] Failed to build runtime: {} | src/cron.rs | - | - |
debug | [auto-rotate-cron] Running scheduled key auto-rotation check | src/cron.rs | - | - |
debug | [auto-rotate-cron] Shutdown signal received; stopping cron thread | src/cron.rs | - | - |
trace | Auto-deactivating object {} (deactivation_date {} <= now {}) | src/core/retrieve_object_utils.rs | - | ×2 in this file |
trace | execute_keyset_try_each: key {} failed for {}: {} | src/core/operations/key_ops/crypto_op.rs | - | - |
trace | HSM ReKey: old={uid} → new={new_uid} (slot={slot_id}, gen={new_gen}), user={user} | src/core/operations/rekey/symmetric/hsm.rs | uid, new_uid, slot_id, new_gen, user | - |
trace | ReCertify: {} | src/core/operations/recertify.rs | - | - |
trace | ReKey: resolved keyset ref '{}' → '{}' | src/core/operations/rekey/symmetric/mod.rs | - | - |
trace | SetAttribute: clearing CKA_START_DATE / CKA_END_DATE on HSM key '{}' (rotation disabled) | src/core/operations/attributes/set.rs | - | - |
trace | SetAttribute: writing CKA_LABEL '{}' on HSM key '{}' | src/core/operations/attributes/set.rs | - | - |
trace | SetAttribute: writing CKA_START_DATE={} CKA_END_DATE={} on HSM key '{}' | src/core/operations/attributes/set.rs | - | - |
trace | walk_keyset_chain: keyset '{}' has {} keys in chain | src/core/uid_utils.rs | - | - |
warn | ui_session_salt is not configured — using a randomly generated ephemeral session key. Sessions will be invalidated on server restart and are not portable across instances. For persistent sessions and load-balanced deployments, set `ui_session_salt` (or KMS_UI_SESSION_SALT) to a strong random secret value. | src/start_kms_server.rs | - | - |
trace | Found valid JWK in JWKS at `{jwks_uri}`: {jwk:#?} | src/middlewares/jwt/jwks.rs | jwks_uri, jwk | - |
trace | Ignoring invalid JWK in JWKS at `{jwks_uri}`: {e}: {v:#?} | src/middlewares/jwt/jwks.rs | jwks_uri, e, v | - |
trace | PKCS#11 `C_CloseSession` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_Decrypt` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_DecryptFinal` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_DecryptInit` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_DecryptUpdate` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_DestroyObject` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_Encrypt` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_EncryptFinal` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_EncryptInit` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_EncryptUpdate` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_Finalize` failed: {e} | src/core/operations/pkcs11.rs | e | - |
trace | PKCS#11 `C_FindObjects` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_FindObjectsFinal` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_FindObjectsInit` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_GenerateKey` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_GenerateKeyPair` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_GenerateRandom` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_GetAttributeValue` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_GetInfo` failed: {e} | src/core/operations/pkcs11.rs | e | - |
trace | PKCS#11 `C_GetMechanismInfo` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_GetMechanismList` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_Initialize` called on already initialized library - treating as success | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_Initialize` failed: {e} | src/core/operations/pkcs11.rs | e | - |
trace | PKCS#11 `C_Login` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_Logout` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_OpenSession` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_SeedRandom` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_UnwrapKey` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | PKCS#11 `C_WrapKey` not yet implemented | src/core/operations/pkcs11.rs | - | - |
trace | ReKeyKeyPair: resolved keyset ref '{}' → '{}' | src/core/operations/rekey/keypair/mod.rs | - | - |
warn | find_wrapped_by({old_uid}) failed — skipping re-wrap of dependants: {e} | src/core/operations/rekey/common.rs | old_uid, e | - |
warn | [auto-rotate] Failed to query keys due for rotation: {e} | src/core/operations/auto_rotate.rs | e | - |
warn | [auto-rotate] Failed to re-arm rotation policy on replacement {new_uid}: {e} | src/core/operations/auto_rotate.rs | new_uid, e | - |
warn | [auto-rotate] Failed to retrieve key {uid}: {e}; skipping | src/core/operations/auto_rotate.rs | uid, e | - |
warn | [auto-rotate] Failed to rotate key {uid} (owner={owner}): {e} | src/core/operations/auto_rotate.rs | uid, owner, e | - |
warn | [auto-rotate] Key {uid} not found; skipping | src/core/operations/auto_rotate.rs | uid | - |
info | [auto-rotate] Found {} key(s) due for rotation | src/core/operations/auto_rotate.rs | - | - |
info | [auto-rotate] Key {uid} (owner={owner}) rotation due in {days} day(s) (warning threshold: {threshold} days) | src/core/operations/auto_rotate.rs | uid, owner, days, threshold | - |
info | [auto-rotate] Key {uid} (owner={owner}, algo={algorithm}) rotated successfully | src/core/operations/auto_rotate.rs | uid, owner, algorithm | - |
debug | [auto-rotate] Failed to query keys for renewal warnings: {e} | src/core/operations/auto_rotate.rs | e | - |
debug | [auto-rotate] No keys due for rotation at {now} | src/core/operations/auto_rotate.rs | now | - |
debug | [auto-rotate] rotate_one_key returned: {e} | src/core/operations/auto_rotate.rs | e | - |
debug | [auto-rotate] Skipping HSM key {uid} | src/core/operations/auto_rotate.rs | uid | - |
debug | [auto-rotate] Skipping {uid}: object type {other:?} has no auto-rotation support | src/core/operations/auto_rotate.rs | uid, other | - |
debug | [auto-rotate] Skipping {uid}: PublicKey is rotated as part of its paired PrivateKey rotation | src/core/operations/auto_rotate.rs | uid | - |
debug | SetAttribute: implicitly enabling rotate_automatic for key '{}' (RotateInterval > 0 with no explicit RotateAutomatic) | src/core/operations/attributes/set.rs | - | - |
warn | Azure EKM JSON deserialization error: {err} | src/routes/azure_ekm/mod.rs | err | - |
warn | JWKS endpoint enabled — all active public keys with the "jwks" tag will be publicly exposed (unauthenticated) at `{kms_public_url}/.well-known/jwks.json`. Up to {} keys will be served. Ensure this is intentional. Configure via the `[jwks_endpoint]` section in the server configuration file. | src/start_kms_server.rs | kms_public_url | - |
warn | JWKS response truncated: more than {} eligible public keys found | src/routes/jwks.rs | - | - |
warn | Key uid={uid} found by Locate but missing on retrieve — skipping | src/routes/jwks.rs | uid | - |
warn | Skipping key uid={uid} from JWKS (conversion failed): {e} | src/routes/jwks.rs | uid, e | - |
info | GET /.well-known/jwks.json | src/routes/jwks.rs | - | - |
trace | DELETE /v1/crypto/keys/{kid}/tags | src/routes/jose/tags.rs | kid | - |
trace | GET /v1/crypto/keys/{kid}/tags | src/routes/jose/tags.rs | kid | - |
trace | JWKS key order is database insertion order — not stable across restarts or backends. Returning {} eligible key(s); consumers must match by `kid`, not position. | src/routes/jwks.rs | - | - |
trace | POST /v1/crypto/keys/{kid}/tags | src/routes/jose/tags.rs | kid | - |
error | Failed to serialize response to JSON: {e} | src/routes/kmip.rs | e | - |
info | http_workers not configured; defaulting to total core count ({total}) | src/start_kms_server.rs | total | - |
info | KMS HTTP server configured with {http_workers} worker thread(s) | src/start_kms_server.rs | http_workers | - |
debug | POST /kmip {}.{} Binary. Request: {:?} {} | src/routes/kmip.rs | - | - |
debug | POST /kmip {}.{} JSON. Request: {:?} {} | src/routes/kmip.rs | - | - |
debug | POST /kmip/2_1. Request: {:?} {} | src/routes/kmip.rs | - | - |
warn | JOSE CEK cache insert error for {uid}: {e} | src/routes/jose/cek_cache.rs | uid, e | - |
warn | JOSE CEK cache peek error for {uid}: {e} | src/routes/jose/cek_cache.rs | uid, e | - |
warn | JOSE CEK cache: failed to construct KMIP SymmetricKey: {e} | src/routes/jose/cek_cache.rs | e | - |
warn | JOSE CEK cache: unexpected CEK length {other} bytes — not an AES-128/192/256 key | src/routes/jose/cek_cache.rs | other | - |
warn | JOSE CEK cache: unexpected object type for {uid} | src/routes/jose/cek_cache.rs | uid | - |
debug | JOSE CEK cache hit for {uid} | src/routes/jose/cek_cache.rs | uid | - |
debug | JOSE CEK cached for {uid} | src/routes/jose/cek_cache.rs | uid | - |
debug | TLS: an authenticated user was already present; skipping certificate check | src/middlewares/tls_auth.rs | - | - |
cosmian_kms_server_database
Crate path: crate/server_database
RUST_LOG target: cosmian_kms_server_database
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
debug | Empty Redis database detected. Initializing a new database instance. | src/stores/redis/redis_with_findex.rs | - | - |
debug | Existing Redis database detected (version {version}). Using current database. | src/stores/redis/redis_with_findex.rs | version: version | - |
debug | Listed {} rows | src/stores/sql/mysql.rs | - | ×2 in this file |
debug | Owner = {} | src/stores/sql/mysql.rs | - | - |
debug | PG find query: {} | src/stores/sql/pgsql.rs | - | - |
debug | Uid = {} | src/stores/sql/mysql.rs | - | - |
trace | Created in DB: {uid} / {owner} | src/stores/sql/mysql.rs | uid — …owner — … | — |
trace | Deleted in DB: {uid} | src/stores/sql/mysql.rs | uid — … | — |
trace | find: tags: {tags:?} | src/stores/redis/redis_with_findex.rs | tags — … | — |
trace | find: uids before permissions: {:?} | src/stores/redis/redis_with_findex.rs | — | — |
trace | find: user must be owner | src/stores/redis/redis_with_findex.rs | — | — |
trace | find_: {:?} | src/stores/sql/mysql.rs | — | — |
trace | Insert read access right in DB: {uid} / {userid} | src/stores/sql/mysql.rs | uid — …userid — … | — |
trace | Invalidating the cache for {} | src/core/unwrapped_cache.rs | — | — |
trace | Redis DB size: {count} | src/stores/redis/redis_with_findex.rs | count — … | — |
trace | Updated in DB: {uid} | src/stores/sql/mysql.rs | uid — … | ×2 in this file |
trace | Upserted in DB: {uid} | src/stores/sql/mysql.rs | uid — … | — |
debug | [redis-bootstrap] skipping key {key}: {e} | src/stores/redis/objects_db.rs | key, e | ×2 in this file |
debug | [redis-metrics] reconcile: live_objects={live_count}, non_destroyed_keys={key_count} | src/stores/redis/redis_with_findex.rs | live_count, key_count | — |
debug | [redis-metrics] bootstrapped {} live object(s) into `{}` | src/stores/redis/redis_with_findex.rs | - | - |
debug | [redis-metrics] bootstrapped {} non-destroyed key(s) into `{}` | src/stores/redis/redis_with_findex.rs | - | - |
debug | [redis-scan-rotation] skipping key {key}: {e} | src/stores/redis/objects_db.rs | key, e | - |
warn | PostgreSQL BEGIN failed — retrying | src/stores/sql/pgsql.rs | attempt, delay_ms, error | - |
warn | PostgreSQL COMMIT failed — retrying | src/stores/sql/pgsql.rs | attempt, delay_ms, error | - |
warn | PostgreSQL pool error — retrying | src/stores/sql/pgsql.rs | attempt, delay_ms, error | - |
warn | PostgreSQL retryable error — retrying | src/stores/sql/pgsql.rs | attempt, delay_ms, error | - |
warn | PostgreSQL transaction body failed — retrying | src/stores/sql/pgsql.rs | attempt, delay_ms, error | - |
warn | wrapping_key_id backfill: skipping object that failed to deserialize | src/stores/sql/sqlite.rs | - | - |
warn | wrapping_key_id backfill: skipping object that failed to deserialize | src/stores/sql/pgsql.rs | - | - |
warn | wrapping_key_id backfill: skipping object {id} that failed to deserialize: {e} | src/stores/sql/mysql.rs | id, e | - |
debug | [redis-scan-wrapped] skipping key {key}: {e} | src/stores/redis/objects_db.rs | key, e | - |
cosmian_kms_crypto
Crate path: crate/crypto
RUST_LOG target: cosmian_kms_crypto
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
error | Error verifying ({:?}) signature: {:?}, data: {:?}, error: {err:?} | src/crypto/rsa/verify.rs | err: error detail | - |
error | Error verifying digest ({:?}) signature: {:?}, data: {:?}, error: {err:?} | src/crypto/rsa/verify.rs | err: error detail | ×2 in this file |
error | Error verifying raw ({:?}) signature: {:?}, data: {:?}, error: {err:?} | src/crypto/rsa/verify.rs | err: error detail | - |
warn | test_openssl_cli_compat: openssl CLI call failed, skipping test: {output:#?} | src/crypto/rsa/ckm_rsa_aes_key_wrap.rs | output: output | - |
warn | test_openssl_cli_compat: openssl CLI not found, skipping test | src/crypto/rsa/ckm_rsa_aes_key_wrap.rs | - | - |
warn | test_openssl_cli_compat: openssl CLI output is not valid UTF-8 | src/crypto/rsa/ckm_rsa_aes_key_wrap.rs | - | - |
info | ===> Wrapping asymmetric key with asymmetric key | src/crypto/wrap/tests.rs | - | - |
info | ===> Wrapping asymmetric key with symmetric key | src/crypto/wrap/tests.rs | - | - |
info | ===> Wrapping symmetric key with asymmetric key | src/crypto/wrap/tests.rs | - | - |
info | ===> Wrapping symmetric key with symmetric key | src/crypto/wrap/tests.rs | - | - |
info | value is: {:?} | src/openssl/x509_extensions.rs | - | ×2 in this file |
debug | attribute: {attribute:?}, encryption_hint: {encryption_hint:?} | src/crypto/cover_crypt/access_structure.rs | attribute: KMIP attribute (debug display)encryption_hint: encryption hint | - |
debug | create_dk_object: key len: {}, attributes: {attributes} | src/crypto/kem.rs | attributes: KMIP attribute (debug display)s | - |
debug | create_msk_object: key len: {}, attributes: {attributes} | src/crypto/cover_crypt/master_keys.rs | attributes: KMIP attribute (debug display)s | - |
debug | Decrypted data with user key {} of len (Plain/Enc): {}/{} | src/crypto/cover_crypt/decryption.rs | - | - |
debug | Encrypted data with auth data {:?} of len (Plain/Enc): {}/{} | src/crypto/cover_crypt/encryption.rs | - | - |
debug | RSA key pair generated: private key id: {private_key_uid} | src/crypto/rsa/operation.rs | private_key_uid: private key uid | - |
debug | RSA key pair generation: size in bits: {key_size_in_bits} | src/crypto/rsa/operation.rs | key_size_in_bits: RSA key size in bits | - |
debug | server: access_structure: {access_structure:?} | src/crypto/cover_crypt/master_keys.rs | access_structure: Covercrypt access structure | - |
debug | using GCM | src/crypto/wrap/wrap_key.rs | - | - |
debug | wrapping with CKM_RSA (v1.5) | src/crypto/wrap/wrap_key.rs | - | - |
debug | wrapping with CKM_RSA_AES_KEY_WRAP and hashing function: {hashing_fn} | src/crypto/wrap/wrap_key.rs | hashing_fn: hash function | - |
debug | wrapping with CKM_RSA_OAEP and hashing function: {hashing_fn} | src/crypto/wrap/wrap_key.rs | hashing_fn: hash function | - |
trace | Access Policy: {access_policy:?} | src/crypto/cover_crypt/user_key.rs | access_policy — … | — |
trace | authenticated_encryption_additional_data: {ad:?} | src/crypto/cover_crypt/encryption.rs | ad — … | — |
trace | bytes len: {:?}, bits: {} | src/crypto/elliptic_curves/operation.rs | — | ×2 in this file |
trace | bytes len: {}, bits: {} | src/crypto/rsa/operation.rs | — | ×2 in this file |
trace | ChaCha20 (pure) encryption: key_len={}, nonce_len={}, pt_len={} | src/crypto/symmetric/symmetric_ciphers.rs | — | — |
trace | Created user decryption key with access policy: {access_policy:?} | src/crypto/cover_crypt/user_key.rs | access_policy — … | — |
trace | decrypt: ad: {ad:?} | src/crypto/cover_crypt/decryption.rs | ad — … | — |
trace | Ed25519 | src/crypto/elliptic_curves/ecies/salsa_sealbox.rs | — | — |
trace | encrypted_bytes len: {} | src/crypto/cover_crypt/decryption.rs | — | — |
trace | encrypted_header parsed | src/crypto/cover_crypt/decryption.rs | — | — |
trace | encryption_policy: {ap:?} | src/crypto/cover_crypt/encryption.rs | ap — … | ×2 in this file |
trace | instantiate entering | src/crypto/cover_crypt/decryption.rs | — | — |
trace | Instantiated hybrid Covercrypt encipher for public key id: {public_key_uid} | src/crypto/cover_crypt/encryption.rs | public_key_uid — … | — |
trace | Key format type: convert Rsa<Public> openssl object | src/openssl/public_key.rs | — | — |
trace | Key format type: TransparentDSAPublicKey | src/openssl/public_key.rs | — | — |
trace | Key format type: TransparentRSAPublicKey | src/openssl/public_key.rs | — | — |
trace | key_wrapping_specification: {} | src/crypto/wrap/wrap_key.rs | — | — |
trace | nonce_len={}, tag_len={} | src/crypto/wrap/wrap_key.rs | — | — |
trace | output object: {output} | src/crypto/rsa/operation.rs | output — … | — |
trace | private key converted OK | src/crypto/elliptic_curves/operation.rs | — | — |
trace | public key converted OK | src/crypto/elliptic_curves/operation.rs | — | — |
trace | Refreshed user decryption key {usk:?} | src/crypto/cover_crypt/user_key.rs | usk — … | — |
trace | using RFC-3394 (AES Key Wrap, no padding) | src/crypto/wrap/wrap_key.rs | — | — |
trace | using RFC-5649 (AES Key Wrap with Padding) | src/crypto/wrap/wrap_key.rs | — | — |
trace | with object type: {:?} | src/crypto/wrap/wrap_key.rs | — | — |
trace | wrapping key: format={} | src/crypto/wrap/wrap_key.rs | — | — |
trace | X25519 | src/crypto/elliptic_curves/ecies/salsa_sealbox.rs | — | — |
trace | {} | src/openssl/public_key.rs | — | — |
warn | test_openssl_cli_compat: openssl version is not OpenSSL 3: {res}, skipping test | src/crypto/rsa/ckm_rsa_aes_key_wrap.rs | res | — |
info | \n\next: {:?} | src/openssl/x509_extensions.rs | — | ×2 in this file |
debug | Instantiated hybrid CoverCrypt decipher for user decryption key id: {user_decryption_key_uid} | src/crypto/cover_crypt/decryption.rs | user_decryption_key_uid | — |
debug | symmetric wrapping using {cryptographic_algorithm} and block_cipher_mode: {:?}, padding_method: {:?} | src/crypto/wrap/wrap_key.rs | cryptographic_algorithm | — |
trace | algorithm: {algorithm:?}, block_cipher_mode: {block_cipher_mode:?}, key_size: {key_size} | src/crypto/symmetric/symmetric_ciphers.rs | algorithm, block_cipher_mode, key_size | — |
trace | encrypt: sym_cipher: {sym_cipher:?}, key length: {}, nonce length: {}, aad length: {}, plaintext length: {}, padding_method: {padding_method:?} | src/crypto/symmetric/symmetric_ciphers.rs | sym_cipher, padding_method | — |
warn | ignored `basicConstraints` extension's value: {value} | src/openssl/x509_extensions.rs | value | - |
info | RFC 3394 is deprecated in favor of RFC 5649 and is supported only for legacy compatibility. Please consider using `BlockCipherMode::AESKeyWrapPadding` (RFC 5649) for new applications instead of `BlockCipherMode::NISTKeyWrap `. | src/crypto/symmetric/symmetric_ciphers.rs | - | ×2 in this file |
cosmian_kmip
Crate path: crate/kmip
RUST_LOG target: cosmian_kmip
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
warn | Custom attribute name does not start with 'x-' or 'y-': {} | src/kmip_1_4/kmip_attributes.rs | - | - |
warn | Failed to deserialize KMIP 2.1 attribute: {} | src/kmip_1_4/kmip_attributes.rs | - | - |
warn | KMIP 1.4 Lease Time ({v}) exceeds i32::MAX; clamping to {} | src/kmip_1_4/kmip_attributes.rs | v: parsed value | ×2 in this file |
warn | KMIP 2.1 does not support the KMIP 1 attribute {attribute:?} | src/kmip_1_4/kmip_attributes.rs | attribute: KMIP attribute (debug display) | ×9 in this file |
warn | Unexpected value type for y-unsupported-2_1-attribute: {:?} | src/kmip_1_4/kmip_attributes.rs | - | - |
debug | [serialize] writing tag: {} | src/ttlv/wire/ttlv_bytes_serializer.rs | - | - |
debug | Converting KMIP 2.1 QueryResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value: value | - |
trace | ... => This is an Object => identifier: key: Object | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... added a struct field: {key}, the parent struct is now: {:?} | src/ttlv/kmip_ttlv_serializer.rs | key — … | — |
trace | ... assuming deserialization of BigInteger: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... assuming deserialization of ByteString: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... coerced ShortUniqueIdentifier ByteString -> hex string: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... coerced {} Enumeration(code={}) -> string | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... coerced {} Enumeration(name={}) -> string | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... coerced {} Integer({}) -> string | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... deserializing an adjacently tagged structure | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... deserializing enum at root | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... deserializing enum that is the only child of the current element | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... deserializing transparent seq with tag: {tag} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | tag — … | — |
trace | ... detected VendorAttribute triple children; deserializing element itself as enum variant | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... enum: index: {:#x} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... enum: name: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... identifier: key: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... Seq element added, the current parent value is: {:?} | src/ttlv/kmip_ttlv_serializer.rs | — | — |
trace | ... str: key: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... structure recognized as byte-like; concatenated len={} for tag {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... structure: 1.4 Object | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... structure: 2.1 Object | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... structure: tag: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... tag: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ... text string: value: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | ===> KeyMaterial: Deserializing Bytes String for key format type: {:?} | src/kmip_2_1/kmip_data_structures.rs | — | ×2 in this file |
trace | ===> KeyMaterial: Deserializing key format type: {f:?} as struct | src/kmip_1_4/kmip_data_structures.rs | f — … | — |
trace | ===> KeyMaterial: Deserializing Structure for key format type: {f:?} | src/kmip_2_1/kmip_data_structures.rs | f — … | — |
trace | ===> KeyMaterial: Deserializing {:?} key format type as seq | src/kmip_1_4/kmip_data_structures.rs | — | — |
trace | ==> Deserializing KeyBlock | src/kmip_1_4/kmip_data_structures.rs | — | — |
trace | ==> Deserializing KeyBlock | src/kmip_2_1/kmip_data_structures.rs | — | — |
trace | array_access: next_element_seed in seq: {}, current index: {}, elem at index: {:?} | src/ttlv/kmip_ttlv_deserializer/array_deserializer.rs | — | — |
trace | Checking usage mask authorization {:?} for flag: {:?} | src/kmip_2_1/kmip_attributes.rs | — | — |
trace | Converting KMIP 2.1 CreateKeyPairResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 CreateResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 DecryptResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 DestroyResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 EncryptResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 GetAttributesResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 GetResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 ImportResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 LocateResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 RegisterResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | Converting KMIP 2.1 SignResponse to KMIP 1.4: {value} | src/kmip_1_4/kmip_operations.rs | value — … | — |
trace | current struct: {}, num children: {}, next child {:?} | src/ttlv/kmip_ttlv_deserializer/structure_walker.rs | — | — |
trace | deserialize_any of enum variant: name: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_any of enum variant: value: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_any value of BigInt: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_any value of Structure: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_any: map access state: key, tag: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_any: map access state: {:?}, index: {}, child: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_any: state: {:?} | src/ttlv/kmip_ttlv_deserializer/kmip_big_int_deserializer.rs | — | — |
trace | deserialize_bool: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_bytes: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_bytes_buff: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_char: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_enum: name {name}, element: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | name — … | — |
trace | deserialize_f32: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_f64: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_i128: element: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_i16 state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_i32: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_i64: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_identifier: map state: {:?}, element: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_ignored_any: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_map: calling Untagged Enum deserializer for: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_new_type_struct with name: {name}, state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | name — … | — |
trace | deserialize_option: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_seq: child index: {}: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_seq: state: {:?} | src/ttlv/kmip_ttlv_deserializer/kmip_big_int_deserializer.rs | — | — |
trace | deserialize_str: map state: {:?}, element tag: {} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_string: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_struct: name {name}, fields: {fields:?}, element: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | name — …fields — … | — |
trace | deserialize_tuple: child index: {}, current : {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_tuple: state: {:?} | src/ttlv/kmip_ttlv_deserializer/kmip_big_int_deserializer.rs | — | — |
trace | deserialize_tuple_struct: name: {name}, len: {len}, state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | name — …len — … | — |
trace | deserialize_u16: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_u32: state: {}: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_u64: state: {}: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_u8: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_unit: state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | — | — |
trace | deserialize_unit_struct with name: {name}, state: {:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | name — … | — |
trace | deserializing bytes string at tag: {}, of len: {} | src/ttlv/kmip_ttlv_deserializer/byte_string_deserializer.rs | — | — |
trace | deserializing OffsetDateTime at tag: {}, value: {}, index: {} | src/ttlv/kmip_ttlv_deserializer/offset_date_time_deserializer.rs | — | — |
trace | element: {:?} | src/ttlv/kmip_ttlv_deserializer/enum_walker.rs | — | — |
trace | element: {:?} | src/ttlv/kmip_ttlv_deserializer/structure_walker.rs | — | — |
trace | Finished serializing byte sequence as ByteString, parent: {:?} | src/ttlv/kmip_ttlv_serializer.rs | — | — |
trace | Finished serializing the sequence, the parent is: {:?} | src/ttlv/kmip_ttlv_serializer.rs | — | — |
trace | from_ttlv: {s:?} | src/ttlv/kmip_ttlv_deserializer/deserializer.rs | s — … | — |
trace | Key: State ? {:?} | src/ttlv/kmip_ttlv_deserializer/adjacently_tagged_structure.rs | — | — |
trace | key_wrap_type: {key_wrap_type:?}, attributes: {attributes} | src/kmip_2_1/requests/import.rs | key_wrap_type — …attributes — … | — |
trace | MessageBatchItem operation: {operation:?} | src/kmip_1_4/kmip_messages.rs | operation — … | — |
trace | MessageBatchItem operation: {operation:?} | src/kmip_2_1/kmip_messages.rs | operation — … | — |
trace | MessageBatchItem request payload: {request_payload} | src/kmip_1_4/kmip_messages.rs | request_payload — … | — |
trace | MessageBatchItem request payload: {request_payload} | src/kmip_2_1/kmip_messages.rs | request_payload — … | — |
trace | MessageResponseBatchItem operation: {operation:?} | src/kmip_1_4/kmip_messages.rs | operation — … | — |
trace | MessageResponseBatchItem operation: {operation:?} | src/kmip_2_1/kmip_messages.rs | operation — … | — |
trace | MessageResponseBatchItem response payload: {response_payload} | src/kmip_1_4/kmip_messages.rs | response_payload — … | — |
trace | MessageResponseBatchItem response payload: {response_payload} | src/kmip_2_1/kmip_messages.rs | response_payload — … | — |
trace | newtype_variant_seed: child index: {}, at root: {}, current tag: {:?} | src/ttlv/kmip_ttlv_deserializer/enum_walker.rs | — | — |
trace | Not a BulkData | src/kmip_2_1/extra/bulk_data.rs | — | — |
trace | Object Visitor: visit_map: key: {key:?}, | src/kmip_1_4/kmip_objects.rs | key — … | — |
trace | Object Visitor: visit_map: key: {key:?}, | src/kmip_2_1/kmip_objects.rs | key — … | — |
trace | Seq Element: serializing a seq element with tag {}, stack is: {:?} | src/ttlv/kmip_ttlv_serializer.rs | — | — |
trace | seq_access: next_element_seed: state: {:?} | src/ttlv/kmip_ttlv_deserializer/kmip_big_int_deserializer.rs | — | — |
trace | serialize_map of len: {len:?}. Current: {:?} | src/ttlv/kmip_ttlv_serializer.rs | len — … | — |
trace | serialize_newtype_variant, name: {name}::{variant} (variant index: {variant_index}) | src/ttlv/kmip_ttlv_serializer.rs | name — …variant — …variant_index — … | — |
trace | serialize_seq of len: {len:?} in receiver: {:?} | src/ttlv/kmip_ttlv_serializer.rs | len — … | — |
trace | serialize_seq of len: {len:?} in receiver: {:?} (byte accumulation mode) | src/ttlv/kmip_ttlv_serializer.rs | len — … | — |
trace | serialize_struct named: {name} in parent: {:?} | src/ttlv/kmip_ttlv_serializer.rs | name — … | — |
trace | serialize_struct, no parent found, creating a new one with tag: {} | src/ttlv/kmip_ttlv_serializer.rs | — | — |
trace | serialize_tuple of len {len}. Current: {:?} | src/ttlv/kmip_ttlv_serializer.rs | len — … | — |
trace | serialize_tuple_struct {name} of len {len}. Current: {:?} | src/ttlv/kmip_ttlv_serializer.rs | name — …len — … | — |
trace | serialize_unit_variant, name: {name}::{variant}; variant_index: {variant_index} | src/ttlv/kmip_ttlv_serializer.rs | name — …variant — …variant_index — … | — |
trace | serializing a struct field with name: {key}, stack: {:?} | src/ttlv/kmip_ttlv_serializer.rs | key — … | — |
trace | struct_variant with fields: {fields:?}: state: {:?} | src/ttlv/kmip_ttlv_deserializer/enum_walker.rs | fields — … | — |
trace | Structure finalized, stack: {:?} | src/ttlv/kmip_ttlv_serializer.rs | — | — |
trace | tag: {:?}, content: {:?} | src/ttlv/kmip_ttlv_deserializer/adjacently_tagged_structure.rs | — | — |
trace | tuple_variant of len: {len}, child index: {}, current: {:?} | src/ttlv/kmip_ttlv_deserializer/enum_walker.rs | len — … | — |
trace | unique_identifier: {unique_identifier} | src/kmip_2_1/requests/import.rs | unique_identifier — … | — |
trace | unit_variant: child index: {}, current: {:?} | src/ttlv/kmip_ttlv_deserializer/enum_walker.rs | — | — |
trace | Untagged Enum map: next_value_seed: current tag: {:?}, at root: {} | src/ttlv/kmip_ttlv_deserializer/untagged_enum_walker.rs | — | — |
trace | Value: State ? {:?} | src/ttlv/kmip_ttlv_deserializer/adjacently_tagged_structure.rs | — | — |
trace | visit_f64: {} | src/ttlv/deserialize.rs | — | — |
trace | visit_i64: {} | src/ttlv/deserialize.rs | — | — |
trace | visit_map: Enumeration | src/ttlv/deserialize.rs | — | — |
trace | visit_str: {} | src/ttlv/deserialize.rs | — | — |
trace | visit_u64: {} | src/ttlv/deserialize.rs | — | — |
trace | ... replacing "Object" with: {name} | src/ttlv/kmip_ttlv_serializer.rs | name | |
trace | serialize_seq, no parent found. This is a direct vec![] serialization. Creating a new one with tag: {} | src/ttlv/kmip_ttlv_serializer.rs | — | — |
trace | serialize_struct_variant {name}::{variant} (variant index: {variant_index}) of len {len}. Current: {:?} | src/ttlv/kmip_ttlv_serializer.rs | name, variant, variant_index, len | — |
trace | serialize_tuple_variant {name}::{variant} (variant index: {variant_index}) of len {len}. Current: {:?} | src/ttlv/kmip_ttlv_serializer.rs | name, variant, variant_index, len | — |
trace | Untagged Enum map: next_key_seed: completed?: {}, at root: {}, index: {}, current tag: {:?} | src/ttlv/kmip_ttlv_deserializer/untagged_enum_walker.rs | — | — |
cosmian_kms_interfaces
Crate path: crate/interfaces
RUST_LOG target: cosmian_kms_interfaces
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
error | Failed to decode object_id {} | src/hsm/hsm_store.rs | - | Malformed object ID in PKCS#11 session. Key may have been created by a different client. |
debug | Created HSM AES Key of length {key_length} with id {uid} | src/hsm/hsm_store.rs | key_length: key lengthuid: KMIP object UID | - |
debug | Creating RSA keypair with uid: {uid} | src/hsm/hsm_store.rs | uid: KMIP object UID | - |
debug | HSM find: incompatible filter, skipping HSM search: {e} | src/hsm/hsm_store.rs | e: caught error | - |
debug | Is {owner} an HSM admin? {} | src/hsm/hsm_store.rs | owner: object owner identity | - |
debug | No researched_attributes provided. Defaulting to empty filter attributes | src/hsm/hsm_store.rs | - | - |
debug | sign: using algorithm {algorithm:?} for key {uid} | src/hsm/hsm_store.rs | algorithm: cryptographic algorithmuid: KMIP object UID | - |
debug | User '{}' is not an HSM admin; skipping HSM keys for ownership query | src/hsm/hsm_store.rs | - | - |
debug | Using default algorithm to decrypt | src/hsm/hsm_store.rs | - | - |
debug | Using default algorithm to encrypt | src/hsm/hsm_store.rs | - | - |
debug | {e} | src/hsm/hsm_store.rs | e: caught error | - |
trace | Found: {uid} | src/hsm/hsm_store.rs | uid — … | — |
trace | Getting metadata for: {:02X?} | src/hsm/hsm_store.rs | — | — |
warn | count_all_non_destroyed not implemented for this ObjectsStore backend — kms.objects.total will read 0 until a real implementation is provided | src/stores/objects_store.rs | — | — |
warn | count_non_destroyed_keys not implemented for this ObjectsStore backend — kms.keys.active.count will read 0 until a real implementation is provided | src/stores/objects_store.rs | — | — |
warn | HSM count_non_destroyed_keys: failed to list slots: {e} | src/hsm/hsm_store.rs | e | — |
warn | ModifyAttribute/SetAttribute on HSM key {uid}: attribute update accepted but not persisted to PKCS#11 slot (HSM does not support KMIP attribute storage) | src/hsm/hsm_store.rs | uid | — |
debug | encrypt: an RSA private key {uid} was specified. Trying to use public key {pk_uid} for encryption | src/hsm/hsm_store.rs | uid, pk_uid | — |
debug | HSM count_non_destroyed_keys: slot {slot_id} query failed: {e} | src/hsm/hsm_store.rs | slot_id, e | — |
debug | HSM key {uid} export failed ({e}); falling back to metadata-only stub for attribute operations | src/hsm/hsm_store.rs | uid, e | — |
cosmian_kms_access
Crate path: crate/access
RUST_LOG target: cosmian_kms_access
No production log call-sites in this crate.
cosmian_kms_base_hsm
Crate path: crate/hsm/base_hsm
RUST_LOG target: cosmian_kms_base_hsm
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
warn | HSM library already initialized (CKR_CRYPTOKI_ALREADY_INITIALIZED); continuing | src/hsm_lib.rs | - | - |
warn | user already logged in, ignoring logging | src/slots.rs | - | - |
debug | Creating new session: {session_handle}. Logging in? {logging_in} | src/session/session_impl.rs | session_handle: session handlelogging_in: logging in | - |
debug | Found {} possible handles | src/session/session_impl.rs | - | - |
debug | Invalid object, skipping | src/kms_hsm.rs | - | - |
debug | Logging in session {session_handle} with password | src/slots.rs | session_handle: session handle | - |
debug | Opening a session on slot: {slot_id}. Read write? {read_write}. Logging in? {} | src/slots.rs | slot_id: PKCS#11 slot identifierread_write: read write | - |
debug | Performing multi round AES CBC decryption | src/session/session_impl.rs | - | - |
debug | Performing multi round AES CBC encryption | src/session/session_impl.rs | - | - |
debug | Retrieved HSM key type for key handle {key_handle}: {key_type:?} | src/session/session_impl.rs | key_handle: key handlekey_type: key type | - |
debug | Retrieving HSM key attributes for key handle: {key_handle} | src/session/session_impl.rs | key_handle: key handle | - |
debug | Reusing slot {slot_id} | src/base_hsm.rs | slot_id: PKCS#11 slot identifier | - |
debug | Using PKCS#11 library with {:?} | src/base_hsm.rs | - | - |
trace | Doing round with {round_length} bytes. {processed_length} of {total_length} done | src/session/session_impl.rs | round_length — …processed_length — …total_length — … | ×2 in this file |
trace | Found {object_count} objects | src/session/session_impl.rs | object_count — … | — |
debug | OAEP hash {hash} not supported: {e} | src/session/session_impl.rs | hash, e | - |
Domain: CLI (ckms)
cosmian_kms_cli_actions
Crate path: crate/clients/clap
RUST_LOG target: cosmian_kms_cli_actions
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
info | [{email}] - certificate ID used: {certificate_unique_identifier} | src/actions/google/key_pairs/create.rs | email: Google Workspace user emailcertificate_unique_identifier: KMS UID of the certificate | - |
info | [{email}] - Import PKCS12 file before using it in Google key pair generation | src/actions/google/key_pairs/create.rs | email: Google Workspace user email | - |
info | ModifyAttributes response for {effective_uid}: {attribute} | src/actions/attributes/modify.rs | effective_uid: resolved KMIP object UIDattribute: updated attribute name and value | - |
info | SetAttributes response for {unique_identifier}: {attribute} | src/actions/attributes/set.rs | unique_identifier: KMIP object UIDattribute: attribute name and value that was set | - |
debug | {decrypt_request} | src/actions/cover_crypt/decrypt.rs | decrypt_request: full Covercrypt decrypt request (debug display) | - |
debug | {encrypt_request} | src/actions/cover_crypt/encrypt.rs | encrypt_request: full Covercrypt encrypt request (debug display) | - |
debug | access_structure: {access_structure} | src/actions/cover_crypt/keys/create_key_pair.rs | access_structure: Covercrypt access structure (debug display) | - |
debug | Creating new leaf certificate with attributes: {attributes} | src/actions/google/key_pairs/create.rs | attributes: X.509 certificate attributes being submitted | - |
debug | GetAttributes response for {unique_identifier}: {attributes} | src/actions/attributes/get.rs | unique_identifier: KMIP object UIDattributes: structured attributes response | - |
debug | import certificate as {format_label} file | src/actions/certificates/import_certificate.rs | format_label: certificate format name (e.g. PEM, DER) | - |
debug | import certificate as PKCS12 file | src/actions/certificates/import_certificate.rs | - | - |
debug | import certificate chain as PEM file | src/actions/certificates/import_certificate.rs | - | - |
trace | {self} | src/actions/attributes/delete.rs | self — full delete action configuration (debug display) | — |
trace | {self} | src/actions/attributes/get.rs | self — full get-attributes action configuration (debug display) | — |
trace | {self} | src/actions/attributes/modify.rs | self — full modify action configuration (debug display) | — |
trace | {self} | src/actions/attributes/set.rs | self — full set-attributes action configuration (debug display) | — |
trace | {self} | src/actions/certificates/export_certificate.rs | self — full export action configuration (debug display) | — |
trace | {self} | src/actions/certificates/import_certificate.rs | self — full import action configuration (debug display) | — |
trace | {id} | src/actions/shared/get_key_uid.rs | id — resolved KMIP object UID | — |
trace | data_encryption_algorithm: {data_encryption_algorithm} | src/actions/symmetric/encrypt.rs | data_encryption_algorithm — selected symmetric encryption algorithm | — |
trace | Determine the certificate to use - either existing or newly created | src/actions/google/key_pairs/create.rs | — | — |
trace | import certificate as TTLV JSON file | src/actions/certificates/import_certificate.rs | — | — |
trace | response for {unique_identifier}: <none> | src/actions/attributes/delete.rs | unique_identifier — KMIP object UID (no attribute was present) | — |
trace | unwrap using server-side HSM crypto oracle for key: {key_id} | src/actions/shared/unwrap_key.rs | key_id — UID of the key being unwrapped via the HSM crypto oracle | — |
info | [{email}] - Generating new leaf certificate with extensions file: {:?} | src/actions/google/key_pairs/create.rs | email | — |
debug | GetAttributes response for {unique_identifier}: {} | src/actions/attributes/get.rs | unique_identifier | — |
debug | MoveFileExW(DELAY_UNTIL_REBOOT) failed for '{}'; leftover file is harmless. | src/actions/cng.rs | — | — |
trace | dek (len={}): {dek:?} | src/actions/symmetric/encrypt.rs | dek | — |
trace | dek length {} | src/actions/symmetric/decrypt.rs | — | ×2 in this file |
trace | encapsulation length {} | src/actions/symmetric/decrypt.rs | — | — |
trace | encryption algorithm {:?}, key id {:?}, ciphertext (len={}): {:?} | src/actions/symmetric/decrypt.rs | — | — |
trace | Leaf certificate attributes: {} | src/actions/certificates/import_certificate.rs | — | — |
trace | pkcs7_object: {:?} | src/actions/google/key_pairs/create.rs | — | — |
trace | response for {unique_identifier}: {} | src/actions/attributes/delete.rs | unique_identifier | — |
trace | wrapped_key_bytes: {:?} | src/actions/google/key_pairs/create.rs | — | — |
ckms
Crate path: crate/clients/ckms
RUST_LOG target: ckms
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
info | Starting KMS CLI | src/commands.rs | - | - |
info | Starting KMS CLI configuration wizard | src/commands.rs | - | - |
debug | Loading configuration from: {conf_path_buf} | src/config.rs | conf_path_buf: filesystem path of the configuration file being loaded | - |
trace | Configuration: {config} | src/commands.rs | config — full resolved CLI configuration (pretty debug display) | — |
info | Configuration saved at {} | src/commands.rs | — | — |
cosmian_kms_client
Crate path: crate/clients/client
RUST_LOG target: cosmian_kms_client
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
info | GET {server_url} | src/kms_rest_client.rs | server_url: full URL of the GET request being sent | - |
info | The decrypted file is available at {output_file} | src/file_utils.rs | output_file: path to the decrypted output file | ×2 in this file |
info | The encrypted file is available at {output_file} | src/file_utils.rs | output_file: path to the encrypted output file | ×2 in this file |
info | Using server URL: {} | src/http_client/client.rs | — | — |
trace | <==\n{} | src/kms_rest_client.rs | — | ×2 in this file |
trace | ==>\n{} | src/kms_rest_client.rs | — | ×2 in this file |
warn | Failed to set TLS 1.2 cipher list '{}' (using defaults): {} | src/http_client/tls.rs | — | — |
warn | Failed to set TLS 1.3 ciphersuites '{}' (using defaults): {} | src/http_client/tls.rs | — | — |
warn | Unknown TLS 1.2 IANA cipher suite '{}' (skipping) | src/http_client/tls.rs | — | — |
info | Using proxy: {:?} | src/http_client/client.rs | — | — |
debug | CONNECT tunnel established: {target_host}:{target_port} | src/http_client/proxy.rs | target_host, target_port | — |
debug | CONNECT tunnel: {proxy_addr} → {target_host}:{target_port} | src/http_client/proxy.rs | proxy_addr, target_host, target_port | — |
trace | Error response on {endpoint}: status={status}, body={text} | src/kms_rest_client.rs | endpoint, status, text | — |
warn | ckms config: `{}` is deprecated — rename it to `{}` in your ckms.toml to silence this warning. | src/http_client/client.rs | - | - |
cosmian_kms_client_utils
Crate path: crate/clients/client_utils
RUST_LOG target: cosmian_kms_client_utils
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
info | WARNING: the PEM file contains multiple objects. Only the private key will be imported. A corresponding public key will be generated automatically. | src/import_utils.rs | — | — |
Domain: PKCS#11
cosmian_pkcs11
Crate path: crate/clients/pkcs11/provider
RUST_LOG target: cosmian_pkcs11
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
error | C_GetFunctionList: failed to instantiate base KMS client: {} | src/lib.rs | - | PKCS#11 module failed to create the KMS client on load. Check server URL and auth in ckms.toml. |
error | Failed to parse EC P256 public key: {:?} | src/pkcs11_public_key.rs | - | HSM returned a malformed EC P256 key. Verify key generation parameters. |
error | Failed to parse RSA private key: {:?} | src/pkcs11_private_key.rs | - | - |
error | Failed to parse RSA public key: {:?} | src/pkcs11_public_key.rs | - | - |
error | Public key is not an EC P256 key | src/pkcs11_private_key.rs | - | - |
error | Public key is not an EC P256 key | src/pkcs11_public_key.rs | - | - |
error | Public key is not an RSA key | src/pkcs11_public_key.rs | - | - |
error | remote_sign failed for Pkcs11PrivateKey with remote_id {}: {e} | src/pkcs11_private_key.rs | e: caught error | Remote signing via PKCS#11 failed. Check KMS connectivity and key permissions. |
error | Unsupported cryptographic algorithm: {:?} | src/kms_object.rs | - | - |
error | Unsupported key algorithm: {:?} | src/kms_object.rs | - | - |
error | verify not implemented for Pkcs11PublicKey | src/pkcs11_public_key.rs | - | - |
warn | create_private_key_from_id: {id} has type {:?} (expected PrivateKey), skipping | src/backend.rs | id: object ID | - |
warn | create_symmetric_key_from_id: {id} has type {:?} (expected SymmetricKey), skipping | src/backend.rs | id: object ID | - |
debug | decrypt: decrypt_ctx: {ctx:?} | src/backend.rs | ctx: ctx | - |
debug | encrypt: ctx: {ctx:?} | src/backend.rs | ctx: ctx | - |
debug | kms_encrypt_async: ciphertext: {} | src/kms_object.rs | - | - |
debug | kms_import_object_async: label: {label}, data (length): {} | src/kms_object.rs | label: label | - |
debug | Locate response: ids: {:?} | src/kms_object.rs | - | - |
debug | Located objects: tags: {tags:?}, type: {object_type:?} => {uniques_identifiers:?} | src/kms_object.rs | tags: KMIP tag setobject_type: KMIP object typeuniques_identifiers: uniques identifiers | - |
debug | remote_sign: remote_id: {remote_id}, algorithm: {algorithm:?} | src/backend.rs | remote_id: remote idalgorithm: cryptographic algorithm | - |
debug | vol1: {} | src/tests.rs | - | - |
trace | create_object: {label:?} | src/backend.rs | label — … | — |
trace | find_all_certificates | src/backend.rs | — | — |
trace | find_all_data_objects: entering | src/backend.rs | — | — |
trace | find_all_data_objects: found {} objects | src/backend.rs | — | — |
trace | find_all_objects: entering | src/backend.rs | — | — |
trace | find_all_objects: found {} keys | src/backend.rs | — | — |
trace | find_all_private_keys | src/backend.rs | — | — |
trace | find_all_public_keys | src/backend.rs | — | — |
trace | find_all_symmetric_keys | src/backend.rs | — | — |
trace | find_certificate | src/backend.rs | — | — |
trace | find_data_object: {:?} | src/backend.rs | — | — |
trace | find_private_key: {:?} | src/backend.rs | — | — |
trace | find_public_key: {:?} | src/backend.rs | — | — |
trace | find_symmetric_key: {:?} | src/backend.rs | — | — |
trace | Found {} objects | src/kms_object.rs | — | — |
trace | generate_key: {algorithm:?}-{key_length}, {label:?} | src/backend.rs | algorithm — …key_length — …label — … | — |
trace | get_kms_certificate_objects_async: found {} Certificate objects | src/kms_object.rs | — | — |
trace | get_kms_certificate_objects_async: no Certificate objects found for tags: {:?} | src/kms_object.rs | — | — |
trace | get_kms_objects_async: no objects found for tags: {:?} | src/kms_object.rs | — | — |
trace | get_kms_secret_data_objects_async: found {} SecretData objects | src/kms_object.rs | — | — |
trace | get_kms_secret_data_objects_async: no SecretData objects found for tags: {:?} | src/kms_object.rs | — | — |
error | C_GetFunctionList: failed to instantiate KMS client: {}. Check that ckms.toml exists alongside the DLL (C:\opt\oracle\extapi\64\pkcs11\ckms.toml), at ~/.cosmian/ckms.toml, or set CKMS_CONF to its path. | src/lib.rs | — | |
error | C_GetFunctionList: failed to load ckms.toml: {}. Check that ckms.toml exists alongside the DLL (C:\opt\oracle\extapi\64\pkcs11\ckms.toml), at ~/.cosmian/ckms.toml, or set CKMS_CONF to its path. | src/lib.rs | — | |
warn | create_object_from_attributes: unsupported object type: {other}, skipping {id} | src/backend.rs | other, id | — |
warn | create_private_key_from_id: unsupported key/algorithm for PrivateKey {id}: {e}, skipping | src/backend.rs | id, e | — |
warn | create_private_key_object: unsupported key/algorithm for PrivateKey {id}: {e}, skipping | src/backend.rs | id, e | — |
warn | create_public_key_object: unsupported key/algorithm for PublicKey {id}: {e}, skipping | src/backend.rs | id, e | — |
warn | create_symmetric_key_from_id: unsupported key/algorithm for SymmetricKey {id}: {e}, skipping | src/backend.rs | id, e | — |
warn | create_symmetric_key_object: unsupported key/algorithm for SymmetricKey {id}: {e}, skipping | src/backend.rs | id, e | — |
warn | find_all_public_keys: failed to build Pkcs11PublicKey for {id}: {e}, skipping | src/backend.rs | id, e | — |
warn | find_all_public_keys: failed to export public key {id}: {e}, skipping | src/backend.rs | id, e | — |
warn | find_all_data_objects: failed to build DataObject for disk-encryption key: {e}, skipping | src/backend.rs | e | — |
warn | find_all_data_objects: failed to fetch disk-encryption data objects: {e}, returning empty list | src/backend.rs | e | — |
warn | find_all_objects: failed to build DataObject for disk-encryption key: {e}, skipping | src/backend.rs | e | — |
warn | find_all_objects: failed to fetch disk-encryption data objects: {e}, returning empty list | src/backend.rs | e | — |
trace | find_all_objects: total {} objects (including disk-encryption DataObjects) | src/backend.rs | — | — |
trace | get_kms_disk_encryption_data_objects_async: found {} SymmetricKey objects | src/kms_object.rs | — | — |
trace | get_kms_disk_encryption_data_objects_async: no SymmetricKey objects found for tag: {disk_encryption_tag} | src/kms_object.rs | disk_encryption_tag | — |
cosmian_pkcs11_module
Crate path: crate/clients/pkcs11/module
RUST_LOG target: cosmian_pkcs11_module
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
error | C_GetAttributeValue: error: {e}, session: {:?}, object: {:?}, type: {:?} | src/pkcs11.rs | e: caught error | - |
error | certificate: type_ unimplemented: {type_:?} | src/core/object.rs | type_: type | - |
error | Data object: type_ unimplemented: {type_:?} | src/core/object.rs | type_: type | - |
error | Failed to extract RSA key parameters: {e:?} | src/core/object.rs | e: caught error | - Could not read RSA key components from HSM object. Key may be non-exportable. |
error | Failed to parse RSA private key from PKCS#8 DER: {e:?} | src/core/object.rs | e: caught error | - HSM returned a malformed RSA PKCS#8 blob. Check HSM firmware and key type. |
error | pParameter incorrect: {} != {} | src/core/mechanism.rs | - | PKCS#11 mechanism parameter size mismatch. Client sent the wrong parameter struct. |
error | private_key: type_ unimplemented: {type_:?} | src/core/object.rs | type_: type | - |
error | profile: type_ unimplemented: {type_:?} | src/core/object.rs | type_: type | - |
error | public_key: type_ unimplemented: {type_:?} | src/core/object.rs | type_: type | - |
error | symmetric_key: type_ unimplemented: {type_:?} | src/core/object.rs | type_: type | - |
error | Unsupported hashAlg: {} | src/core/mechanism.rs | - | PKCS#11 hash algorithm not supported. Use SHA-256 or SHA-384. |
error | Unsupported mgf: {} | src/core/mechanism.rs | - | PKCS#11 MGF algorithm not supported. Use MGF1 with a supported hash. |
error | {}: {} | src/pkcs11.rs | - | Generic two-part error - inspect both values for the error type and detail. |
warn | load_find_context: id {label} not found in store | src/sessions.rs | label: label | - |
info | C_CloseAllSessions: slot: {:?} | src/pkcs11.rs | - | - |
info | C_CloseSession: session: {:?} | src/pkcs11.rs | - | - |
info | C_FindObjects: session: {:?}, no more objects to return | src/pkcs11.rs | - | - |
info | C_FindObjects: session: {:?}, returning {} object with handles {:?} | src/pkcs11.rs | - | - |
info | C_GetAttributeValue: session: {:?}, object: {:?} [handle: {}], type: {:?} | src/pkcs11.rs | - | - |
info | C_OpenSession: slot={slotID:?} flags={flags:?} session handle written | src/pkcs11.rs | slotID: slotIDflags: flags | - |
debug | C_DestroyObject: session: {hSession:?}, hObject: {hObject} | src/pkcs11.rs | hSession: hSessionhObject: hObject | - |
debug | CKO_DATA match: remote_id={}, handle={} | src/sessions.rs | - | - |
debug | CKO_DATA search: label_filter={:?}, store has {} DataObjects | src/sessions.rs | - | - |
debug | create_object: attributes: {attributes:?} | src/sessions.rs | attributes: KMIP attribute (debug display)s | - |
debug | create_object: created object with handle: {handle} | src/sessions.rs | handle: PKCS#11 object handle | - |
debug | destroy_object: handle: {handle} | src/sessions.rs | handle: PKCS#11 object handle | ×2 in this file |
debug | generate_key: generated key with handle: {handle} | src/sessions.rs | handle: PKCS#11 object handle | - |
debug | generate_key: generating key with mechanism: {:?} and attributes: {:?} | src/sessions.rs | - | - |
debug | load_find_context: display current store: {find_ctx} | src/sessions.rs | find_ctx: find ctx | - |
debug | load_find_context: loading for label: {label:?} and attributes: {attributes:?} | src/sessions.rs | label: labelattributes: KMIP attribute (debug display)s | - |
debug | load_find_context: search by id: {label} -> handle: {} -> object: {}: {} | src/sessions.rs | label: label | - |
debug | load_find_context_by_class: added {} objects with handles: {:?} | src/sessions.rs | - | - |
debug | map_oracle_tde_security_to_mk: processing label: {label} | src/sessions.rs | label: label | - |
debug | Object: {}, attribute: {:?} => {:?} | src/core/object.rs | - | - |
debug | parse_mechanism: iv: {iv:?} | src/core/mechanism.rs | iv: iv | - |
debug | parse_mechanism: {mechanism:?} | src/core/mechanism.rs | mechanism: PKCS#11 mechanism | - |
debug | session: {h} found | src/sessions.rs | h: h | - |
debug | STORE: inserting new object with remote id: {id} and handle: {handle} | src/objects_store.rs | id: object IDhandle: PKCS#11 object handle | - |
debug | STORE: updating object with remote id: {id} and handle: {handle} | src/objects_store.rs | id: object IDhandle: PKCS#11 object handle | - |
trace | Attribute::try_from: attribute parsed: {:?} => {:?} | src/core/attribute.rs | — | — |
trace | Attribute::try_from: parsing attribute: {:?} | src/core/attribute.rs | — | — |
trace | Attribute::try_from: type: {attr_type:?} | src/core/attribute.rs | attr_type — … | — |
trace | Attribute::try_from: value: {val:?} | src/core/attribute.rs | val — … | — |
trace | Attributes::try_from: parsing single attribute: {attr:?} | src/core/attribute.rs | attr — … | — |
trace | C_FindObjects: session: {:?}, objects available: {:?} | src/pkcs11.rs | — | — |
trace | C_GetAttributeValue: session: {:?}, object: {:?} | src/pkcs11.rs | — | — |
trace | C_GetSessionInfo: session: {:?}, slot: {:?}, state: {:?}, flags: {:?} | src/pkcs11.rs | — | — |
trace | create_object: class: {class:?} | src/sessions.rs | class — … | — |
trace | create_object: Object not supported: {o} | src/sessions.rs | o — … | — |
trace | Generated random: {} | src/pkcs11.rs | — | — |
trace | load_find_context succeeded | src/sessions.rs | — | — |
info | C_FindObjectsInit: session: {hSession:?}, load Objects Store context for attributes: {attributes:?} | src/pkcs11.rs | hSession, attributes | — |
debug | C_CreateObject: session: {hSession:?}, pTemplate: {pTemplate:?}, ulCount: {ulCount:?}, phObject: {phObject:?} | src/pkcs11.rs | hSession, pTemplate, ulCount, phObject | — |
debug | C_Decrypt: pEncryptedData: {pEncryptedData:?}, ulEncryptedDataLen: {ulEncryptedDataLen:?}, pData: {pData:?}, pulDataLen: {pulDataLen:?} | src/pkcs11.rs | pEncryptedData, ulEncryptedDataLen, pData, pulDataLen | — |
debug | C_Decrypt: session: {:?}, encrypted_data_len: {:?}, cleartext_len: {:?}, ciphertext: {:?} | src/pkcs11.rs | — | — |
debug | C_DecryptInit: session: {hSession:?}, hKey: {hKey:?}, mechanism: {mechanism:?}, object: {object:?} | src/pkcs11.rs | hSession, hKey, mechanism, object | — |
debug | C_Encrypt: pData: {pData:?}, ulDataLen: {ulDataLen:?}, pEncryptedData: {pEncryptedData:?}, pulEncryptedDataLen: {pulEncryptedDataLen:?} | src/pkcs11.rs | pData, ulDataLen, pEncryptedData, pulEncryptedDataLen | — |
debug | C_Encrypt: session: {:?}, plain_data_len: {:?}, ciphertext_len: {:?}, cleartext: {:?} | src/pkcs11.rs | — | — |
debug | C_EncryptInit: session: {hSession:?}, hKey: {hKey:?}, mechanism: {mechanism:?}, object: {object:?} | src/pkcs11.rs | hSession, hKey, mechanism, object | — |
debug | C_GenerateKey: session: {hSession:?}, pMechanism: {pMechanism:?}, pTemplate: {pTemplate:?}, ulCount: {ulCount:?}, phKey: {phKey:?} | src/pkcs11.rs | hSession, pMechanism, pTemplate, ulCount, phKey | — |
debug | load_find_context_by_class: loading for class: {search_class:?} and options: {search_options:?}, attributes: {attributes:?} | src/sessions.rs | search_class, search_options, attributes | — |
debug | load_find_context_by_class: search by id: {} -> handle: {} -> certificate: {}:{} | src/sessions.rs | — | — |
debug | load_find_context_by_class: search by id: {} -> handle: {} -> object: {}:{} | src/sessions.rs | — | — |
Domain: CNG (Windows)
cosmian_cng
Crate path: crate/clients/cng
RUST_LOG target: cosmian_cng
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
error | CNG KSP decrypt: {e} | src/provider.rs | e: caught error | Decryption via CNG failed. Check key state and CNG provider logs. |
error | CNG KSP delete_key: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP encrypt: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP enum_keys: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP export_key private: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP export_key: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP finalize_key: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP import_key attrs: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP import_key backend: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP import_key parse blob: {e} | src/provider.rs | e: caught error | - |
error | CNG KSP open_key attrs({name}): {e} | src/provider.rs | name: key or object namee: caught error | - |
error | CNG KSP open_key pub({name}): {e} | src/provider.rs | name: key or object namee: caught error | - |
error | CNG KSP open_key({name}): {e} | src/provider.rs | name: key or object namee: caught error | - |
error | CNG KSP open_provider: {e} | src/provider.rs | e: caught error | CNG provider DLL failed to load or initialise. Verify the DLL is registered. |
error | CNG KSP sign_hash: {e} | src/provider.rs | e: caught error | Signing via CNG failed. Key may be non-exportable or in an invalid state. |
error | CNG KSP verify_signature: {e} | src/provider.rs | e: caught error | - |
info | CNG KSP provider already registered; skipping BCryptRegisterProvider | src/registry.rs | - | - |
info | DLL was locked; old copy renamed to '{}' and scheduled for deletion on reboot. | src/registry.rs | - | - |
debug | BCryptAddContextFunction returned {status:#010x} (may already exist) | src/registry.rs | status: HTTP response status | - |
debug | BCryptRemoveContextFunctionProvider returned {status:#010x} | src/registry.rs | status: HTTP response status | - |
debug | CNG KSP GetKeyStorageInterface called | src/lib.rs | - | - |
debug | CNG KSP register: source dll={} | src/registry.rs | - | - |
debug | CNG KSP unregister | src/registry.rs | - | - |
debug | CNG KSP: create_ec_key_pair name={key_name} curve={curve:?} | src/backend.rs | key_name: CNG key namecurve: elliptic curve identifier | - |
debug | CNG KSP: create_rsa_key_pair name={key_name} bits={bit_length} | src/backend.rs | key_name: CNG key namebit_length: key size in bits | - |
debug | CNG KSP: decoded PEM to {} bytes DER | src/key.rs | - | - |
debug | CNG KSP: decrypt_data uid={uid} len={} | src/backend.rs | uid: KMIP object UID | - |
debug | CNG KSP: destroy_key uid={uid} | src/backend.rs | uid: KMIP object UID | - |
debug | CNG KSP: encrypt_data uid={uid} len={} | src/backend.rs | uid: KMIP object UID | - |
debug | CNG KSP: export_private_key_pkcs8 uid={uid} | src/backend.rs | uid: KMIP object UID | - |
debug | CNG KSP: export_public_key_spki uid={uid} | src/backend.rs | uid: KMIP object UID | - |
debug | CNG KSP: finalize import blob len={}, first_bytes={:?} | src/key.rs | - | - |
debug | CNG KSP: finalized key '{}' → priv={}, pub={} | src/key.rs | - | - |
debug | CNG KSP: import_rsa_private_key name={key_name} | src/backend.rs | key_name: CNG key name | - |
debug | CNG KSP: revoke_key uid={uid} | src/backend.rs | uid: KMIP object UID | - |
debug | CNG KSP: sign_hash uid={uid} hash_len={} | src/backend.rs | uid: KMIP object UID | - |
debug | CNG KSP: verify_signature uid={uid} hash_len={} sig_len={} | src/backend.rs | uid: KMIP object UID | - |
debug | Copying {} -> {} | src/registry.rs | - | - |
debug | MoveFileExW(DELAY_UNTIL_REBOOT) failed for '{}'; leftover file is harmless. | src/registry.rs | - | - |
trace | CNG KSP: list_cng_keys | src/backend.rs | — | — |
trace | CNG KSP: locate_key_by_name tag={tag} | src/backend.rs | tag — … | — |
trace | CNG KSP: locate_public_key_by_name tag={tag} | src/backend.rs | tag — … | — |
Domain: Web UI
The Web UI emits browser console messages via console.*. These are visible in the
browser developer tools (F12 → Console tab) and are not captured by RUST_LOG or
the OTLP pipeline.
Crate path: ui/src/
| Level | Message | File | Variables | Notes |
|---|---|---|---|---|
warn | revoke_ttlv_request not available in WASM package | components/common/Locate.tsx | - | - |
info | [KMS] vendor_id set to "{vendorId}" | App.tsx | vendorId: vendor identifier string received from the server | - |
error | Aggregate date error: | actions/Tokenize/TokenizeAggregateDate.tsx | — | — |
error | Aggregate number error: | actions/Tokenize/TokenizeAggregateNumber.tsx | — | — |
error | Certificate validation failed: | pages/LoginPage.tsx | — | — |
error | Error creating FPE key: | actions/FPE/FpeKeysCreate.tsx | — | — |
error | Error fetching create permission: | actions/Access/AccessObtained.tsx | — | — |
error | Error fetching CSE information: | actions/Keys/CseInfo.tsx | — | — |
error | Error fetching Get for ${uid}: | components/common/Locate.tsx | uid | ×4 in this file |
error | Error fetching HSM status: | actions/Objects/HsmStatus.tsx | — | — |
error | Error fetching privileged access: | actions/Access/AccessGrant.tsx | — | — |
error | Error fetching privileged access: | actions/Access/AccessRevoke.tsx | — | — |
error | Error getting attributes: | actions/Attributes/AttributeGet.tsx | — | — |
error | Error listing objects: | actions/Access/AccessObtained.tsx | — | — |
error | Error listing objects: | actions/Objects/ObjectsOwned.tsx | — | — |
error | Error loading certificate algorithms from WASM: | actions/Certificates/CertificateCertify.tsx | — | — |
error | Error loading EC algorithms from WASM: | actions/EC/ECKeysCreate.tsx | — | — |
error | Error loading hash algorithms from WASM: | actions/Symmetric/SymmetricHash.tsx | — | — |
error | Error loading PQC algorithms from WASM: | actions/PQC/PqcKeysCreate.tsx | — | — |
error | Error loading symmetric algorithms from WASM: | actions/Keys/SymKeysCreate.tsx | — | — |
error | Error parsing tags JSON: | actions/CloudProviders/AwsExportKeyMaterial.tsx | — | — |
error | Error parsing tags JSON: | utils/azureByok.ts | — | — |
error | Fallback Locate without KFT failed: | components/common/Locate.tsx | — | — |
error | FPE decrypt error: | actions/FPE/FpeDecrypt.tsx | — | — |
error | FPE encrypt error: | actions/FPE/FpeEncrypt.tsx | — | — |
error | Hash tokenize error: | actions/Tokenize/TokenizeHash.tsx | — | — |
error | Login error: | contexts/AuthContext.tsx | — | — |
error | Login error: | pages/LoginPage.tsx | — | — |
error | Noise tokenize error: | actions/Tokenize/TokenizeNoise.tsx | — | — |
error | Scale number error: | actions/Tokenize/TokenizeScaleNumber.tsx | — | — |
error | WASM init failed: | App.tsx | — | — |
error | Word mask error: | actions/Tokenize/TokenizeWordMask.tsx | — | — |
error | Word pattern mask error: | actions/Tokenize/TokenizeWordPatternMask.tsx | — | — |
error | Word tokenize error: | actions/Tokenize/TokenizeWordTokenize.tsx | — | — |
warn | [KMS] Could not query server vendor_id, using default: | App.tsx | — | — |
warn | State+KFT fallback Locate without KFT failed: | components/common/Locate.tsx | — | — |
warn | Symmetric google_cse key check failed: | actions/Keys/CseInfo.tsx | — | — |
debug | ECSign: signature length | actions/EC/ECSign.tsx | — | — |
debug | ECVerify: dataBuf len | actions/EC/ECVerify.tsx | — | — |
debug | RsaSign: signature length | actions/RSA/RsaSign.tsx | — | — |
debug | RsaVerify: dataBuf len | actions/RSA/RsaVerify.tsx | — | — |
error | JWT fallback failed: | App.tsx | - | - |
Monitoring Stack — Setup Guide
This guide walks you through deploying the KMS observability stack step by step. For a full reference of OTLP options and pipeline internals, see → KMS Telemetry
Table of contents
- Download
- Prerequisites
- Local mode — KMS included
- External mode — existing KMS
- Explore Grafana
- Troubleshooting
Download
The monitoring stack is distributed as a standalone archive containing the Docker Compose file, configuration templates, and helper scripts.
Download the archive from the KMS GitHub Releases page
(cosmian-kms-monitoring.zip), or use wget with the version you are deploying:
wget https://package.cosmian.com/kms/<version>/monitoring/cosmian-kms-monitoring.zip
unzip cosmian-kms-monitoring.zip
cd monitoring/
Replace <version> with the KMS version you are deploying (e.g. 5.25.0).
The list of available versions is at https://package.cosmian.com/kms/.
Alternatively, clone the KMS repository and navigate to the
monitoring/ directory.
Prerequisites
Before getting started, make sure the following tools are installed on your machine.
Required
-
Docker Engine ≥ 20.10 Compose profiles (
COMPOSE_PROFILES) require Docker Compose v2 and Docker Engine 20.10+. Verify your version:docker --version docker compose version -
Docker Compose V2 (included in Docker Desktop 3.4+) The stack uses the
docker composecommand (with a space), not the legacydocker-compose.
Local mode only
-
openssl— used bygenerate-demo-cert.shto generate the demo TLS certificate. Verify it is available:openssl versionOn macOS it is pre-installed. On Linux:
apt install opensslordnf install openssl.
External mode only
-
Your existing KMS must be configured to export telemetry via OTLP to the collector:
# gRPC (recommended) KMS_OTLP_URL=http://<collector-host>:4317 # or HTTP KMS_OTLP_URL=http://<collector-host>:4318
Ports availability
The following ports must be free on the host before starting the stack:
| Port | Service |
|---|---|
3000 | Grafana |
4317 | OTel Collector (gRPC) |
4318 | OTel Collector (HTTP) |
8428 | VictoriaMetrics |
9998 | KMS (local mode only) |
Local mode — KMS included
In this mode, the full stack starts together: KMS, OTel Collector, VictoriaMetrics, and Grafana. Use this mode for local development or to evaluate the stack end-to-end.
All files referenced below (docker-compose.yml, .env, generate-demo-cert.sh) are located in the
monitoring/ directory of the KMS repository. Navigate there first:
cd monitoring/
1. Configure .env
Open the .env file — this is the only file you need to edit.
Make sure the following values are set:
# ── KMS Mode / Docker profiles ───────────────────────────────────
COMPOSE_PROFILES=kms-local
KMS_MODE=local
# ── TLS certificate password (used by generate-demo-cert.sh) ─────
KMS_P12_PASSWORD=testpassword
# ── KMS topology metadata ────────────────────────────────────────
KMS_CLUSTER=cosmian-kms-local
# ── Metadata for metrics/traces ──────────────────────────────────
KMS_VERSION=latest
ENVIRONMENT=demo
# ── Grafana ──────────────────────────────────────────────────────
GRAFANA_ADMIN_USER=demo
GRAFANA_ADMIN_PASSWORD=demo
# ── Metrics retention (VictoriaMetrics, in months) ───────────────
METRICS_RETENTION_MONTHS=12
✏️ Screenshot placeholder —
.envfile open in editor,COMPOSE_PROFILESandKMS_MODEhighlighted.
2. Generate the demo TLS certificate
The KMS container requires a PKCS#12 certificate to serve its API over TLS.
The provided script generates a self-signed certificate valid for 10 years,
using the password defined in KMS_P12_PASSWORD:
bash generate-demo-cert.sh
Expected output:
Generating a 4096 bit RSA private key
.............................................++++
.............................................++++
.............................................++++
writing new private key to './certs/kms-demo.key'
-----
PKCS#12 demo certificate generated at: ./certs/kms.p12
Password: testpassword

⚠️ This certificate is for demo purposes only. Do not use it in production.
3. Start the stack
docker compose up -d
Docker will pull the required images and start all containers. On first run, this may take a minute depending on your network speed.

4. Verify the stack is healthy
docker compose ps
All containers should show Up or Up (healthy):
NAME STATUS
kms Up (healthy)
otel-collector Up
victoria-metrics Up
grafana Up (healthy)
You can also check the OTel Collector health endpoint:
curl http://localhost:13133
Expected response: {"status":"Server available"}

External mode — existing KMS
Use this mode when you already have a running KMS instance and only want to attach the observability stack to it.
All files referenced below are located in the monitoring/ directory of the KMS repository.
Navigate there first:
cd monitoring/
1. Configure .env
Only a few lines change compared to local mode:
-COMPOSE_PROFILES=kms-local
-KMS_MODE=local
+COMPOSE_PROFILES=
+KMS_MODE=external
-# KMS_P12_PASSWORD is not needed in external mode
-KMS_P12_PASSWORD=testpassword
KMS_CLUSTER=cosmian-kms-local
KMS_VERSION=latest
-ENVIRONMENT=demo
+ENVIRONMENT=production
GRAFANA_ADMIN_USER=demo
GRAFANA_ADMIN_PASSWORD=demo
METRICS_RETENTION_MONTHS=12

2. Point your KMS to the collector
On your existing KMS, enable OTLP export toward the collector host:
# via environment variable
KMS_OTLP_URL=http://<collector-host>:4317
# or via CLI argument
./cosmian_kms_server --otlp http://<collector-host>:4317 --enable-metering
If the KMS runs on the same machine as the stack, use
http://localhost:4317.
3. Start the stack (without KMS)
docker compose up -d
With COMPOSE_PROFILES left empty, Docker Compose will start only
OTel Collector, VictoriaMetrics, and Grafana — the KMS container is skipped.
4. Verify the stack is healthy
docker compose ps
Expected output (no kms container):
NAME STATUS
otel-collector Up
victoria-metrics Up
grafana Up (healthy)
Verify the collector is receiving data from your KMS:
# Check that otelcol_receiver_accepted_spans is incrementing
curl -s http://localhost:8888/metrics | grep otelcol_receiver_accepted_spans
Or

Explore Grafana
Once the stack is running, open Grafana in your browser:
http://localhost:3000
Login with:
| Field | Value |
|---|---|
| Username | value of GRAFANA_ADMIN_USER in .env (default: demo) |
| Password | value of GRAFANA_ADMIN_PASSWORD in .env (default: demo) |

Pre-provisioned dashboards are available under Dashboards → Browse:

After few seconds metrics will be available

Troubleshooting
Containers not starting
docker compose logs -f otel-collector
docker compose logs -f kms # local mode only
No data in Grafana dashboards
-
Confirm the OTel Collector is up:
curl http://localhost:13133 -
Confirm VictoriaMetrics is receiving data:
curl http://localhost:8428/health -
Check that your KMS is sending OTLP — look for incoming spans in collector logs:
docker compose logs otel-collector | grep "traces"
KMS container fails to start (local mode)
Verify the certificate was generated:
ls -la .certs/kms.p12
If missing, re-run:
bash generate-demo-cert.sh
Port conflict
If a port is already in use, identify the process:
# macOS / Linux
lsof -i :<port>
# Windows
netstat -ano | findstr :<port>
Then either stop the conflicting process or edit the port mapping in docker-compose.yml.
For a complete reference of all OTLP options, log levels, and pipeline internals, see → KMS Telemetry
OTLP Metrics Reference
The KMS server pushes metrics to any OpenTelemetry collector via
OTLP/gRPC every 30 seconds. No HTTP /metrics endpoint is exposed — metrics are always
pushed, never scraped.
For deployment instructions and Grafana setup, see Monitoring Setup. To enable the feature, see Telemetry & Observability.
KMIP Operations
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.kmip.operations.total | counter | Total KMIP operations executed | operation |
kms.kmip.operations.per_user.total | counter | Total KMIP operations per user | operation, user |
kms.kmip.operation.duration | histogram (s) | Duration of each KMIP operation | operation |
Users & Permissions
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.active.users | up-down counter | Unique users who issued at least one request | — |
kms.permissions.granted.per_user.total | counter | Access rights granted, broken down by user | user, permission_type |
kms.permissions.granted.total | counter | Total access rights granted | — |
Database
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.database.operations.total | counter | DB operations by type and result | operation, backend, outcome |
kms.database.operation.duration | histogram (s) | Wall-clock time of each DB call | operation, backend, outcome |
Label values:
backend:sqlite·postgresql·mysql·redisoutcome:success·error
HTTP
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.http.requests.total | counter | Incoming HTTP requests | method, path, status |
kms.http.request.duration | histogram (s) | HTTP request latency | method, path, status |
path is normalised (e.g. /kmip/2_1, /google_cse/...) to avoid high cardinality from
object identifiers.
Server Health
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.server.uptime | counter (monotonic, s) | Seconds elapsed since server start | — |
kms.server.start_time | up-down counter | Server start time as Unix timestamp (s) | — |
kms.active.connections | up-down counter | Current open HTTP connections | — |
kms.errors.total | counter | Errors categorised by type | error_type |
Objects & Keys
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.objects.total | gauge | Total non-destroyed objects in the KMS | — |
kms.keys.active.count | gauge | Non-destroyed key objects (SymmetricKey, PrivateKey, PublicKey, SplitKey) across all states: PreActive, Active, Deactivated, Compromised | — |
Both metrics are refreshed every 30 s by the metrics cron task and seeded at server startup.
Cache
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.cache.operations.total | counter | Unwrap-cache lookups | operation, result |
HSM
| Metric | Type | Description | Labels |
|---|---|---|---|
kms.hsm.operations.total | counter | HSM operations by type and model | operation, hsm_model |
KMS User Interface
The KMS User Interface (UI) is a web-based application served from the KMS server, allowing users to perform key management operations easily.
Accessing the User Interface
Once the KMS server is running, open the following URL in your browser:
https://YOUR_KMS_URL/ui
Replace YOUR_KMS_URL with the actual KMS server address.
If the KMS is running behind a reverse proxy, set kms_public_url in the server configuration to the public-facing URL — this is required for the OIDC redirect flow to work correctly.
The UI bundle is served from the path configured by ui_index_html_folder (defaults to the built-in bundle shipped with the server).
Authentication Configuration
The UI automatically detects the authentication method configured on the KMS server and adapts its login flow accordingly:
- OIDC Authentication: The UI presents a LOGIN button that redirects to the identity provider. See Configuring OIDC Authentication below.
- Certificate Authentication: The UI presents an ACCESS KMS button. The browser negotiates the mTLS handshake and submits the client certificate automatically. If no valid certificate is available, the login page is shown again with an error. See Configuring Certificate Authentication below.
- No authentication configured: No login is required — the UI takes you directly to the key management interface. However, a warning banner is displayed:
To remove the warning "Authentication is disabled on this KMS server", configure an [authentication method like explained in the next sections](#authentication-configuration).
Configuring OIDC Authentication
To enable authentication via OIDC, configure the KMS UI with details from the selected OIDC compliant tenant.
1. Using the Configuration File (.toml)
Add the following section to your KMS configuration file:
[ui_config.ui_oidc_auth]
ui_oidc_client_id = "your_client_id"
ui_oidc_client_secret = "your_client_secret" # (optional)
ui_oidc_issuer_url = "https://your_oidc_issuer_url"
ui_oidc_logout_url = "https://your_oidc_logout_url"
If your KMS is accessible behind a proxy, also specify the public KMS URL in the generic section:
kms_public_url = "your_kms_public_url"
You may also need to register the following URIs in your Identity Provider (IdP) application settings:
- Allowed redirect/callback URI:
https://YOUR_KMS_URL/ui/callback - Application Login URI:
https://YOUR_KMS_URL/ui/login - Logout URI:
https://YOUR_KMS_URL/ui/login
2. Using Command-Line Arguments
--ui-oidc-client-id "your_client_id" \
--ui-oidc-client-secret "your_client_secret" \
--ui-oidc-issuer-url "https://your_oidc_issuer_url" \
--ui-oidc-logout-url "https://your_oidc_logout_url"
The UI login flow always uses PKCE (code_challenge_method=S256). The client secret is optional — see the PKCE Authentication guide for per-provider configuration instructions.
Configuring Certificate Authentication (mTLS)
When the KMS server is started with mutual TLS and a client CA (clients_ca_cert_file), the UI switches to certificate-based login. See Enabling TLS for server-side configuration.
The browser handles the mTLS handshake transparently: Chrome presents the client certificate during the TLS handshake and the KMS server extracts the Subject CN of the certificate and uses it as the KMS username. For example, a certificate with CN=alice identifies the user as alice for all access-control decisions.
Users who have no valid client certificate installed will see a "CERT identity verification failed" error on the login page.
Step 1 — Obtain your client certificate
The client certificate must be signed by the CA configured in clients_ca_cert_file on the server. Obtain it from your PKI or administrator. If you are using the KMS setup wizard, it generates a client.crt + client.key pair automatically.
Step 2 — Convert PEM to PKCS#12 (if needed)
Browsers import certificates as PKCS#12 (.p12) bundles. If you have separate PEM files, convert them:
openssl pkcs12 -export \
-certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg sha1 \
-in client.crt \
-inkey client.key \
-certfile ca.crt \
-out client.p12 \
-passout pass:your-password
OpenSSL 3.x generates PKCS#12 files with AES-256 ciphers by default. macOS
Security.framework (which Chrome on macOS uses) cannot import that format.
The -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg sha1 flags select
the older 3DES format that macOS accepts.
If you already have a .p12 file generated by the KMS wizard (client.p12), skip this step — it is already in the correct format.
Step 3 — Install the certificate in the browser
- Open
chrome://settings/certificates(or Settings → Privacy and security → Security → Manage certificates). - Go to the Your certificates tab.
- Click Import, select
client.p12, and enter the password when prompted.
Chrome and Safari on macOS read client certificates from the system keychain — do not use Chrome's built-in certificate manager.
- Double-click
client.p12in Finder, or run:security import client.p12 -k ~/Library/Keychains/login.keychain-db - Open Keychain Access, find your certificate under My Certificates.
- Double-click the certificate → expand Trust → set "When using this certificate" to Always Trust (or ensure the signing CA is already trusted).
Chrome and Edge on Windows read client certificates from the Windows Certificate Store.
- Double-click
client.p12→ follow the Import Wizard → store in Personal. - If the signing CA is not already trusted, also import
ca.crtinto Trusted Root Certification Authorities usingcertmgr.msc.
After installing or changing a client certificate, fully close and relaunch the browser. Browsers cache TLS session state and will not renegotiate with the new certificate until all windows are closed.
The Common Name (CN) of the client certificate becomes the KMS username. Make sure the CN matches the identity you want to use for access control. A wildcard CN (*) is explicitly rejected by the server.
UI Branding (post-install, no rebuild)
The KMS UI can be white‑labeled at runtime by editing the installed UI static files (no UI rebuild required).
What to change after install
The UI is served under /ui, from the UI dist directory on disk.
- Branding file:
/usr/local/cosmian/ui/dist/branding.json - Theme assets:
/usr/local/cosmian/ui/dist/themes/<theme>/...
All asset URLs in branding.json are URLs under /ui/... (for example: /ui/themes/example/example-logo-light.svg).
Post-install customization (deb/rpm)
When the KMS server is installed from Linux packages, branding can be customized after install by editing files directly in the UI dist folder (no UI rebuild required).
- Default UI dist path (Linux):
/usr/local/cosmian/ui/dist/ - Branding file:
/usr/local/cosmian/ui/dist/branding.json - Theme assets:
/usr/local/cosmian/ui/dist/themes/<theme>/...
The packaging scripts preserve these files across upgrades by backing them up and restoring them (upgrade-safe customization).
In this repo, theme assets are stored under ui/public/themes/ and the build step publishes them into ui/dist/themes/.
Switch to the example theme
Edit /usr/local/cosmian/ui/dist/branding.json and point the URLs to the example theme assets:
{
"title": "Example",
"faviconUrl": "/ui/themes/example/favicon-32x32.png",
"logoAlt": "Example",
"logoLightUrl": "/ui/themes/example/example-logo-light.svg",
"logoDarkUrl": "/ui/themes/example/example-logo-dark.svg",
"backgroundImageUrl": "/ui/themes/example/example-login-bg.jpg"
}
Restart the service (or clear browser cache) to see changes.
Start from the blank theme
The blank theme is a minimal starter template with placeholder assets — copy
it as your starting point for a new white-label deployment:
# Copy the blank theme to the installed UI dist directory
cp -r /usr/local/cosmian/ui/dist/themes/blank /usr/local/cosmian/ui/dist/themes/acme
# Customise the copy
nano /usr/local/cosmian/ui/dist/themes/acme/branding.json
# Replace logo-light.svg, logo-dark.svg, favicon.svg, login-bg.svg with your assets
# Activate it by pointing branding.json to the new theme
cp /usr/local/cosmian/ui/dist/themes/acme/branding.json /usr/local/cosmian/ui/dist/branding.json
The blank theme ships the following placeholder files:
| File | Purpose |
|---|---|
branding.json | Full example with every supported field |
logo-light.svg | Logo for light-mode header (dark text) |
logo-dark.svg | Logo for dark-mode header (white text) |
favicon.svg | Browser tab icon |
login-bg.svg | Login page background (dark blue gradient) |
branding.json schema
Example:
{
"title": "Example",
"faviconUrl": "/ui/themes/example/favicon-32x32.png",
"logoAlt": "Example Key Management",
"logoLightUrl": "/ui/themes/example/example-logo-light.svg",
"logoDarkUrl": "/ui/themes/example/example-logo-dark.svg",
"loginTitle": "Example",
"loginSubtitle": "Welcome",
"backgroundImageUrl": "/ui/themes/example/example-login-bg.jpg",
"loginCardColor": "rgba(126,34,206,0.3)",
"menuTheme": "dark",
"tokens": {
"light": { "colorPrimary": "#0057ff", "colorText": "#111827" },
"dark": { "colorPrimary": "#7c3aed", "colorText": "#e5e7eb" }
}
}
Keys
title: Setsdocument.title.faviconUrl: URL for the page favicon.logoAlt: Used as the header label and<img alt>.logoLightUrl/logoDarkUrl: Header logo depending on light/dark mode.loginTitle/loginSubtitle: Login page texts.backgroundImageUrl: Login background image.loginCardColor: CSS background color of the card overlaid on the login background. Accepts any CSS color value (e.g."rgba(0,87,255,0.3)","#0057ff4d"). Defaults to"rgba(126,34,206,0.3)"(semi-transparent purple).menuTheme:"light"or"dark".tokens.light/tokens.dark: Ant Design theme token overrides.
Behavior and fallbacks
- If
/ui/branding.jsonis missing or invalid, the UI uses built-in defaults. - If a key is missing, the UI falls back to the default value.
Notes
- The UI fetches
branding.jsonon startup and applies title/favicon before React renders. branding.jsonis fetched with cache busting by default.
About branding.ts
The UI branding loader/helpers live in ui/src/branding.ts.
It is a plain TypeScript module (no JSX), so it uses the .ts extension rather than .tsx.
Upgrade behavior
Linux packages are designed so you can customize UI files in place.
- On upgrade: package maintainer scripts back up UI dist content to
/var/lib/cosmian/ui/and restore it after installing the new version. - If you want to reset to package defaults: remove your customized
branding.jsonand/orthemes/<theme>/overrides, then reinstall or restore from a clean package.
Custom OpenSSL Build
The Eviden KMS dynamic package links against OpenSSL at runtime. You can redirect the service to a custom OpenSSL build — for example, a vendor-supplied or hardware-accelerated variant — without touching any Cosmian-owned files, by overriding the systemd service environment.
Static builds embed OpenSSL at compile time and cannot be redirected at runtime.
How it works
The KMS systemd unit (/lib/systemd/system/cosmian_kms.service) sets three environment variables that together control which OpenSSL is loaded:
| Variable | Default value (package install) | Purpose |
|---|---|---|
LD_LIBRARY_PATH | /usr/local/cosmian/lib | Directory searched first for libssl.so.3 / libcrypto.so.3 |
OPENSSL_CONF | /usr/local/cosmian/lib/ssl/openssl.cnf | OpenSSL configuration file |
OPENSSL_MODULES | /usr/local/cosmian/lib/ossl-modules | Directory containing provider modules (e.g. fips.so, legacy.so) |
Pointing all three at your custom OpenSSL installation is sufficient to make the service use it exclusively.
On startup the server logs the active OpenSSL version:
INFO cosmian_kms: [run] OpenSSL version: OpenSSL 3.X.Y DD Mon YYYY,
in OPENSSLDIR: "/usr/local/ssl", number: 30X000Y0
Overriding via systemd drop-in
1. Install your custom OpenSSL build
Place the libraries anywhere that is accessible to the cosmian_kms service
(i.e. not under /home/ — the systemd unit sets ProtectHome=yes).
Recommended locations: /opt/ or /usr/local/lib/.
Vendor CC/FIPS packages commonly ship with a nested usr/local/ tree inside
the archive. Copy the whole folder as-is:
sudo cp -r /path/to/openssl-<version>-linux-x86_64 /usr/local/lib/
Resulting layout:
/usr/local/lib/openssl-<version>-linux-x86_64/
usr/
local/
lib64/
libssl.so.3
libcrypto.so.3
ossl-modules/
fips.so
legacy.so
ssl/
openssl.cnf
fipsmodule.cnf
In the override.conf you then reference the nested usr/local/lib64/ path:
LD_LIBRARY_PATH=/usr/local/lib/openssl-<version>-linux-x86_64/usr/local/lib64
OPENSSL_MODULES=/usr/local/lib/openssl-<version>-linux-x86_64/usr/local/lib64/ossl-modules
If the archive extracts directly to lib64/ at the top level (no usr/local/
subdirectory), use a simpler install path such as /opt/openssl-custom/ and
reference lib64/ directly.
2. Create the systemd drop-in override
sudo systemctl edit cosmian_kms
This opens $EDITOR with a drop-in template saved at
/etc/systemd/system/cosmian_kms.service.d/override.conf.
Add the three environment variables, replacing the paths with those of your
installation:
[Service]
Environment="LD_LIBRARY_PATH=/opt/openssl-custom/lib"
Environment="OPENSSL_CONF=/opt/openssl-custom/ssl/openssl.cnf"
Environment="OPENSSL_MODULES=/opt/openssl-custom/lib/ossl-modules"
# Required when OIDC/JWKS auth is enabled: the default unit blocks outbound
# traffic to public IPs. See "Network firewall" below.
IPAddressAllow=any
3. Reload and restart
sudo systemctl daemon-reload
sudo systemctl restart cosmian_kms
4. Verify
sudo journalctl -u cosmian_kms --no-pager | grep "OpenSSL version"
The log line should reflect your custom build string.
Network firewall
The default systemd unit ships with IPAddressDeny=any and only allows
traffic to localhost and RFC-1918 private ranges:
IPAddressDeny=any
IPAddressAllow=localhost
IPAddressAllow=10.0.0.0/8
IPAddressAllow=172.16.0.0/12
IPAddressAllow=192.168.0.0/16
When jwt_auth_provider is configured, the KMS fetches JWKS keys from a
public OIDC endpoint (e.g. login.microsoftonline.com) at startup.
Because the endpoint's IP is not in the allowed list, the BPF firewall
silently drops the outbound SYN packets — the service hangs indefinitely
at the Refreshing JWKS log line and never starts listening.
Fix: allow outbound HTTPS in the drop-in
Add IPAddressAllow=any to the override.conf drop-in (taking precedence over
the IPAddressDeny=any in the unit):
[Service]
# … OpenSSL entries …
IPAddressAllow=any
If a stricter policy is preferred, add only the OIDC provider's IP ranges
instead of any. For Microsoft Entra ID / Azure AD (as of 2026), the range
is documented in the
Microsoft 365 IP address list.
If the custom OpenSSL was compiled with OPENSSLDIR=/usr/local/ssl (check
via openssl version -a), the FIPS provider looks for its configuration at
that path regardless of OPENSSL_CONF. Create the path and run
fipsinstall before starting the service:
sudo mkdir -p /usr/local/ssl
sudo env LD_LIBRARY_PATH=/opt/openssl-custom/lib64 \
/opt/openssl-custom/bin/openssl fipsinstall \
-module /opt/openssl-custom/lib64/ossl-modules/fips.so \
-out /usr/local/ssl/fipsmodule.cnf
# Create a minimal openssl.cnf at the compiled-in OPENSSLDIR
sudo tee /usr/local/ssl/openssl.cnf > /dev/null <<'EOF'
openssl_conf = openssl_init
config_diagnostics = 1
.include /usr/local/ssl/fipsmodule.cnf
[openssl_init]
providers = provider_sect
[provider_sect]
fips = fips_sect
default = default_sect
[default_sect]
activate = 1
EOF
Verify FIPS loads before restarting the service:
sudo env LD_LIBRARY_PATH=/opt/openssl-custom/lib64 \
OPENSSL_MODULES=/opt/openssl-custom/lib64/ossl-modules \
/opt/openssl-custom/bin/openssl list -providers
# Expected: both "default" and "fips" providers show status: active
Then reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart cosmian_kms
The systemd unit sets ProtectHome=yes. Custom OpenSSL builds placed
under /home/… are inaccessible to the service. Install custom builds
under /opt/ or /usr/local/ so the service can load them.
Rollback
Remove the drop-in override file and restart the service to revert to the Cosmian-bundled OpenSSL:
sudo rm -f /etc/systemd/system/cosmian_kms.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart cosmian_kms
Notes
- ABI compatibility:
libssl.so.3/libcrypto.so.3must be ABI-compatible with OpenSSL 3.x (major version3). - Provider modules:
legacy.so(or any other provider) must be compiled against the same OpenSSL version as the libraries you are installing. - Package upgrades: a
deb/rpmupgrade does not touch the drop-in override file, so the custom OpenSSL remains active after an upgrade.
Secret backends
Store sensitive configuration values — database passwords, API keys, tokens — in an external secret manager instead of plain text in the KMS TOML config file.
How it works
sequenceDiagram
participant Operator
participant KMS Server
participant Secret Backend
Operator->>KMS Server: cosmian_kms --backend vault -c kms.toml
KMS Server->>KMS Server: Parse TOML, find secret:// URIs
KMS Server->>Secret Backend: Resolve each secret:// URI
Secret Backend-->>KMS Server: Return plaintext value
KMS Server->>KMS Server: Replace URIs with values, apply config
KMS Server->>Operator: Server ready
- In your
kms.toml, replace any sensitive value with asecret://...URI. - Start the KMS with
--backend <backend>(or setKMS_SECRET_BACKENDenv var). - At startup the KMS resolves every
secret://URI once, then applies the config normally.
The config file never contains actual secrets — only references.
Supported backends
| Backend | --backend | URI format | Required env vars |
|---|---|---|---|
| HashiCorp Vault | vault | secret://<mount>/<path>[#<field>] | VAULT_ADDR, VAULT_TOKEN |
| AWS SSM Parameter Store | aws-ssm | secret://<region>/<parameter-name> | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY |
| Azure Key Vault | azure-kv | secret://<vault>/secrets/<name>[/<version>] | AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET |
| Cosmian KMS | cosmian-kms | secret://<host>[:<port>]/<object-id> | (optional) COSMIAN_KMS_SECRET_TOKEN |
HashiCorp Vault
Uses the KV-v2 secrets engine. The URI fragment #field selects a specific
key in the secret's JSON data; defaults to value if omitted.
1. Store a secret in Vault
vault kv put secret/kms/db password=my-db-password
2. Reference it in kms.toml
[db]
database_type = "postgresql"
postgres_url = "postgresql://kms:secret://secret/kms/db#password@db.internal:5432/kms"
Or for a standalone field:
[db]
database_type = "postgresql"
postgres_url = "secret://secret/kms/postgres-url#value"
3. Start the KMS
export VAULT_ADDR=http://vault.internal:8200
export VAULT_TOKEN=s.xxxxxxxx
cosmian_kms --backend vault -c /etc/cosmian/kms.toml
AWS SSM Parameter Store
Fetches a SecureString parameter. The leading / is prepended automatically — do not include it in the URI.
1. Store a secret in SSM
aws ssm put-parameter \
--name /kms/db-password \
--value "my-db-password" \
--type SecureString \
--region eu-west-1
2. Reference it in kms.toml
[db]
postgres_url = "secret://eu-west-1/kms/db-password"
3. Start the KMS
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
# Optional: export AWS_SESSION_TOKEN=...
cosmian_kms --backend aws-ssm -c /etc/cosmian/kms.toml
Azure Key Vault
Uses service-principal client credentials (OAuth2) to authenticate to Azure AD, then fetches the secret from the Key Vault REST API (v7.4).
1. Store a secret
az keyvault secret set \
--vault-name myvault \
--name db-password \
--value "my-db-password"
2. Reference it in kms.toml
[db]
postgres_url = "secret://myvault/secrets/db-password"
To pin a specific version:
postgres_url = "secret://myvault/secrets/db-password/abc123def456"
3. Start the KMS
export AZURE_TENANT_ID=...
export AZURE_CLIENT_ID=...
export AZURE_CLIENT_SECRET=...
cosmian_kms --backend azure-kv -c /etc/cosmian/kms.toml
Cosmian KMS (self-referencing)
Use another Cosmian KMS instance as the secret store. The secret must be stored as a SecretData or OpaqueObject whose raw bytes are the UTF-8 value.
This is useful for hierarchical deployments where a "vault KMS" holds credentials used by downstream KMS instances.
1. Import a secret into the vault KMS
ckms secret-data create --value "my-db-password" --type password
# → UniqueIdentifier: 550e8400-e29b-41d4-a716-446655440000
2. Reference it in kms.toml
[db]
postgres_url = "secret://vault-kms.internal:9998/550e8400-e29b-41d4-a716-446655440000"
For localhost (uses http automatically):
postgres_url = "secret://localhost:9998/550e8400-e29b-41d4-a716-446655440000"
3. Start the KMS
# Optional token if the vault KMS requires authentication:
export COSMIAN_KMS_SECRET_TOKEN=eyJhbGciOi...
# Accept self-signed certs (dev only):
export COSMIAN_KMS_INSECURE_CERTS=true
cosmian_kms --backend cosmian-kms -c /etc/cosmian/kms.toml
Security considerations
| Concern | Mitigation |
|---|---|
| Secret exposure in config files | Only secret:// references are stored on disk — never plaintext values. |
| Secret lifetime | URIs are resolved once at startup. Resolved values live only in process memory. |
| Backend credentials | Always inject via environment variables, never in the TOML file. |
| Network security | Use TLS for all backend communication. For Vault and Cosmian KMS, ensure VAULT_ADDR uses https:// in production. |
| Rotation | Restart the KMS to pick up rotated secrets. There is no hot-reload. |
Only one --backend can be active at a time. All secret:// URIs
in the config must be resolvable by the selected backend.
FIPS 140-3
The Federal Information Processing Standard (FIPS) Publication 140-3, Security Requirements for Cryptographic Modules, is a US government standard that specifies the security requirements for cryptographic modules protecting sensitive information.
When compiled in FIPS mode, the Eviden KMS uses only cryptographic primitives that are compliant with the standards of the National Institute of Standards and Technology (NIST) and uses implementations of an NIST FIPS 140-3 compliant cryptographic module: the OpenSSL FIPS provider.
The OpenSSL FIPS provider is certified under
Eviden produces pre-built Debian based Linux packages and docker containers of the KMS (on gcr.io).
By default, the Eviden KMS is built with FIPS compliance enabled.
Alternatively, you can enable all cryptographic mechanisms by building from source, using the --features non-fips flag:
cargo build --release --features non-fips
Cryptographic Algorithms
The Eviden server supports a large, and growing, list of cryptographic algorithms. This page lists the supported algorithms, their details and their reference in various standards. FIPS compliant algorithms are also listed with the corresponding NIST standard.
Keys and certificates for all the listed algorithms can be generated, imported, exported, wrapped, unwrapped... using the Eviden KMS server API or KMS CLI
Should you require a specific algorithm or standard to be supported, please directly open a ticket or pull request on the Github repository.
Key-wrapping schemes
The Eviden server supports key-wrapping via the Import(unwrapping) and Export (wrapping) kmip operations.
The (un)wrapping key identifier may be that of a key or a certificate.
In the latter case, the public key (or the associated private key for unwrapping, if any) will be retrieved and used.
The supported key-wrapping algorithms are:
| Algorithm | Wrap Key Type | FIPS mode | Description |
|---|---|---|---|
| AES-KW | Symmetric key wrapping | NIST SP 800-38F | Symmetric key-wrapping without padding as defined in RFC3394. |
| AES-KWP | Symmetric key wrapping | NIST SP 800-38F | Symmetric key-wrapping with padding as defined in RFC5649. |
| CKM_RSA_PKCS | RSA PKCS#1 v1.5 | Not anymore | RSA WITH PKCS#1 v1.5 padding - removed by NIST approved algorithms for key wrapping in FIPS 140-3 |
| CKM_RSA_PKCS_OAEP | RSA key wrapping | NIST 800-56B rev. 2 | RSA OAEP with NIST approved hashing functions for RSA key size 2048, 3072 or 4096 bits. |
| CKM_RSA_AES_KEY_WRAP | RSA-AES hybrid key wrapping | NIST SP 800-38F | RSA OAEP with NIST approved hashing functions and AES-KWP for RSA key size 2048, 3072 or 4096 bits. |
| Salsa Sealed Box | X25519, Ed25519 and Salsa20 Poly1305 | No | ECIES compatible with libsodium Sealed Boxes. |
| ECIES | P-256, P-384, P-521 | No | ECIES with a NIST curve: P-256 uses SHAKE128 + AES-128-GCM; P-384 and P-521 use SHAKE256 + AES-256-GCM. |
Any encryption scheme below can be used for key-wrapping as well.
Encryption schemes
Encryption is supported via the Encrypt and Decrypt kmip operations.
For bulk operations (i.e. encrypting/decrypting multiple data with the same key),
please refer to KMIP Messages that allow combining multiple operations in a
single request.
Encryption can be performed using a key or a certificate. Decryption can be performed using a key.
The supported encryption algorithms are:
| Algorithm | Encryption Key Type | FIPS mode | Description |
|---|---|---|---|
| Covercrypt | Covercrypt | No | A fast post-quantum attribute based scheme: Covercrypt. |
| AES GCM | Symmetric authenticated encryption with additional data | NIST FIPS 197 | The NIST standardized symmetric encryption in FIPS 197. |
| AES XTS | Symmetric, not authenticated | NIST SP 800-38E | Used in disk encryption. Requires 2 keys (e.g. a double-sized key) |
| AES GCM-SIV | Symmetric, authenticated, synthetic IV | No | Used for deterministic encryption and encryption of very large data sets. |
| FPE FF1 | Symmetric, format-preserving encryption | No | NIST SP 800-38G FF1 format-preserving encryption for text, integers, and floating-point values through KMIP Encrypt/Decrypt. |
| ChaCha20-Poly1305 | Symmetric authenticated encryption with additional data | No | A popular symmetric encryption algorithm standardized in RFC-8439 |
| CKM_RSA_PKCS | RSA PKCS#1 v1.5 | Not anymore | RSA WITH PKCS#1 v1.5 padding - removed by NIST approved algorithms for encryption in FIPS 140-3 |
| CKM_RSA_PKCS_OAEP | RSA encryption with OAEP padding | NIST 800-56B rev. 2 | RSA OAEP with NIST approved hashing functions for RSA key size 2048, 3072 or 4096 bits. |
| Salsa Sealed Box | X25519, Ed25519 and Salsa20 Poly1305 | No | ECIES compatible with libsodium Sealed Boxes. |
| ECIES | P-256, P-384, P-521 | No | ECIES with a NIST curve: P-256 uses SHAKE128 + AES-128-GCM; P-384 and P-521 use SHAKE256 + AES-256-GCM. |
Algorithms Details
Covercrypt
Covercrypt is a new post-quantum cryptographic algorithm, being standardized at ETSI that allows creating ciphertexts for a set of attributes and issuing user keys with access policies over these attributes. User keys are traceable with a unique fingerprint.
AES GCM
AES is described in NIST FIPS 197. In Eviden KMS it is used as a data encryption mechanism (DEM) with the Galois Counter Mode of operation (GCM) with a 96 bits nonce, a 128 bits tag with and key sizes of 128, 192 or 256 bits.
FPE FF1
Cosmian KMS supports NIST SP 800-38G FF1
format-preserving encryption in non-FIPS mode through the KMIP Encrypt and Decrypt
operations when the Cryptographic Algorithm is set to FPE_FF1.
The server supports three data shapes:
- text values, using the alphabet name or a custom alphabet in
AuthenticatedEncryptionAdditionalData - integer values, using JSON metadata such as
{"type":"integer","alphabet":"numeric"} - floating-point values, using JSON metadata such as
{"type":"float"}
The tweak is supplied through IVCounterNonce. The CLI exposes the same flow via ckms fpe
commands: ckms fpe keys create, ckms fpe encrypt, and ckms fpe decrypt.
ChaCha20-Poly1305
ChaCha20-Poly1305 is a symmetric authenticated encryption algorithm that is described in RFC-8439. The algorithm is not standardized by NIST but is a popular secure alternative to AES-GCM and is used in the same way, in particular by Google.
AES-KWP
Allows to symmetrically wrap keys using RFC5649 which is also standardized as PKCS#11 CKM_AES_KEY_WRAP_PAD and described in NIST SP 800-38F.
CKM_RSA_PKCS
A.k.a PKCS #1 v1.5 RSA as specified in PKCS#11 v2.40.
The algorithm is not recommended by NIST for encryption or key wrapping in FIPS 140-3. It is still supported for signature operations.
The maximum plaintext length is k-11 where k is the length in octets of the RSA modulus
The output length is the same as the modulus length.
CKM_RSA_PKCS_OAEP
A.k.a PKCS #1 RSA OAEP as specified in PKCS#11 v2.40. This scheme is part of the NIST 800-56B rev. 2 recommendation available at section 7.2.2.
The maximum plaintext length is k-2-2*hLen where
kis the length in octets of the RSA modulushLenis the length in octets of the hash function output
The output length is the same as the modulus length.
The default hash function is SHA-256 but any NIST approved hash functions can be used for the OAEP scheme as listed in
- NIST FIPS 180-4: SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
- NIST FIPS 202: SHA3-224, SHA3-256, SHA3-384, SHA3-512
Set the corresponding name of the hash function in the Cryptographic Parameters when performing a
KMIP operation.
To request this algorithm using the KMIP Encrypt/Decrypt operation, or key-wrapping as part of
the Import/Export
operations, specify the id/tags of an RSA key and set the Cryptographic Algorithm to RSA.
CKM_RSA_AES_KEY_WRAP
A PKCS#11 key wrapping mechanism that is supported by most HSMs.
The scheme asymmetrically wrap keys as described here and allows wrapping keys of any size using using a hybrid RSA/AES scheme.
Since old similar wrapping methods based on RSA used naive RSA encryption and could present some flaws, it aims at a generally more secure method to wrap keys:
- Receive data of the form
c|wkwhere|is the concatenation operator. Distinguishcandwk, respectively the encryptedkekand the wrapped key. First decrypt the key-encryption-keykekusing RSA-OAEP, then proceed to unwrap the key by decryptingm = dec(wk, kek)using AES-KWP as specified in RFC5649.
The algorithm can be used with any NIST approved hash function described above; set the
corresponding value in the Cryptographic Parameters when performing a KMIP operation.
To request this algorithm using key-wrapping as part of the Import/Export operations, specify the
id/tags of an RSA key as the wrapping key and set the Cryptographic Algorithm to RSA and
the Padding Method to None in the Key Wrapping Specification.
In the Eviden KMIP routing logic, the padding method discriminates between the three RSA wrapping schemes:
| Padding Method | Algorithm selected |
|---|---|
None | CKM_RSA_AES_KEY_WRAP (this scheme) |
OAEP | CKM_RSA_PKCS_OAEP |
PKCS1v15 | CKM_RSA_PKCS (non-FIPS only) |
PaddingMethod::None does not mean unpadded RSA. It is the signal to route toward the
hybrid RSA/AES wrapping scheme. The RSA OAEP padding is still applied internally — the field
merely selects which wrapping scheme to invoke.
The following JSON TTLV snippet shows the CryptographicParameters to embed in a
KeyWrappingSpecification on an Export or Import request:
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "RSA"
},
{
"tag": "PaddingMethod",
"type": "Enumeration",
"value": "None"
},
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA256"
}
]
}
This algorithm is compatible with the one used in Google KMS.
RSA OAEP AES 128 GCM
CKM_RSA_AES_KEY_WRAP can only be used for key wrapping and not for encryption. This scheme adds authentication by using AES 128 in Galois Counter Mode (GCM). Combined with RSA OAEP to encapsulate the AES key, this scheme is compatible with NIST SP 800-38F.
To request this algorithm using the KMIP Encrypt/Decrypt operation, specify the id/tags of an RSA
key and set the Cryptographic Algorithm to AES.
Salsa sealed box
An ECIES scheme that uses X25519 and XSalsa20-Poly1305 and is compatible with libsodium Sealed Boxes.
An Ed25519 key can be used; it will be automatically converted to X25519 first.
Ecies with NIST Curves
Although there is no specific FIPS standard for hybrid encryption, the ECIES encryption scheme is based on FIPS compliant cryptographic primitives only and uses the same algorithm as the Salsa Sealed Boxes. It supports the NIST P curves starting at P-256, and uses AES-128-GCM and SHAKE128 for curves with security strength $s \leq 128$ bits:
P-256
and AES-256-GCM and SHAKE256 for curves with security strength $s > 128$ bits:
P-384P-521
PQC Hybridized KEM
The Eviden KMS supports Post-Quantum Cryptography (PQC) hybridized Key Encapsulation Mechanisms (KEM) via the cosmian_cover_crypt crate. This crate provides a configurable KEM framework that can operate in pure classical, pure post-quantum, or hybrid mode by combining a pre-quantum KEM with a post-quantum KEM through a KEM combiner (using SHA-256).
The available pre-quantum KEMs are:
- P-256 — ECDH-based KEM on the NIST P-256 curve (via OpenSSL).
- Curve25519 — ECDH-based KEM on Curve25519.
The available post-quantum KEMs are:
- ML-KEM-512 — NIST FIPS 203 lattice-based KEM at security level 1.
- ML-KEM-768 — NIST FIPS 203 lattice-based KEM at security level 3.
The hybridized combinations pair one classical and one post-quantum KEM:
| Hybrid variant | Pre-quantum | Post-quantum | Approximate security |
|---|---|---|---|
| ML-KEM-512 + P-256 | P-256 | ML-KEM-512 | ~128 bits |
| ML-KEM-768 + P-256 | P-256 | ML-KEM-768 | ~192 bits |
| ML-KEM-512 + Curve25519 | Curve25519 | ML-KEM-512 | ~128 bits |
| ML-KEM-768 + Curve25519 | Curve25519 | ML-KEM-768 | ~192 bits |
The hybrid approach ensures that security is maintained even if one of the two underlying KEMs is broken: the combined shared secret remains secure as long as at least one component KEM is secure.
Key generation, encapsulation and decapsulation are exposed via the KMS CLI under
ckms pqc (non-FIPS builds only) using algorithm names ml-kem-512-p256, ml-kem-768-p256,
ml-kem-512-curve25519, and ml-kem-768-curve25519.
OpenSSL Native PQC Algorithms
Starting with OpenSSL 3.5, the Eviden KMS also provides direct support for OpenSSL-native Post-Quantum Cryptography algorithms standardized by NIST in August 2024. These algorithms are available in non-FIPS builds only.
ML-KEM — Key Encapsulation Mechanism (NIST FIPS 203)
ML-KEM (Module-Lattice-Based Key-Encapsulation Mechanism) is a lattice-based KEM standardized in NIST FIPS 203. It supersedes the CRYSTALS-Kyber candidate from the NIST PQC competition.
| Variant | Security level | Approximate security |
|---|---|---|
| ML-KEM-512 | NIST L1 | ~128 bits |
| ML-KEM-768 | NIST L3 | ~192 bits |
| ML-KEM-1024 | NIST L5 | ~256 bits |
Key generation, encapsulation, and decapsulation are exposed via the KMS CLI under ckms pqc ml-kem.
OpenSSL Hybrid KEM
OpenSSL also provides hybrid combinations that pair a classical elliptic-curve Diffie-Hellman key exchange with ML-KEM, following the IETF draft for hybrid key exchange in TLS 1.3.
| Variant | Classical component | Post-quantum component | Approximate security |
|---|---|---|---|
| X25519MLKEM768 | X25519 | ML-KEM-768 | ~192 bits |
| X448MLKEM1024 | X448 | ML-KEM-1024 | ~256 bits |
Key generation, encapsulation, and decapsulation for these hybrid variants are also exposed via
ckms pqc ml-kem.
ML-DSA — Lattice-Based Digital Signature (NIST FIPS 204)
ML-DSA (Module-Lattice-Based Digital Signature Algorithm) is a lattice-based signature scheme standardized in NIST FIPS 204. It supersedes the CRYSTALS-Dilithium candidate.
| Variant | Security level | Approximate security |
|---|---|---|
| ML-DSA-44 | NIST L2 | ~128 bits |
| ML-DSA-65 | NIST L3 | ~192 bits |
| ML-DSA-87 | NIST L5 | ~256 bits |
Key generation, signing, and verification are exposed via the KMS CLI under ckms pqc ml-dsa.
SLH-DSA — Hash-Based Digital Signature (NIST FIPS 205)
SLH-DSA (Stateless Hash-Based Digital Signature Algorithm) is a hash-based signature scheme standardized in NIST FIPS 205. It supersedes the SPHINCS+ candidate and is the only standardized PQC signature scheme not based on lattices.
Variants follow the naming convention SLH-DSA-<hash>-<level><speed> where:
<hash>is eitherSHA2orSHAKE<level>is128,192, or256(security level in bits)<speed>iss(small signature, slower signing) orf(fast signing, larger signature)
| Variant | Hash | Security | Signature size | Signing speed |
|---|---|---|---|---|
| SLH-DSA-SHA2-128s | SHA2 | ~128 bit | Small | Slow |
| SLH-DSA-SHA2-128f | SHA2 | ~128 bit | Large | Fast |
| SLH-DSA-SHA2-192s | SHA2 | ~192 bit | Small | Slow |
| SLH-DSA-SHA2-192f | SHA2 | ~192 bit | Large | Fast |
| SLH-DSA-SHA2-256s | SHA2 | ~256 bit | Small | Slow |
| SLH-DSA-SHA2-256f | SHA2 | ~256 bit | Large | Fast |
| SLH-DSA-SHAKE-128s | SHAKE | ~128 bit | Small | Slow |
| SLH-DSA-SHAKE-128f | SHAKE | ~128 bit | Large | Fast |
| SLH-DSA-SHAKE-192s | SHAKE | ~192 bit | Small | Slow |
| SLH-DSA-SHAKE-192f | SHAKE | ~192 bit | Large | Fast |
| SLH-DSA-SHAKE-256s | SHAKE | ~256 bit | Small | Slow |
| SLH-DSA-SHAKE-256f | SHAKE | ~256 bit | Large | Fast |
Key generation, signing, and verification are exposed via the KMS CLI under ckms pqc slh-dsa.
Signature schemes
Digital signature signing and verification are supported via both the Certify operation (for certificate signing) and the Sign operation (for direct data signing).
The Certify operation is used to create a certificate either by signing a certificate request, or building it from an existing public key.
The Sign operation is used to perform digital signature operations on provided data using a private key. This operation supports:
- Signing raw data (the operation will hash the data using the specified or default hash algorithm)
- Signing pre-hashed data (digested data) for cases where the client has already computed the hash
| Algorithm | Signature Key Type | FIPS mode | Description |
|---|---|---|---|
| RSASSA-PSS | RSA-2048, RSA-3072, RSA-4096 | Yes | RSA signatures using PKCS#1 PSS padding with approved hash functions (SHA-256, SHA-384, SHA-512). |
| ECDSA | P-256, P-384, P-521 | Restricted to curves P-256, P-384 and P-521. | See FIPS-186.5 and NIST.SP.800-186 - Section 3.1.2 table 2. |
| ECDSA | secp256k1 | No | ECDSA on the secp256k1 curve (RFC 6979 deterministic). Non-FIPS only. |
| EdDSA | Ed25519, Ed448 | Yes | See FIPS-186.5. |
| ML-DSA | ML-DSA-44, ML-DSA-65, ML-DSA-87 | No (non-FIPS only) | Lattice-based signatures. NIST FIPS 204. Supersedes CRYSTALS-Dilithium. |
| SLH-DSA | SLH-DSA-SHA2/SHAKE-128/192/256-s/f (12 variants) | No (non-FIPS only) | Hash-based signatures. NIST FIPS 205. Supersedes SPHINCS+. |
Digital Signature Operations
RSASSA-PSSperforms digital signatures using RSA keys with PSS padding and NIST-approved hash functions.ECDSAperforms digital signatures on elliptic curvesP-256,P-384,P-521(FIPS), andsecp256k1(non-FIPS only). Note:X25519andX448are Diffie-Hellman exchange curves and are not used for ECDSA signatures.EdDSAperforms digital signatures on Edwards curvesEd25519andEd448.
Key derivation (KMIP DeriveKey)
The KMS exposes the KMIP DeriveKey operation, which derives a new symmetric key or secret data
from an existing key material. Two methods are supported:
| Method | Hash algorithms | FIPS mode | Notes |
|---|---|---|---|
| PBKDF2 | SHA-{1,224,256,384,512} | Yes | Default: SHA-256, 600 000 iterations (OWASP). Salt is mandatory. |
| HKDF | SHA-{1,224,256,384,512} | Yes | Default: SHA-256. Salt is optional; info (context) is optional. |
Both derivation methods are implemented via OpenSSL.
Password-based key derivation
The randomness of cryptographic keys is essential for the security of cryptographic applications. Sometimes, passwords may be the only input required from the users who are eligible to access the data. Due to the low entropy and possibly poor randomness of those passwords, they are not suitable to be used directly as cryptographic keys. The KMS addresses this problem by providing methods to derive a password into a secure cryptographic key.
In normal mode, passwords are derived using Argon2 hash algorithm with a random 128-bit salt.
Argon2 has the property of being computationally intensive making it significantly harder to crack
by brute force only.
In FIPS mode, passwords are derived using FIPS compliant PBKDF2_HMAC with SHA512 and recommended
210,000 iterations
by OWASP
which follows FIPS recommendations as well. An additional random 128-bit salt is used.
Hash functions
The Eviden server supports the following hashing algorithms:
FIPS 180-4 (SHA-2 family):
- SHA-224
- SHA-256
- SHA-384
- SHA-512
NIST FIPS 202 (SHA-3 family):
- SHA3-224
- SHA3-256
- SHA3-384
- SHA3-512
References
-
NIST.FIPS.140-3, Implementation Guidance for FIPS 140-3 and the Cryptographic Module Validation Program, August 1, 2023
- General information and pointers to other NIST documents concerning the FIPS standard.
-
NIST.SP.800-186, Recommendations for Discrete Logarithm-based Cryptography: Elliptic Curve Domain Parameters, February 2023
- Recommended curves for specific usage (ECDH, ECDSA, EdDSA, ...) and associated security strength. Describes each curves parameters in details.
-
NIST.SP.800-38F, Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping, December 2012
- Description of symmetric key wrapping using AES-KW and AES-KWP. Approving RFC 5649.
-
NIST.FIPS.800-132, Recommendation for Password-Based Key Derivation, December 2010
- Description of low-entropy data derivation into secure master key.
-
NIST.SP.800-56Cr2, Recommendation for Key-Derivation Methods in Key-Establishment Schemes, August 2020
- Description of high-entropy data derivation into secure master key.
-
NIST.SP.800-131Ar2, Transitioning the Use of Cryptographic Algorithms and Key Lengths, March 2019
- Key length specification for different domain parameters, algorithms and cryptographic schemes.
-
NIST.SP.800-56Ar3, Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography, April 2018
- General information on discrete logarithm parameters.
-
NIST.SP.800-56Br2, Recommendation for Pair-Wise Key Establishment Using Integer Factorization Cryptography, March 2019
- Information regarding RSA primitive specifications: key length, encryption, decryption and padding to use.
-
NIST.FIPS.180-4, Secure Hash Standard (SHS), August 2015
- Specification regarding SHA family of hash functions.
-
NIST.FIPS.202, SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions, August 2015
- Specification for SHA3.
-
NIST.FIPS.186-5, Digital Signature Standard (DSS), February 3, 2023
- Information on ECDSA, EdDSA and key generation.
-
NIST.FIPS.203, Module-Lattice-Based Key-Encapsulation Mechanism Standard, August 13, 2024
- Specification for ML-KEM (supersedes CRYSTALS-Kyber). Key encapsulation at security levels 1, 3, and 5.
-
NIST.FIPS.204, Module-Lattice-Based Digital Signature Standard, August 13, 2024
- Specification for ML-DSA (supersedes CRYSTALS-Dilithium). Lattice-based digital signatures at security levels 2, 3, and 5.
-
NIST.FIPS.205, Stateless Hash-Based Digital Signature Standard, August 13, 2024
- Specification for SLH-DSA (supersedes SPHINCS+). Hash-based digital signatures using SHA2 or SHAKE, 12 parameter sets.
-
NIST.FIPS.800-135r1, Recommendation for Existing Application-Specific Key Derivation Functions, December 2011
-
OpenSSL FIPS 140-2 Security Policy, 26 January 2023
- OpenSSL official documentation
KMIP algorithm policy (server-side)
The cosmian_kms_server crate can enforce a KMIP algorithm policy at request entry points (and on retrieved keys).
The policy selector is kmip.policy_id.
You can also set it via:
- CLI:
--kmip-policy-id(case-insensitive) - Env var:
KMS_POLICY_ID
Accepted values (case-insensitive):
DEFAULT: enforce the built-in conservative allowlists.CUSTOM: enforce the allowlists you provide under[kmip.allowlists](use with caution).
Enabling the default policy
If kmip.policy_id is unset, the KMIP policy layer is disabled.
To explicitly select the built-in default policy, set kmip.policy_id = "DEFAULT" in kms.toml (or pass it on the command line):
[kmip]
policy_id = "DEFAULT"
CLI:
cosmian_kms --kmip-policy-id DEFAULT
Env var:
export KMS_POLICY_ID=DEFAULT
Policies to use with caution
CUSTOM: enforces the allowlists under[kmip.allowlists]. Misconfiguration can unintentionally allow weak choices or, conversely, deny most operations (e.g., if you set an empty list[]).
Notes:
- When
kmip.policy_id = "DEFAULT", any[kmip.allowlists]values in the configuration file are ignored (the server uses the built-in defaults). - When
kmip.policy_id = "CUSTOM"and an allowlist key is omitted, that parameter is not restricted by an allowlist.
What the DEFAULT policy enforces
The DEFAULT policy is a conservative (ANSSI/NIST/FIPS-aligned) allowlist.
It constrains KMIP requests by validating their declared cryptographic parameters and, when applicable, the characteristics of the referenced keys.
In particular, it allowlists:
- Cryptographic algorithms (all builds):
AES,RSA,ECDSA,ECDH,EC,HMACSHA256,HMACSHA384,HMACSHA512 - Cryptographic algorithms (non-FIPS builds only):
ChaCha20Poly1305,Ed25519,SHAKE128,SHAKE256,ConfigurableKEM,MLKEM_512,MLKEM_768,MLKEM_1024 - Hash functions:
SHA256,SHA384,SHA512,SHA3256,SHA3384,SHA3512 - Signature algorithms:
SHA256WithRSAEncryption,SHA384WithRSAEncryption,SHA512WithRSAEncryption,RSASSAPSS,ECDSAWithSHA256,ECDSAWithSHA384,ECDSAWithSHA512 - Curves:
P256,P384,P521,CURVE25519,CURVE448 - Block cipher modes:
GCM,CCM,XTS,NISTKeyWrap,AESKeyWrapPadding,GCMSIV - Padding methods:
OAEP,PSS,PKCS5 - MGF hashes:
SHA256,SHA384,SHA512 - Mask generators:
MGF1
It also enforces key-size constraints:
- RSA key sizes:
3072,4096(in addition to baseline structural constraints) - AES key sizes:
128,192,256
Baseline constraints (independent from the allowlists):
- RSA keys smaller than 2048 bits are always rejected when the policy layer is enabled.
Custom allowlists (CUSTOM)
When kmip.policy_id = "CUSTOM", the policy layer uses the allowlists under [kmip.allowlists].
All allowlists follow these semantics:
- omitted key: no allowlist restriction for that parameter
- empty list
[]: deny everything for that parameter - non-empty list: allow only listed values
Allowlists are config-file only (there are no per-allowlist CLI flags).
Allowlist keys
[kmip.allowlists] supports:
algorithms: KMIPCryptographicAlgorithm(e.g."AES","RSA")hashes: KMIPHashingAlgorithm(e.g."SHA256")signature_algorithms: KMIPDigitalSignatureAlgorithm(e.g."RSASSAPSS")curves: KMIPRecommendedCurve(e.g."P256","CURVE25519")block_cipher_modes: KMIPBlockCipherMode(e.g."GCM")padding_methods: KMIPPaddingMethod(e.g."OAEP","PSS","PKCS1v15","PKCS5")rsa_key_sizes: RSA key sizes in bits (strings):"2048","3072","4096"aes_key_sizes: AES key sizes in bits (strings):"128","192","256", and optionally"512"for some AES-XTS client encodingsmgf_hashes: KMIPHashingAlgorithmfor MGF1 (e.g."SHA256")mask_generators: KMIPMaskGenerator(e.g."MGF1")
Values are matched case-insensitively against the KMIP enum display names.
Example: AES-GCM only
[kmip]
policy_id = "CUSTOM"
[kmip.allowlists]
algorithms = ["AES"]
block_cipher_modes = ["GCM"]
aes_key_sizes = ["256"]
Example: RSA-OAEP with RSA-3072+
[kmip]
policy_id = "CUSTOM"
[kmip.allowlists]
algorithms = ["RSA"]
padding_methods = ["OAEP"]
hashes = ["SHA256", "SHA384", "SHA512"]
mask_generators = ["MGF1"]
mgf_hashes = ["SHA256", "SHA384", "SHA512"]
rsa_key_sizes = ["3072", "4096"]
Zeroization
Secret keys and plaintexts are considered highly sensitive information and to securely erase from
memory or storage Eviden KMS implements data zeroization.
The term zeroization originates from the process of setting all relevant bits to zero, effectively
rendering the data unreadable and unrecoverable.
This practice is essential to prevent unwanted memory residue of critical data,
especially in scenarios where the confidentiality and integrity of data are paramount.
This is particularly crucial in environments where multiple users or processes access the same resources, but this does not prevent in any way an attacker reading from live memory as the latter may not be encrypted.
It is good to notice that in the source code, only keys and plaintexts represented as byte arrays
are being zeroized using the zeroize crate.
Regarding OpenSSL PKey types, they are being zeroized by OpenSSL itself, which is triggered on
drop by Rust.
EVP_PKEYs are dropped with EVP_PKEY_free, which should use the appropriate cipher-internal freeing function, which in turn should cleanse all private data unless there is a bug in the underlying OpenSSL library [...]. source
Regulatory Compliance
Eviden KMS thus adheres to relevant industry standards and regulatory requirements concerning data security and privacy such as the Rust guidelines from ANSSI. The use of zeroization aligns with this standard, demonstrating our commitment to safeguarding sensitive information and meeting the necessary compliance obligations.
Software Bill of Materials (SBOM)
A Software Bill of Materials (SBOM) is a formal record of all components, libraries, and dependencies used to build a software artifact — analogous to an ingredient list for software. Eviden KMS ships SBOMs for every release to support:
- Supply chain security: identify exactly which packages and versions are included in each build.
- Vulnerability management: cross-reference components against CVE databases to detect known vulnerabilities before they reach production.
- License compliance: audit open-source licenses across the full dependency tree.
- Regulatory requirements: satisfy NTIA, CISA, and EU CRA SBOM mandates for critical software.
Artifacts
SBOMs are generated from Nix build outputs, providing a complete and reproducible view of runtime dependencies. They are available for all build variants:
| Artifact | Variants | Location |
|---|---|---|
| KMS server | fips / non-fips × static / dynamic | sbom/server/<variant>/<link>/ |
ckms CLI | fips / non-fips × static / dynamic | sbom/ckms/<variant>/<link>/ |
| OpenSSL 3.1.2 (FIPS derivation) | — | sbom/openssl_3_1_2/ |
| OpenSSL 3.6.0 (non-FIPS derivation) | — | sbom/openssl_3_6_0/ |
Each output directory contains:
| File | Format | Purpose |
|---|---|---|
bom.cdx.json | CycloneDX 1.5 JSON | Import into SBOM platforms (e.g., Dependency-Track) |
bom.spdx.json | SPDX 2.3 JSON | License compliance and SPDX tooling |
sbom.csv | CSV | Tabular component inventory |
vulns.csv | CSV | Deduplicated vulnerability rows (CVE/OSV/Grype/Vulnix) |
graph.png | PNG | Visual dependency graph |
meta.json | JSON | Build metadata (variant, link, counts, timestamps) |
The default FIPS static server SBOM is at
sbom/server/fips/static/bom.cdx.json.
Vulnerability scanning
Vulnerability data is produced by vulnxscan, which aggregates three sources:
- Grype — scans against NVD, GitHub Security Advisories, and other databases.
- Vulnix — scans against the NixOS security tracker with Nix-specific package context.
- OSV — queries the OSV database for additional coverage.
Duplicate CVE rows (e.g. CVE-2026-0915, UBUNTU-CVE-2026-0915, DEBIAN-CVE-2026-0915) are
collapsed to a single entry by nix/scripts/dedup_cves.py before the file is committed.
Regenerating the SBOM
Re-run after any change to Cargo.lock or the package version:
# All combinations (server + ckms + OpenSSL derivations)
mise run sbom:generate
# Server only — one specific combination
mise run sbom:generate --target server --variant fips --link static
# OpenSSL 3.6.0 derivation only
mise run sbom:generate --target openssl_3_6_0
See sbom/README.md for the full regeneration guide and usage
examples (Dependency-Track upload, jq queries, vulnerability review).
Standards & references
- CycloneDX specification
- SPDX specification — ISO/IEC 5962:2021
- NTIA SBOM guidance
- CISA SBOM resources
- sbomnix toolchain
Cryptography Bill of Materials (CBOM)
A Cryptography Bill of Materials (CBOM) is a formal inventory of all cryptographic assets used in a software system — algorithms, key types, parameters, and the libraries that implement them. It follows the CycloneDX 1.6 standard and is designed to support:
- Crypto-agility audits: identify which algorithms are in use and where, to plan migration when standards change (e.g. deprecation of RSA-2048 or SHA-1).
- Post-quantum readiness: track which operations still rely on classical algorithms vulnerable to quantum attacks.
- Compliance reporting: demonstrate that only approved algorithms are in use for FIPS or other regulatory frameworks.
- Supply chain security: record implementing libraries (e.g. OpenSSL, RustCrypto) with their versions alongside the algorithms they provide.
CBOM artifact
The Eviden KMS CBOM is generated from the actual source code and Cargo.lock, ensuring it
reflects the running codebase rather than a manual registry.
| File | Format | Description |
|---|---|---|
cbom/cbom.cdx.json | CycloneDX 1.6 JSON | Full cryptographic asset inventory |
The CBOM covers:
- All symmetric and asymmetric algorithms (AES-GCM, ChaCha20-Poly1305, RSA, ECDSA, EdDSA, …)
- Post-quantum algorithms (ML-KEM, ML-DSA, SLH-DSA, Covercrypt)
- Key derivation functions (PBKDF2, HKDF, Argon2)
- Hash functions (SHA-2, SHA-3)
- Key encapsulation and wrapping schemes
- The implementing Rust crates (RustCrypto, OpenSSL, Eviden) with versions from
Cargo.lock - FIPS compliance status per algorithm
Regenerating the CBOM
Re-run the generator after any algorithm or dependency change:
python3 .mise/scripts/sbom/generate_cbom.py --output cbom/cbom.cdx.json
The script:
- Runs
cargo metadata --features non-fipsto read implementing-library versions fromCargo.lock. - Scans Rust source files under
crate/to confirm each algorithm is actively referenced. - Emits a CycloneDX 1.6 CBOM JSON document.
Only the algorithm catalogue inside the script requires manual maintenance when a new algorithm is added or removed; library versions and source-scan results are refreshed automatically.
Importing into SBOM platforms
The CBOM uses the same CycloneDX format as the SBOM, so it can be imported into any CycloneDX-compatible platform such as Dependency-Track:
curl -X POST "https://dtrack.example.com/api/v1/bom" \
-H "X-Api-Key: ${API_KEY}" \
-H "Content-Type: multipart/form-data" \
-F "project=${PROJECT_UUID}" \
-F "bom=@cbom/cbom.cdx.json"
Standards & references
- CycloneDX CBOM specification
- NIST Post-Quantum Cryptography standards
- CISA Post-Quantum Cryptography initiative
🔐 kms — Cryptographic Posture Report
ℹ️ Auto-generated report — do not edit by hand
ℹ️ Auto-generated report — do not edit by hand
Last commit: 70512c0b
To regenerate:
bash .mise/scripts/audit/crypto_sensor.sh --repo-root .
🎯 Security Posture Scorecard
HIGH findings are not covered by a KMIP-spec mitigation. Review the Priority Remediation section below.
📊 Discovery Overview
| Severity | Count | Context |
|---|---|---|
| 🔴 CRITICAL | 21 | Broken algorithms (DES·MD5·RC4) — all KMIP spec enums, blocked at runtime |
| 🟠 HIGH | 41 | Weak key sizes (RSA-1024·EC-P192) and deprecated SHA-1 |
| 🟡 MEDIUM | 0 | Medium-severity issues |
| 🔵 LOW / ⚪ INFO | 2449 | Informational algorithm usage references |
pie title Sensor findings by severity "CRITICAL" : 21 "HIGH" : 41 "INFO" : 2449
Reference counts = source lines matching each algorithm pattern.
| Algorithm | Category | FIPS 140-3 | PQC | Refs |
|---|---|---|---|---|
| PKCS#11/HSM | HSM interface | ❌ | — | 559 |
| RSA | Asymmetric | ✅ | ❌ | 248 |
| X.509 certificate | PKI / TLS | ✅ | — | 233 |
| ML-KEM (FIPS 203) | Post-Quantum KEM | ✅ | ✅ | 225 |
| SLH-DSA (FIPS 205) | Post-Quantum Signature | ✅ | — | 223 |
| Covercrypt (ABE) | Attribute-Based Encryption | ❌ | — | 197 |
| ML-DSA (FIPS 204) | Post-Quantum Signature | ✅ | — | 141 |
| EdDSA (Ed25519/Ed448) | Asymmetric | ✅ | ❌ | 141 |
| AES-GCM/GCM-SIV | Symmetric | ✅ | — | 66 |
| Argon2 | KDF | ❌ | — | 26 |
| Hybrid KEM | Classical + PQC | ✅ | ✅ | 24 |
| EC-P192 | Asymmetric — WEAK KEY | ❌ | ❌ | 20 |
| EC (ECDSA/ECDH) | Asymmetric | ✅ | ❌ | 15 |
| DES/3DES | Symmetric — DEPRECATED | ❌ | — | 15 |
| SHA-1 | Hash — deprecated for signing | ❌ | — | 13 |
| ChaCha20-Poly1305 | Symmetric (non-FIPS) | ❌ | — | 8 |
| RSA-1024 | Asymmetric — WEAK KEY | ❌ | ❌ | 8 |
| RC4 | Symmetric — BROKEN | ❌ | — | 5 |
| SHA-2/SHA-3 | Hash | ✅ | — | 1 |
| MD5 | Hash — BROKEN | ❌ | — | 1 |
Deprecated entries in
kmip_1_4/are KMIP spec enum definitions — not active operations. Blocked at runtime byalgorithm_policy.rs.
pie title Algorithm usage by category "PKCS#11 / HSM" : 559 "Asymmetric (RSA)" : 248 "TLS / X.509" : 233 "PQC (ML-KEM)" : 225 "PQC (SLH-DSA)" : 223 "ABE (Covercrypt)" : 197 "PQC (ML-DSA)" : 141 "Asymmetric (EdDSA)" : 141 "Symmetric (AES)" : 66 "Asymmetric — weak" : 28 "KDF (Argon2)" : 26 "PQC (Hybrid KEM)" : 24 "Asymmetric (EC)" : 15 "Symmetric (deprecated)" : 15 "Hash (deprecated)" : 13 "Symmetric (ChaCha20)" : 8 "Symmetric (RC4)" : 5 "Hash (SHA-2/3)" : 1 "Hash (MD5)" : 1
| Dependency | Description | Standard | Cargo.toml refs |
|---|---|---|---|
openssl (FIPS provider) | openssl (FIPS provider) | 85 | |
openssl | OpenSSL 3.6 (FIPS provider) | FIPS 140-3 | 34 |
cosmian_crypto_core | cosmian_crypto_core | 5 | |
x509-parser | x509-parser | RFC 5280 | 4 |
p256 | p256 (NIST P-256) | FIPS 186-5 | 3 |
rustls | rustls (TLS) | RFC 8446 | 2 |
aes-gcm | RustCrypto/aes-gcm-siv | RFC 8452 | 1 |
argon2 | RustCrypto/argon2 | RFC 9106 | 1 |
cosmian_cover_crypt | cosmian_cover_crypt | 1 | |
k256 | k256 (secp256k1) | 1 | |
ring | ring (BoringSSL subset) | 1 |
flowchart TD
KMS["kms"]
KMS --> OPENSSL__FIPS_PROVIDER_["openssl (FIPS provider)"]
KMS --> OPENSSL["OpenSSL (FIPS provider)"]
KMS --> COSMIAN_CRYPTO_CORE["cosmian_crypto_core (KEM combiner)"]
KMS --> X509_PARSER["x509-parser"]
KMS --> P256["p256 NIST P-256"]
KMS --> RUSTLS["rustls (TLS)"]
KMS --> AES_GCM["RustCrypto/aes-gcm"]
KMS --> ARGON2["RustCrypto/argon2"]
KMS --> COSMIAN_COVER_CRYPT["cosmian_cover_crypt (ABE)"]
KMS --> K256["k256 secp256k1"]
KMS --> RING["ring (BoringSSL subset)"]
⚡ Priority Remediation
62 CRITICAL + HIGH total | 1 actionable | 61 suppressed by KMIP policy
| # | Severity | Algorithm | File | Detail | Remediation |
|---|---|---|---|---|---|
| 1 | 🟠 HIGH | EC-P192 | ttlv/enum_lookup.rs:200 | P-192 is below the 112-bit security level. Use P-256 or higher. | Upgrade to P-256 or higher curve. |
🚀 Post-Quantum Readiness
Score: 59% — 59% of asymmetric operations have a PQC alternative.
pie title PQC vs Classical asymmetric coverage
"PQC-ready (ML-KEM, ML-DSA, SLH-DSA, Hybrid)" : 59
"Classical-only (RSA, EC, EdDSA)" : 41
| Standard | Algorithm | Status |
|---|---|---|
| FIPS 203 | ML-KEM (CRYSTALS-Kyber) | ✅ |
| FIPS 204 | ML-DSA (CRYSTALS-Dilithium) | ✅ |
| FIPS 205 | SLH-DSA (SPHINCS+) | ✅ |
| CNSA 2.0 | Hybrid KEM (classical + PQC) | ✅ |
| RFC 8032 | EdDSA (Ed25519 / Ed448) | ✅ |
| FIPS 186-5 | ECDH / ECDSA (P-256+) | ✅ |
FIPS 203, 204, 205 and CNSA 2.0 Hybrid KEM are already deployed. The European Commission end-of-2026 inventory mandate is addressed.
🔒 FIPS 140-3 Compliance
Score: 49% of detected algorithm references are FIPS 140-3 approved.
The remaining 51% are:
| Category | Reason |
|---|---|
| PKCS#11 / HSM | FIPS status depends on the certified HSM hardware |
| Covercrypt ABE | Attribute-based encryption — FIPS not applicable |
| ChaCha20-Poly1305 | Non-FIPS builds only (--features non-fips) |
| KMIP 1.4 legacy enums | Type definitions — not active crypto operations |
cargo build (without --features non-fips) exercises only FIPS 140-3
approved algorithms at runtime.
🛡️ Memory Safety — Zeroize Discipline
The sensor found 204 references to Zeroizing<T> / ZeroizeOnDrop
across the codebase — automatic key-material zeroing on drop (CWE-316 mitigation).
All derived key material (HKDF, PBKDF2) and private key bytes are wrapped in
Zeroizing<Vec<u8>> — secrets are scrubbed from memory when their scope ends.
🔍 How the Sensor Works
flowchart LR
A["Discover\nScan Rust sources\n& Cargo.toml"] --> B["Analyze\nApply risk rules\nMatch KMIP context"]
B --> C["Prioritize\nSeverity scoring\nMitigation tagging"]
C --> D["Report\nCBOM & MkDocs\nJSON + Markdown"]
D --> E["Monitor\nPre-commit hook\nCI integration"]
style A fill:#f0f9ff,stroke:#0ea5e9
style B fill:#fefce8,stroke:#eab308
style C fill:#fff7ed,stroke:#f97316
style D fill:#f0fdf4,stroke:#22c55e
style E fill:#faf5ff,stroke:#a855f7
| Layer | Tool | What it discovers |
|---|---|---|
| Source code | scan_source.py | Algorithm usage, deprecated primitives, weak keys, hardcoded material, PQC/zeroize |
| Dependency tree | cdxgen (OWASP CycloneDX) | Cryptographic library versions from Cargo.lock |
| CVE feed | cargo audit (RustSec) | Known vulnerabilities in crypto dependencies |
| Live TLS | testssl.sh (optional) | Cipher suites, certificate chain, TLS version |
The sensor outputs a Cryptographic Bill of Materials (CBOM) in CycloneDX 1.6 format
(see cbom/cbom.cdx.json).
▶️ How to Run
Full scan — source + CVE + CBOM (also updates this page)
Full scan — source + CVE + CBOM (also updates this page)
bash .mise/scripts/audit/crypto_sensor.sh --repo-root .
# With live TLS scan:
bash .mise/scripts/audit/crypto_sensor.sh \\
--repo-root . --server-url https://localhost:9998 --update-cbom
Source scanner only (fast, no network)
Source scanner only (fast, no network)
python3 .mise/scripts/audit/scan_source.py \\
--repo-root . --output /tmp/findings.json
Risk scorer + page regeneration
Risk scorer + page regeneration
python3 .mise/scripts/audit/risk_score.py \\
--input /tmp/findings.json \\
--output-json /tmp/risk_report.json \\
--docs-output documentation/docs/certifications_and_compliance/audit/crypto_inventory.md
Output files are written to cbom/sensor/ (stable path — overwritten on each run):
| File | Content |
|---|---|
findings.json | Raw per-line source scanner findings |
risk_report.json | Risk-scored findings + CVE data |
cargo_audit.json | CVE advisory data |
dep_cbom.json | Dependency-level CBOM (cdxgen) |
tls_report.txt | TLS scan output (if --server-url was given) |
🔗 Related Documentation
- CBOM (CycloneDX) — full CycloneDX 1.6 CBOM file
- SBOM — software bill of materials
- FIPS 140-3 — FIPS compliance details
- Cryptographic algorithms — algorithm reference
- Zeroization — memory-safety approach for key material
- Security Audit (OWASP) — OWASP Top 10 audit
- Multi-Framework Audit — NIST/CIS/ISO/OSSTMM audit
Eviden KMS — OWASP Security Audit Plan & Report
Document type: Security Audit Plan & Report Template
Standard: OWASP Top 10 (2021) + OWASP ASVS v4.0 (selective)
Repository: Eviden/kms — branch develop
Workspace root: crate/ (Rust workspace) + ui/ (React/TypeScript)
Audit date: 2026-06-05 (re-run with remediation verification: 2026-04-14)
Auditor(s): GitHub Copilot (automated static analysis)
Status: ☑ Complete — automated pass (audit.sh ran 2026-06-05)
Tools available during this audit
| Tool | Version | Status | Notes |
|---|---|---|---|
cargo-audit | 0.22.1 | ✅ Available | Advisory DB scan |
cargo-deny | 0.19.0 | ✅ Available | Policy check (bans, licenses, advisories, sources) |
cargo-outdated | 0.17.0 | ✅ Available | Outdated dep detection |
cargo-geiger | 0.13.0 | ⚠️ Installed — partial | Fails on virtual workspace manifest with bug (#378); fallback: manual grep -r "unsafe " |
semgrep | — | ❌ Not installed | Static pattern matching — install per §1 |
gitleaks / trufflehog3 | — | ❌ Not installed | Secret scanning — install per §1 |
cargo-geiger 0.13.0fails witherror: No such file or directory — crate/cli/src/lib.rswhen invoked against this virtual workspace. This is a known upstream bug. The A06 section below uses manualgrep -r "unsafe"counts as a validated substitute.
Table of Contents
- Tool Installation
- A01 – Broken Access Control
- A02 – Cryptographic Failures
- A03 – Injection
- A04 – Insecure Design
- A05 – Security Misconfiguration
- A06 – Vulnerable and Outdated Components
- A07 – Identification and Authentication Failures
- A08 – Software and Data Integrity Failures
- A09 – Security Logging and Monitoring Failures
- A10 – Server-Side Request Forgery (SSRF)
- EXT-0 – KMS Own Authorization System
- EXT-1 – Cryptographic Key Lifecycle & Zeroization
- EXT-2 – Denial of Service / Resource Exhaustion
- Remediation Priority Matrix
- Report Sign-off
1. Tool Installation
Install every tool before starting the audit. Run all commands from the workspace root.
1.1 Rust security toolchain
# Audit Rust dependencies for known CVEs (RustSec Advisory DB)
cargo install cargo-audit
# Policy-based dependency checking (licenses, bans, advisories)
# cargo-deny is already configured: deny.toml exists at workspace root
cargo install cargo-deny
# Count and locate `unsafe` blocks across the workspace
cargo install cargo-geiger
# Find outdated dependencies
cargo install cargo-outdated
# Verify tool versions
cargo audit --version
cargo deny --version
cargo geiger --version
cargo outdated --version
1.2 Secrets scanning
# Option A: gitleaks (scan git history + working tree for accidentally committed secrets)
curl -sSfL \
https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_linux_amd64.tar.gz \
| tar xz && sudo mv gitleaks /usr/local/bin/
gitleaks version
# Option B: trufflehog (entropy-based secret detection)
pip3 install truffleHog3
trufflehog3 --version
1.3 SAST — Semgrep
# Install semgrep
pip3 install semgrep
semgrep --version
# Verify the Rust and OWASP rulesets are reachable (requires internet)
semgrep --config p/rust --test 2>/dev/null || true
semgrep --config p/owasp-top-ten --test 2>/dev/null || true
semgrep --config p/secrets --test 2>/dev/null || true
1.4 Readiness check
echo "=== Tool readiness ===" && \
cargo audit --version && \
cargo deny --version && \
cargo geiger --version && \
cargo outdated --version && \
semgrep --version && \
(gitleaks version 2>/dev/null || trufflehog3 --version 2>/dev/null || \
echo "WARNING: no secrets scanner found")
2. A01 – Broken Access Control
OWASP description: Restrictions on what authenticated users are allowed to do are not properly enforced. Attackers can exploit these flaws to access unauthorized functionality and/or data.
2.1 Scope
| Area | Key files |
|---|---|
| Auth middleware stack | crate/server/src/middlewares/ensure_auth.rs |
| KMIP route handler | crate/server/src/routes/kmip.rs |
| Access grant / revoke endpoints | crate/server/src/routes/access.rs |
| Unauthenticated public endpoints | crate/server/src/routes/health.rs, root_redirect.rs |
| Server app builder (middleware order) | crate/server/src/start_kms_server.rs |
| Enterprise route auth | crate/server/src/routes/aws_xks/, azure_ekm/, google_cse/, ms_dke/ |
2.2 Investigation Steps
# Step 1 — Enumerate all HTTP routes; identify routes registered WITHOUT
# the standard auth middleware chain
grep -rn \
"web::resource\|web::route\|web::scope\|#\[get\]\|#\[post\]\|#\[put\]\|#\[delete\]" \
crate/server/src/routes/ --include="*.rs"
# Step 2 — Inspect the full middleware assembly order
# Auth wrappers MUST be registered before route handlers
grep -n "App::new\|\.wrap\|\.configure\|\.service" \
crate/server/src/start_kms_server.rs
# Step 3 — Confirm which middleware types protect which routes
grep -rn "EnsureAuth\|JwtMiddleware\|ApiTokenMiddleware\|TlsAuthMiddleware" \
crate/server/src/ --include="*.rs"
# Step 4 — Look for any explicit auth skip or bypass condition
grep -rn "skip\|bypass\|no_auth\|#\[cfg(feature.*insecure" \
crate/server/src/middlewares/ --include="*.rs"
# Step 5 — Horizontal privilege escalation: can a user access another user's objects
# without an explicit grant? Inspect owner check in retrieve_object_for_operation
grep -n "owner\|user_has_permission\|is_object_owned_by" \
crate/server/src/core/retrieve_object_utils.rs
# Step 6 — Semgrep: path traversal and broken access control patterns
semgrep --config p/owasp-top-ten \
crate/server/src/routes/ --lang rust 2>/dev/null \
| grep -i "access\|path\|traversal" || true
2.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server/src/start_kms_server.rscrate/server/src/middlewares/ensure_auth.rs,tls_auth.rs,api_token/,jwt/crate/server/src/routes/health.rs,access.rs,kmip.rscrate/server/src/core/retrieve_object_utils.rs
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A01-1 | start_kms_server.rs:776,795,806,901,962 | Medium | Cors::permissive() applied to all scopes including the main KMIP endpoint. This allows cross-origin requests from any domain, enabling browser-based cross-site attacks against the KMIP API. |
| A01-2 | routes/health.rs:47 | Info | /health is a public (unauthenticated) endpoint that calls kms.get_user(&req) and logs the result. On an unconfigured server the default username is logged on every health probe. Not a direct vulnerability but reveals configuration state. |
| A01-3 | middlewares/ensure_auth.rs:128 | Info | EnsureAuth correctly skips itself when the request is already authenticated (comment confirms intent). No bypass risk. |
Recommended fix:
- A01-1: Replace
Cors::permissive()with an explicit allowlist (Cors::default().allowed_origin(…)) for all scopes. For KMIP, restrict to known client origins or require mTLS instead of relying on CORS. - A01-2: Move the
get_userlog line behind anif tracing::enabled!(Level::DEBUG)guard, or remove it from public endpoints.
OWASP description: Failures related to cryptography (data at rest, data in transit, key management, algorithm choices) that often lead to exposure of sensitive data.
3. A02 – Cryptographic Failures
3.1 Scope
| Area | Key files |
|---|---|
| Crypto primitives | crate/crypto/src/ (all subdirectories) |
| Key export enforcement | crate/server/src/core/operations/export_get.rs |
| Key wrapping / unwrapping | crate/server/src/core/wrapping/wrap.rs, unwrap.rs |
| Key storage format | crate/kmip/src/ — EncryptedKeyBlock, KeyMaterial types |
| OpenSSL build & hash | crate/crypto/build.rs |
| TLS configuration | crate/server/src/config/command_line/tls_config.rs |
3.2 Investigation Steps
# Step 1 — Search for hardcoded keys, zero IVs, or predictable nonces
grep -rn "\[0u8; 16\]\|\[0u8; 32\]\|\[0u8; 12\]\|nonce.*=.*\[0\|iv.*=.*\[0" \
crate/crypto/src/ --include="*.rs"
# Step 2 — Deprecated / weak algorithms (ECB mode, DES, RC4, MD5, SHA-1)
grep -rni "ecb\|des\b\|rc4\|md5\|sha1\b\|sha-1\|rc2\|md4" \
crate/ --include="*.rs" | grep -v "//\|#\[doc\|test_" | head -30
# Step 3 — Sensitive key export: verify the sensitive flag blocks unprotected export
grep -n "sensitive\|key_wrapping_specification\|Sensitive\|is_sensitive" \
crate/server/src/core/operations/export_get.rs
# Step 4 — Non-FIPS algorithm use must be gated behind the non-fips feature flag
grep -rn "#\[cfg(feature.*non.fips\|cfg.*non_fips" \
crate/crypto/src/ --include="*.rs" | head -20
# Cross-check: algorithms that appear outside a cfg gate
grep -rni "Covercrypt\|AES.XTS\|chacha\|xchacha\|kyber\|dilithium" \
crate/crypto/src/ --include="*.rs" | grep -v "#\[cfg" | head -15
# Step 5 — In-memory cache for unwrapped key material: check zeroization on eviction
grep -n "cache\|HashMap\|DashMap\|insert\|remove\|evict\|zeroize\|Zeroizing" \
crate/server/src/core/wrapping/wrap.rs
# Step 6 — OpenSSL download: verify SHA-256 check is non-bypassable
grep -A5 -B5 "sha256\|checksum\|expected\|download\|verify" crate/crypto/build.rs
# Step 7 — Semgrep crypto-specific rules
semgrep --config p/rust crate/crypto/src/ --lang rust 2>/dev/null \
| grep -i "crypto\|cipher\|hash\|random\|seed" || true
3.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/crypto/src/crypto/symmetric/symmetric_ciphers.rscrate/crypto/src/crypto/elliptic_curves/ecies/standard_curves.rscrate/server/src/core/operations/export_get.rscrate/server/src/core/wrapping/wrap.rscrate/crypto/build.rscrate/clients/clap/src/actions/mac.rs,actions/aws/byok/export_key_material.rs
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A02-1 | symmetric_ciphers.rs:429,784 | Info | Zero-initialised buffers (vec![0; nonce_size], [0_u8; 16]) are overwritten immediately by rand_bytes() or by structured counter/nonce construction (ChaCha20). No actual hardcoded IVs. |
| A02-2 | mac.rs:17,31,47 / export_key_material.rs:92,106 | Low | SHA-1 is exposed as a user-selectable MAC/hash algorithm and used in AWS BYOK RSA-OAEP wrapping. SHA-1 is weak for MAC and PKCS#1 v1.5 is weak for key wrapping. These paths are not gated behind #[cfg(feature = "non-fips")] in the CLI actions layer even though FIPS forbids SHA-1. |
| A02-3 | standard_curves.rs:31 | Info | let mut iv = vec![0; iv_size] in ECIES — filled by OpenSSL rand_bytes. Safe; zero is a temporary placeholder. |
| A02-4 | export_get.rs:77 | ✅ | sensitive=true objects are correctly blocked from export unless key_wrapping_specification is present. Per KMIP BL-M-12-21. |
| A02-5 | wrap.rs:118–121 | Medium | Unwrapped key objects are stored in an in-memory DashMap/HashMap cache with no TTL or eviction policy visible in wrap.rs. Cached plaintext key material persists indefinitely in process heap, increasing the window for cold-boot / process-dump attacks. |
| A02-6 | build.rs:234,274–275 | ✅ | verify_hash() enforces SHA-256 check on the OpenSSL tarball. Non-empty sha256 param is required. Supply-chain integrity protected. |
Recommended fix:
- A02-2: Gate SHA-1 MAC and RSA-OAEP-SHA1 behind
#[cfg(feature = "non-fips")]or emit a deprecation warning when selected. Replace with SHA-256 defaults. - A02-5: Add a TTL (e.g. 60 s) or LRU eviction to the unwrapped-object cache. Call
zeroize()on cache values before removal.
OWASP description: Injection flaws occur when untrusted data is sent to an interpreter as part of a command or query (SQL, LDAP, OS shell, TTLV, XML).
4. A03 – Injection
4.1 Scope
| Area | Key files |
|---|---|
| Dynamic SQL query builder | crate/server_database/src/stores/sql/locate_query.rs |
| SQL backends | crate/server_database/src/stores/sql/sqlite.rs, pgsql.rs, mysql.rs |
| TTLV binary parser | crate/kmip/src/ttlv/wire/ttlv_bytes_deserializer.rs |
| TTLV XML parser | crate/kmip/src/ttlv/xml/parser.rs, deserializer.rs |
| JSON → TTLV entry point | crate/server/src/routes/kmip.rs — from_ttlv() call |
| CLI file path arguments | crate/clients/clap/src/actions/ |
4.2 Investigation Steps
# Step 1 — SQL injection: flag any dynamic SQL built with format! or string concatenation
grep -rn \
'format!.*SELECT\|format!.*INSERT\|format!.*UPDATE\|format!.*DELETE\|"SELECT.*{}' \
crate/server_database/src/ --include="*.rs"
# Step 2 — Verify parameterized query usage throughout the SQL backends
grep -n "bind\|execute\|query_as\|fetch" \
crate/server_database/src/stores/sql/locate_query.rs | head -30
# Step 3 — TTLV binary parser: length field checked before allocation?
grep -n "len\|size\|capacity\|Vec::with_capacity\|read_exact\|take\|limit" \
crate/kmip/src/ttlv/wire/ttlv_bytes_deserializer.rs
# Step 4 — Recursion depth guard in TTLV struct parser
grep -rn "depth\|recursion\|stack\|max_depth\|fn from_ttlv\|fn parse" \
crate/kmip/src/ttlv/ --include="*.rs"
# Step 5 — OS shell injection: any std::process::Command with user-supplied data?
grep -rn "Command::new\|std::process\|exec\|popen" \
crate/clients/ crate/server/ --include="*.rs"
# Step 6 — Tag / object-group injection: these are stored as strings — verify binding
grep -n "tag\|Tag\|object_group\|ObjectGroup" \
crate/server_database/src/stores/sql/locate_query.rs | head -20
# Step 7 — Semgrep injection ruleset
semgrep --config p/owasp-top-ten crate/ --lang rust 2>/dev/null \
| grep -i "inject\|sql\|command\|exec" || true
4.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server_database/src/stores/sql/locate_query.rscrate/kmip/src/ttlv/wire/ttlv_bytes_deserializer.rscrate/kmip/src/ttlv/wire/ttlv_bytes_serializer.rscrate/server/src/core/operations/locate.rscrate/server/src/routes/kmip.rscrate/server/benchmarks/bench.rs(CLI-only)
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A03-1 | stores/sql/locate_query.rs (all) | ✅ | All SQL queries use bind-parameter style (sqlx::query!, placeholder ? / $N). No string concatenation into SQL statements. No SQL injection. |
| A03-2 | ttlv_bytes_deserializer.rs:56 | High | read_ttlv() is purely recursive with no depth counter and no maximum depth check. A malicious deeply-nested TTLV binary can exhaust the call stack (stack overflow / uncontrolled recursion). An unauthenticated TTLV POST triggers this code path before any authentication (parsed at HTTP handler level). |
| A03-3 | routes/kmip.rs (XML path) | Medium | The TTLV XML parser (ttlv_xml_deserializer.rs) has a depth counter but the loop contains no max_depth enforcement — deep XML nesting proceeds without limit. |
| A03-4 | bench.rs:2815 | Info | CLI benchmark code builds a gnuplot script embedding the op operation name variable inline. This is benchmark CLI code, not reachable from the server. No server-side command injection. |
| A03-5 | All server routes | ✅ | No OS std::process::Command::new() / shell_exec calls found in production server code. |
Recommended fix:
- A03-2: Add a
depth: u32parameter toread_ttlv()and return an error whendepth > MAX_TTLV_DEPTH(suggested: 64). Example:fn read_ttlv(reader: &mut impl Read, depth: u32) -> Result<Ttlv> { if depth > 64 { return Err(...) } ... read_ttlv(reader, depth + 1) ... } - A03-3: Add
const MAX_XML_DEPTH: usize = 64;and fail whendepth >= MAX_XML_DEPTH.
5. A04 – Insecure Design
OWASP description: Missing or ineffective control design. Unlike misconfiguration, this is a structural flaw that cannot be fixed by correct configuration alone.
5.1 Scope
| Area | Key files |
|---|---|
| KMIP operation dispatcher | crate/server/src/core/operations/dispatch.rs |
| Actix-web app builder | crate/server/src/start_kms_server.rs |
| Server configuration | crate/server/src/config/ |
| KMIP lifecycle state machine | crate/kmip/src/ — object state types |
| Rate limiting | crate/server/src/middlewares/ |
5.2 Investigation Steps
# Step 1 — Max request body size: Actix default is 256 KB; look for an explicit override
grep -n "LimitPayloadSize\|max_payload_size\|PayloadConfig\|content_length\|max_body" \
crate/server/src/start_kms_server.rs crate/server/src/routes/kmip.rs
# Step 2 — Rate limiting middleware
grep -rn "RateLimiter\|rate_limit\|throttle\|governor\|leaky_bucket\|token_bucket" \
crate/server/src/ --include="*.rs"
# Step 3 — KMIP state machine: transitions must follow spec
# (PreActive → Active → Deactivated → Destroyed; no skipping)
grep -rn "Deactivated\|PreActive\|Compromised\|Destroyed\|state.*transition\|update_state" \
crate/server/src/core/operations/ --include="*.rs"
# Step 4 — Bulk operations: can one request mutate thousands of objects?
grep -rn "Locate\|for.*objects\|batch\|BulkRequest\|RequestBatchItem" \
crate/server/src/core/operations/ --include="*.rs" | head -20
# Step 5 — Locate result set: is it bounded / paginated?
grep -rn "limit\|offset\|pagination\|page_size\|LIMIT\|OFFSET\|max_items" \
crate/server_database/src/ --include="*.rs"
# Step 6 — SecretData / Opaque objects: are there constraints on size or type?
grep -rn "SecretData\|Opaque\|OpaqueData\|CertificateRequest" \
crate/server/src/core/operations/ --include="*.rs"
5.3 Findings
Status: ❌ Vulnerability found
Files inspected:
crate/server/src/start_kms_server.rscrate/server/src/core/operations/locate.rscrate/server_database/src/stores/sql/locate_query.rscrate/server/src/middlewares/
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A04-1 | start_kms_server.rs:767-768 | High | HTTP request body limit is set to 10 GB: PayloadConfig::new(10_000_000_000) and JsonConfig::default().limit(10_000_000_000). Any unauthenticated or authenticated client can send a 10 GB request body, potentially exhausting server RAM and causing out-of-memory termination. |
| A04-2 | All server middlewares | High | No rate-limiting middleware is registered anywhere in the Actix-web application. There is no throttling on KMIP operations, API token verification, or UI login. An attacker can issue unlimited requests per second, allowing brute-force of API tokens and CPU/memory exhaustion. |
| A04-3 | operations/locate.rs:96-101 | Medium | The MaximumItems field in a Locate request is fully client-controlled and optional. When absent, the server returns all matching objects. There is no server-side cap on the result set size. A client owning or co-owning a large number of objects can trigger a very large response. |
| A04-4 | operations/dispatch.rs | ✅ | KMIP state machine transitions (PreActive→Active→Deactivated→Destroyed) are enforced via activate.rs, revoke.rs, destroy.rs. Invalid transitions are rejected with ItemNotFound or state-error. |
| A04-5 | operations/locate.rs + batch_items.rs | ✅ | Batch request item limit: the KMIP spec allows batch requests; each item is individually dispatched and access-controlled. No uncontrolled bulk mutation discovered beyond the Locate unbounded-result issue. |
Recommended fix:
- A04-1: Reduce
PayloadConfigandJsonConfiglimits to a realistic maximum (e.g. 64 MB for KMIP bodies, 1 MB for JSON config). UsePayloadConfig::new(64 * 1024 * 1024). - A04-2: Add a rate-limiting middleware using
actix-governorortower-governor. Apply globally plus a stricter limit on authentication endpoints. - A04-3: Add a server-side cap: if
MaximumItemsis absent or exceeds a configuredmax_locate_items(default 1 000), clamp the SQLLIMITto that value.
6. A05 – Security Misconfiguration
OWASP description: The most commonly seen issue, resulting from insecure default configurations, missing hardening, verbose error messages, or open cloud storage.
6.1 Scope
| Area | Key files |
|---|---|
| All server CLI flags & defaults | crate/server/src/config/command_line/ (all files) |
| TLS settings | crate/server/src/config/command_line/tls_config.rs |
| UI authentication & CORS | crate/server/src/routes/ui_auth.rs |
| OpenSSL provider init | crate/server/src/openssl_providers.rs |
| Error response format | crate/server/src/routes/kmip.rs — error handling |
6.2 Investigation Steps
# Step 1 — Enumerate all default values for security-sensitive flags
grep -n "default_value\|default.*=\s*\"\|fn default()" \
crate/server/src/config/command_line/clap_config.rs | head -50
# Step 2 — TLS: minimum protocol version and cipher suite defaults
grep -rn "TLSv1\|tls_cipher\|cipher_suite\|TlsVersion\|min_protocol\|SSLv" \
crate/server/src/config/ --include="*.rs"
grep -n "tls_p12\|tls_cert\|tls_key\|tls_chain\|clients_ca" \
crate/server/src/config/command_line/tls_config.rs
# Step 3 — CORS: look for wildcard origins or missing CORS restrictions
grep -rn "Cors\|allow_origin\|AllowedOrigin\|allow_any_origin" \
crate/server/src/ --include="*.rs"
# Step 4 — Error messages: do they expose stack traces or internal paths?
grep -rn "backtrace\|debug_info\|internal_err\|unwrap()\|expect(" \
crate/server/src/routes/ --include="*.rs" | head -20
# Step 5 — Dangerous feature flags that weaken security
grep -rn "insecure\|skip.*expir\|no.verify\|allow_self_signed" \
crate/server/src/ --include="*.rs" | grep -v "#\[cfg\|cfg(feature\|//.*insecure"
# Step 6 — Environment variable names that carry secrets: verify none are logged
grep -rn 'KMS_.*PASSWORD\|KMS_.*SECRET\|KMS_.*KEY\|KMS_.*TOKEN' \
crate/server/src/ --include="*.rs"
# Step 7 — Secrets scanner: detect hardcoded credentials
semgrep --config p/secrets crate/ --lang rust 2>/dev/null | head -30 || true
gitleaks detect --source . --no-git 2>/dev/null | head -30 || true
6.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server/src/start_kms_server.rscrate/server/src/config/command_line/tls_config.rscrate/server/src/openssl_providers.rsdeny.toml
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A05-1 | start_kms_server.rs:776,795,806,901,962 | Medium | Cors::permissive() applied on every scope: main KMIP, UI, Google CSE, MS DKE, AWS XKS. Sets Access-Control-Allow-Origin: *, allowing any browser origin to reach the KMIP endpoint cross-origin. |
| A05-2 | config/command_line/tls_config.rs | Low | TLS minimum version is not explicitly configured in code. Relies on OpenSSL 3.6.2 default (TLS 1.2+). Should be made explicit. |
| A05-3 | middlewares/jwt/jwt_config.rs:10,155 | Medium | The insecure feature completely disables all JWT validation (signature, expiry, audience). No compile-time guard prevents this feature from reaching production. If accidentally included in a production build, any token is accepted. |
| A05-4 | deny.toml | Low | RUSTSEC-2026-0097 is allow-listed in the cargo deny policy. Should be resolved by upgrading rand instead of permanently suppressing the advisory. |
| A05-5 | All routes | ✅ | Error responses use KMIP error codes; no stack traces or file paths exposed in HTTP responses. |
Recommended fix:
- A05-1: Replace
Cors::permissive()withCors::default().allowed_origin("https://your-kms-domain.example.com")or configure allowed origins from server config. - A05-3: Add
#[cfg(all(not(test), feature = "insecure"))] compile_error!("insecure feature must not be enabled in production");near the top ofjwt_config.rs.
7. A06 – Vulnerable and Outdated Components
OWASP description: Components run with the same privileges as the application. If a vulnerable component is exploited it can cause serious data loss or server takeover.
7.1 Scope
| Area | Files |
|---|---|
| Workspace dependencies | Cargo.toml (root) + all crate/*/Cargo.toml |
| Deny policy | deny.toml |
| OpenSSL build + hash | crate/crypto/build.rs |
| UI dependencies | ui/package.json, ui/pnpm-lock.yaml |
| Git history | .git/ |
7.2 Investigation Steps
# Step 1 — Scan Rust dependencies for known CVEs (RustSec Advisory DB)
cargo audit
# Step 2 — Policy-based check: licenses, banned crates, advisories, duplicates
cargo deny check
# Step 3 — List outdated crates vs latest on crates.io
cargo outdated --workspace
# Step 4 — Count unsafe code per crate (establish risk baseline)
cargo geiger --workspace 2>/dev/null | tail -50
# Step 5 — Verify OpenSSL source is pinned and SHA-256-verified in build script
grep -A5 -B5 "openssl.*version\|OPENSSL_VERSION\|sha256\|expected_hash\|verify" \
crate/crypto/build.rs | head -30
# Step 6 — UI dependency audit
cd ui && pnpm audit 2>/dev/null || npm audit 2>/dev/null; cd ..
# Step 7 — Git-sourced Rust deps (bypass crates.io auditing)
grep -rn "git = \|branch = \|rev = " Cargo.toml crate/*/Cargo.toml
# Step 8 — Scan full git history for accidentally committed secrets
gitleaks detect --source . 2>/dev/null | head -30 || \
trufflehog3 --no-entropy . 2>/dev/null | head -30 || \
echo "Run a secrets scanner manually"
7.3 Findings
Status: ⚠️ Review needed
Files inspected: Cargo.toml (workspace), deny.toml, crate/crypto/build.rs
cargo audit output (2026-04-13):
Warning: 2 vulnerabilities found!
crate: rand version: 0.8.5 advisory: RUSTSEC-2026-0097 (allow-listed)
crate: rand version: 0.9.2 advisory: RUSTSEC-2026-0097 (allow-listed)
cargo deny check: passes with warnings (advisory allow-listed in deny.toml)
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A06-1 | Cargo.toml (workspace) | Medium | RUSTSEC-2026-0097 affects rand 0.8.5 and rand 0.9.2 — two separate version trees coexisting in the dependency graph. Advisory covers unseeded PRNG panic under unusual usage. Suppressed rather than resolved. |
| A06-2 | Cargo.toml (workspace) | Low | 20+ duplicate crate versions: base64 (×3: 0.13, 0.21, 0.22), hashbrown (×4: 0.12–0.15), rand (×2), opentelemetry (×2), time (×3), etc. Increases supply-chain surface and binary size. |
| A06-3 | crate/crypto/build.rs:234,274 | ✅ | OpenSSL 3.6.2 tarball is SHA-256-verified (verify_hash()) before extraction. Version pinned by constant. Supply-chain integrity protected. |
| A06-4 | All Cargo.toml files | ✅ | No git = sourced Rust dependencies. All deps come from crates.io. |
| A06-5 | ui/pnpm-lock.yaml | Info | UI npm/pnpm audit was not run during this automated pass. Manual pnpm audit --audit-level moderate recommended. |
| A06-6 | Workspace (crate/clients/wasm/Cargo.toml) | Low | cargo outdated shows cosmian_kms_client_wasm requires getrandom with the js feature, but the installed version (0.4.2) no longer exposes that feature. This causes cargo outdated to fail for the WASM crate. The WASM build may silently use a mismatched getrandom version in non-browser target builds. |
| A06-7 | workspace (geiger scan) | Info | cargo-geiger 0.13.0 fails on this virtual workspace with a known upstream bug. Manual grep -r "unsafe " shows: crate/server/src/ (5 files, 22 uses — all OpenSSL FFI + FIPS env setup), crate/crypto/src/ (5 files, 35 uses — OpenSSL/PQC FFI), crate/server_database/src/ (0), crate/kmip/src/ (0), crate/access/src/ (0). PKCS#11 module/provider and HSM loaders contain additional unsafe as expected for C FFI. No unexpected unsafe blocks were found in core server logic. |
Recommended fix:
- A06-1: Upgrade
randto the version that resolves RUSTSEC-2026-0097. Runcargo update -p randand verify withcargo audit. - A06-2: Dedup by aligning version requirements across crates using
[patch]or resolving transitive dependency mismatches. Track withcargo deny check duplicates. - A06-5: Add
cd ui && pnpm audit --audit-level moderateto CI pipeline. - A06-6: Align
getrandomversion incrate/clients/wasm/Cargo.tomlto a version that still exposes thejsfeature gate, or remove the feature if no longer applicable. - A06-7 (geiger): Upgrade
cargo-geigerwhen a version supporting Rust 2024 virtual workspaces is available. Track cargo-geiger#378.
8. A07 – Identification and Authentication Failures
OWASP description: Incorrectly implemented authentication and session management allow attackers to compromise passwords, keys, or session tokens, or to assume other users' identities.
8.1 Scope
| Area | Key files |
|---|---|
| JWT middleware | crate/server/src/middlewares/jwt/jwt_middleware.rs, jwt_token_auth.rs, jwt_config.rs |
| JWKS manager | crate/server/src/middlewares/jwt/jwks.rs |
| API token auth | crate/server/src/middlewares/api_token/api_token_auth.rs, api_token_middleware.rs |
| TLS client cert auth | crate/server/src/middlewares/tls_auth.rs |
| AWS SigV4 auth | crate/server/src/routes/aws_xks/sigv4_middleware.rs |
| Auth fallback | crate/server/src/middlewares/ensure_auth.rs |
insecure feature gate | Everywhere gated by #[cfg(feature = "insecure")] |
8.2 Investigation Steps
# Step 1 — JWT algorithm restriction: must be RS256/ES256; reject HS256 and "none"
grep -rn "Algorithm\|alg\|Validation\|decode\|jsonwebtoken\|DecodingKey" \
crate/server/src/middlewares/jwt/ --include="*.rs"
# Step 2 — Token expiration enforcement (insecure feature relaxes this)
grep -rn "exp\|expir\|validate_exp\|insecure\|leeway" \
crate/server/src/middlewares/jwt/ --include="*.rs"
# Step 3 — JWKS fetch URL: must be HTTPS-only; no plain HTTP fallback
grep -n "http://\|reqwest\|fetch_jwks\|jwks_uri\|jwks_url\|url" \
crate/server/src/middlewares/jwt/jwks.rs
# Step 4 — API token comparison: must be constant-time to prevent timing attacks
grep -n "==\|compare\|ConstantTimeEq\|constant_time\|subtle\|ct_eq" \
crate/server/src/middlewares/api_token/api_token_auth.rs
# Step 5 — TLS cert auth: CN alone is insufficient; check if full DN or SAN is used
grep -n "CommonName\|CN\|SubjectAltName\|SAN\|subject\|peer_cert\|peer_certificate" \
crate/server/src/middlewares/tls_auth.rs
# Step 6 — Session fixation in UI auth: cookie must be HttpOnly, Secure, SameSite=Lax (OIDC requires Lax, not Strict)
grep -rn "actix.session\|Session\|cookie\|HttpOnly\|Secure\|SameSite" \
crate/server/src/routes/ui_auth.rs crate/server/src/middlewares/ --include="*.rs"
# Step 7 — Brute-force protection: lookout for rate limiting on auth endpoints
grep -rn "rate_limit\|lockout\|backoff\|attempt\|max_fail" \
crate/server/src/middlewares/ --include="*.rs"
# Step 8 — Semgrep auth patterns
semgrep --config p/owasp-top-ten \
crate/server/src/middlewares/ --lang rust 2>/dev/null || true
8.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server/src/middlewares/jwt/jwt_config.rscrate/server/src/middlewares/api_token/api_token_auth.rscrate/server/src/middlewares/tls_auth.rscrate/server/src/start_kms_server.rs- All
crate/server/src/middlewares/files
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A07-1 | jwt_config.rs:170 | High | Validation::new(header.alg) — JWT validation algorithm is taken directly from the alg field of the incoming token header without any allowlist. An attacker who obtains a valid kid could craft a token with alg: HS256 and use the RSA public key as the HMAC secret (algorithm confusion / "none" alg attack vector). The jsonwebtoken crate's Validation::new initialises with the given algorithm but does NOT restrict to it unless algorithms is explicitly set. |
| A07-2 | api_token_auth.rs:126 | Medium | API token comparison uses client_token == api_token.as_str() — standard == operator, which is not timing-safe. Timing differences can reveal whether the token length matches or prefix bytes are correct. A high-volume attacker on a low-latency network could exploit this to brute-force API tokens. |
| A07-3 | tls_auth.rs:147 | Low | TLS client certificate identity uses CN (Common Name) only, not SAN (Subject Alternative Name). Wildcard CNs (*) are explicitly rejected (correct). Modern TLS stacks prefer SAN; CN-only auth may fail on strict clients. |
| A07-4 | start_kms_server.rs:759 | Low | Session cookie SameSite is set to None (cross-site allowed). SameSite::Strict or Lax would protect against CSRF for browser-initiated requests. |
| A07-5 | jwt_config.rs:10,155 | Medium | The insecure feature disables all JWT validation including signature and expiration. Must not appear in production builds (see also A05-3). |
| A07-6 | All endpoints | High | No brute-force protection or account lockout on any authentication endpoint (JWT, API token, TLS). Combined with A04-2 (no rate limiting), this allows unlimited credential-guessing attempts. |
Recommended fix:
- A07-1: After calling
Validation::new(alg), immediately setvalidation.algorithms = vec AND add a check thatalgis in an explicit server-side allowlist (e.g.[RS256, RS384, RS512, ES256, ES384]). Reject tokens withalg: none,alg: HS256against asymmetric keys. - A07-2: Replace
client_token == api_token.as_str()with a constant-time comparison: usesubtle::ConstantTimeEqorring::constant_time::verify_slices_are_equal(). - A07-4: Change
SameSite::NonetoSameSite::Strictunless cross-site embedding of the KMS UI is required.
9. A08 – Software and Data Integrity Failures
OWASP description: Code and infrastructure that does not protect against integrity violations, including insecure deserialization, CI/CD pipeline attacks, and unsigned updates.
9.1 Scope
| Area | Key files |
|---|---|
| OpenSSL download + verify | crate/crypto/build.rs |
| Imported object validation | crate/server/src/core/operations/import.rs |
| KMIP deserializer | crate/kmip/src/ttlv/ |
| Cargo lock and git deps | Cargo.lock, Cargo.toml |
| CI pipeline scripts | .github/workflows/, .mise/scripts/ |
| Nix vendor hashes | nix/expected-hashes/ |
9.2 Investigation Steps
# Step 1 — OpenSSL build: SHA-256 check must be present and non-bypassable
grep -A5 -B5 "sha256\|checksum\|expected\|download\|verify" crate/crypto/build.rs
# Step 2 — Imported keys: are cryptographic properties validated on import?
# (RSA modulus size, EC curve OID, key material length)
grep -n "validate\|check\|verify\|length\|CryptographicLength\|Algorithm\|curve" \
crate/server/src/core/operations/import.rs | head -30
# Step 3 — KMIP deserialization: unknown fields rejected (not silently ignored)?
grep -rn "deny_unknown_fields\|flatten\|#\[serde\|untagged\|tag" \
crate/kmip/src/ --include="*.rs" | head -20
# Step 4 — Git-sourced or path-sourced Rust deps (integrity not guaranteed by crates.io)
grep -rn "git =\|path =\|branch =\|rev =" Cargo.toml crate/*/Cargo.toml
# Step 5 — CI scripts: unauthenticated downloads or pipe-to-shell patterns
grep -rn "curl.*sh\|wget.*sh\|pip install\|npm install" \
.mise/scripts/ .github/workflows/ 2>/dev/null \
| grep -v "^#\|#.*curl" | head -20
# Step 6 — Nix vendor hashes: all four variants must be present and non-trivial
ls -la nix/expected-hashes/
grep -v "^sha256-AAAA" nix/expected-hashes/*.sha256 2>/dev/null | head -10
9.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server/src/middlewares/ensure_auth.rscrate/kmip/src/crate/server/src/core/operations/import_export.rsdeny.toml
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A08-1 | crate/kmip/src/kmip_0/kmip_operations.rs (all structs) | Low | KMIP request/response structs do not use #[serde(deny_unknown_fields)]. Unknown fields in incoming KMIP JSON/XML are silently ignored rather than rejected. An attacker can add arbitrary fields to requests without triggering any error; this makes protocol-level fuzzing harder to detect. |
| A08-2 | start_kms_server.rs:737 | Medium | The UI session signing key is derived from the server URL. If the server is deployed with the default or a predictable URL (e.g. http://localhost:9998), the session key is predictable, allowing cookie forgery. The fallback salt "cosmian_kms_default_ui_session_key_v1" in build_session_key() makes this exploitable when no explicit key is configured. |
| A08-3 | crate/crypto/build.rs:234,274 | ✅ | OpenSSL tarball SHA-256 is verified before build. Prevents tampered source from being compiled in. |
| A08-4 | All Cargo.toml files | ✅ | No git = sourced deps. All Rust crates come from crates.io with version pinning. |
| A08-5 | crate/server/src/core/operations/import.rs | ✅ | CRL validation is performed on certificate import. Key parameter validation relies on OpenSSL's own enforcement (key size, curve OID, etc.), which is appropriate. |
Recommended fix:
- A08-1: Add
#[serde(deny_unknown_fields)]to all top-level KMIP request structs where spec compliance is required, or at minimum log a warning when unknown fields are encountered. - A08-2: Generate and persist a random 32-byte session key on first startup (saving it to the DB or a config file), and require it to be explicitly set in production. Remove the predictable URL-derived default.
10. A09 – Security Logging and Monitoring Failures
OWASP description: Insufficient logging and monitoring allows attackers to maintain persistence, pivot, and tamper with or exfiltrate data undetected.
10.1 Scope
| Area | Key files |
|---|---|
| KMIP request tracing | crate/server/src/routes/kmip.rs, routes/access.rs |
| Configuration secret logging | crate/server/src/config/command_line/ (all files) |
| Auth failure logging | crate/server/src/middlewares/ |
| Privileged operation audit events | crate/server/src/core/operations/export_get.rs, destroy.rs, revoke.rs |
| Error response content | crate/server/src/routes/ |
10.2 Investigation Steps
# Step 1 — Secrets in config log output: DB URLs, TLS passwords, API tokens
grep -rn "tracing::\|info!\|warn!\|error!\|debug!\|trace!" \
crate/server/src/config/ --include="*.rs" \
| grep -i "password\|secret\|token\|key\|credential\|url\|connection"
# Step 2 — Auth middleware: failure messages must NOT include the raw token value
grep -rn "info!\|warn!\|error!\|debug!" \
crate/server/src/middlewares/ --include="*.rs" \
| grep -i "token\|bearer\|api.key\|password\|secret"
# Step 3 — Privileged operations logged with user identity?
# (Export, Destroy, Revoke are high-value audit events)
grep -n "tracing\|info!\|warn!\|error!" \
crate/server/src/core/operations/export_get.rs \
crate/server/src/core/operations/destroy.rs \
crate/server/src/core/operations/revoke.rs 2>/dev/null | head -40
# Step 4 — Failed auth events: are 401/403 responses logged?
grep -rn "401\|403\|Unauthorized\|Forbidden\|warn!\|error!" \
crate/server/src/middlewares/ --include="*.rs" \
| grep -i "auth\|denied\|failed\|reject"
# Step 5 — Log injection: user-controlled strings inserted into tracing macros
# without sanitization allow log-forging via embedded newlines
grep -rn 'info!.*user\|debug!.*uid\|trace!.*tag\|warn!.*{.*}' \
crate/server/src/core/operations/ --include="*.rs" | head -20
# Step 6 — Coverage: all KMIP operations should have an instrumentation span
grep -rn "span!\|instrument\|#\[tracing::instrument\]" \
crate/server/src/core/operations/ --include="*.rs" | wc -l
echo "Total operation files:"
ls crate/server/src/core/operations/*.rs 2>/dev/null | wc -l
10.3 Findings
Status: ❌ Vulnerability found
Files inspected:
crate/server/src/config/command_line/db.rscrate/server/src/config/command_line/tls_config.rscrate/server/src/middlewares/jwt/jwks.rscrate/server/src/routes/ui_auth.rs
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A09-1 | config/command_line/db.rs:160,168 | High | The Display impl for MainDBConfig prints PostgreSQL and MySQL database_url completely unmasked. A URL like postgresql://kms_user:secretpassword@host/kms_db is logged verbatim at server startup. Any log aggregation system (Splunk, ELK, CloudWatch) will store the database password in plaintext. Redis correctly masks the password as [****]. |
| A09-2 | config/command_line/tls_config.rs:81 | Medium | TLS P12 password is masked via .replace('.', "*") — this only replaces dot characters with asterisks. A password like my_pass is logged unchanged; my.pass becomes my*pass. The masking is ineffective for most passwords. |
| A09-3 | middlewares/jwt/jwt_token_auth.rs:115 | Low | JWT authentication failures (invalid signature, expired token) are logged only at DEBUG level. These are security-relevant events that should be logged at WARN or ERROR to ensure they appear in production monitoring dashboards. |
| A09-4 | core/operations/ (decrypt.rs, locate.rs, sign.rs) | Low | User-controlled strings (uid, user) are embedded in tracing macro log calls without sanitization. An attacker can inject newline characters into a UID field to insert fake log records. |
| A09-5 | core/operations/export_get.rs, destroy.rs | ✅ | Export and Destroy operations are logged with both uid and user at INFO level. Privileged operation audit trail is present. |
| A09-6 | routes/ui_auth.rs | ✅ | ui_oidc_client_secret is masked as **** in Display output. OIDC secret does not leak into logs. |
Recommended fix:
- A09-1: Critical — Mask the password component in database URLs before logging. Parse the URL, replace the password with
[****], then log. Example: use theurlcrate to parse and rebuild. Fix theDisplayimpl forMainDBConfig::PostgreSQLandMainDBConfig::MySQL. - A09-2: Fix the P12 password masking to replace all characters:
.repeat("*", password.len())or simply log"[****]"as a constant. - A09-3: Change JWT auth failure tracing to
tracing::warn!and include the source IP address. - A09-4: Sanitize or percent-encode
uidanduserstrings before embedding them in log calls. Consider usingtracingstructured fields (uid = %uid) and ensuring the log formatter strips control characters.
11. A10 – Server-Side Request Forgery (SSRF)
OWASP description: SSRF flaws occur when a web application fetches a remote resource without validating the user-supplied URL, allowing an attacker to coerce outbound requests to unexpected destinations (cloud metadata endpoints, internal services, etc.).
11.1 Scope
| Area | Key files |
|---|---|
| JWKS URL fetch | crate/server/src/middlewares/jwt/jwks.rs |
| Google CSE callbacks | crate/server/src/routes/google_cse/ |
| AWS XKS outbound calls | crate/server/src/routes/aws_xks/ |
| Azure EKM connections | crate/server/src/routes/azure_ekm/ |
| HTTP client construction | crate/clients/client/src/ |
11.2 Investigation Steps
# Step 1 — Enumerate all outbound HTTP client instantiations
grep -rn "reqwest::Client\|reqwest::get\|Client::new\|ClientBuilder\|hyper::Client" \
crate/ --include="*.rs" | grep -v "test\|#\[cfg(test"
# Step 2 — JWKS URL: validated / allowlisted, or taken verbatim from config?
grep -n "jwks_uri\|jwks_url\|fetch\|get\|url\|https\|http" \
crate/server/src/middlewares/jwt/jwks.rs
# Step 3 — User-controlled URL fields in KMIP extensions or attributes
# (an attacker could embed a URL in a KMIP extension field)
grep -rn "url\|http\|endpoint\|callback\|webhook" \
crate/server/src/core/operations/ --include="*.rs" \
| grep -i "user\|request\|input\|attribute\|extension"
# Step 4 — Google CSE: user-controlled redirect or callback URLs?
grep -rn "redirect\|callback\|url\|uri" \
crate/server/src/routes/google_cse/ --include="*.rs"
# Step 5 — HTTP client redirect policy: SSRF via 301 redirect chain
grep -rn "redirect\|follow_redirect\|redirect_policy\|max_redirect" \
crate/ --include="*.rs"
# Step 6 — Outbound URL allowlists
grep -rn "allowlist\|whitelist\|allowed_url\|valid_host\|parse.*url\|Url::parse" \
crate/ --include="*.rs" | grep -v test | head -15
11.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server/src/middlewares/jwt/jwks.rscrate/server/src/routes/ui_auth.rscrate/clients/client/src/http_client/tls.rscrate/clients/ckms/src/config.rs- All
crate/server/src/routes/URL-consuming code
| ID | File:Line | Severity | Description |
|---|---|---|---|
| A10-1 | clients/ckms/src/config.rs:115 | Medium | accept_invalid_certs: true is hardcoded in the CLI's KmsClientConfig::default(). This disables outbound TLS certificate validation for CLI-to-KMS connections. While the CLI is not server-side code, cosmian_kms_client is also used in integration tests and potentially in embedded contexts where this default silently bypasses TLS chain validation. |
| A10-2 | middlewares/jwt/jwks.rs | Low | reqwest::Client::new() is used for JWKS endpoint fetching. By default reqwest follows HTTP redirects. The JWKS URL comes from admin configuration (jwt_issuer_uri), not from user input at request time. If an admin passes an internal URL as the JWKS issuer, the server could fetch internal endpoints (low-risk SSRF). No redirect allowlist or redirect::none() is applied. |
| A10-3 | routes/ui_auth.rs | Low | Same pattern: reqwest::Client::new() used for OAuth token exchange, following redirects without restriction. |
| A10-4 | All server routes | ✅ | No user-controlled URL parameters are used for server-side HTTP fetches at request time. JWKS/OIDC URLs come from static admin configuration only. The SSRF surface is limited to the initial server startup configuration. |
| A10-5 | routes/aws_xks/, routes/azure_ekm/, routes/google_cse/ | ✅ | Enterprise routes do not make outbound requests based on incoming request data. |
Recommended fix:
- A10-1: Change CLI default to
accept_invalid_certs: false. Provide an explicit--insecureflag orCOSMIAN_KMS_NO_VERIFY_CERT=trueenv var that must be explicitly set. - A10-2 / A10-3: Build the
reqwestclient with.redirect(reqwest::redirect::Policy::none())or restrict to a maximum of 1 redirect, and add a URL scheme allowlist (onlyhttps://).
12. EXT-0 – KMS Own Authorization System
OWASP ASVS V4 (Access Control) The KMS implements a custom, multi-layer authorization model that sits on top of KMIP. This section audits the full call chain from HTTP request to permission decision, covering privilege escalation paths, bypass mechanisms, and delegation controls.
12.1 Architecture
Every KMIP operation follows this authorization chain:
HTTP request
└─ TlsAuthMiddleware | JwtMiddleware | ApiTokenMiddleware
└─ EnsureAuthMiddleware (fallback: uses default_username)
└─ routes/kmip.rs → kms.get_user(&req)
│ ↑ force_default_username=true → ALL identities silently discarded
└─ dispatch(kms, ttlv, user) → operation handler
└─ retrieve_object_for_operation(uid, op, kms, user)
└─ user_has_permission(user, owm, op, kms)
├─ SHORTCUT user == owm.owner() → true (owner bypass)
├─ IMPLICIT ops.contains(Get) → ALL ops allowed
└─ DB query list_user_operations_on_object(uid, user)
├─ SQL: WHERE object_id = uid AND user_id = user
└─ UNION object_id = "*" AND user_id = user
Key design decisions with security implications:
| Mechanism | Location | Risk if abused |
|---|---|---|
| Owner bypass | user_has_permission() | Ownership must be immutable post-creation |
Get → all operations | user_has_permission() | Anyone with Get can Encrypt/Decrypt/Sign/Export |
Wildcard "*" stores Create perm | DB schema | User with Create on "*" can create unlimited objects |
force_default_username=true | kms.get_user() | Discards all user identities — complete authorization bypass |
privileged_users list | clap_config.rs | Members bypass Create/Import permission checks |
EnsureAuth fallback | ensure_auth.rs | Default single-user mode if no auth is configured |
12.2 Scope
| Area | Key files |
|---|---|
| Core permission gate | crate/server/src/core/retrieve_object_utils.rs |
| KMS identity resolution & delegation | crate/server/src/core/kms/permissions.rs |
| Permission data types | crate/access/src/access.rs |
| SQL permission queries | crate/server_database/src/stores/sql/ — permissions table |
| Redis permission store | crate/server_database/src/stores/redis/permissions.rs |
Privilege config (force_default_username, privileged_users) | crate/server/src/config/command_line/clap_config.rs |
| Create / Import authorization | crate/server/src/core/operations/create.rs, import.rs, register.rs |
| Delegation controls | crate/server/src/core/kms/permissions.rs — grant_access(), revoke_access() |
12.3 Investigation Steps
# Step 1 — Map every bypass mechanism and their activation conditions
grep -n "force_default_username\|privileged_users\|default_username" \
crate/server/src/config/command_line/clap_config.rs \
crate/server/src/core/kms/permissions.rs
# Step 2 — Owner bypass: trace user_has_permission() — verify the owner check
# cannot be spoofed (e.g. owners set at Create time, never updated)
grep -n "owner\|is_object_owned_by\|user.*==.*owner\|owner.*==" \
crate/server/src/core/retrieve_object_utils.rs \
crate/server/src/core/kms/permissions.rs
# Step 3 — "Get implies all operations": find the implicit grant and verify scope
grep -n "KmipOperation::Get\|contains.*Get\|implies\|all.*ops" \
crate/server/src/core/retrieve_object_utils.rs
# Step 4 — Wildcard "*" permission for Create: only privileged_users may grant it
grep -n '"\\*"\|wildcard\|Create\|privileged\|grant_access\|is_create' \
crate/server/src/core/kms/permissions.rs \
crate/server/src/core/operations/create.rs \
crate/server/src/core/operations/import.rs
# Step 5 — Non-owner grant delegation: is_object_owned_by() enforced in grant_access()?
grep -A10 "fn grant_access" crate/server/src/core/kms/permissions.rs | head -20
# Step 6 — Self-grant prevention: a caller must not grant themselves extra permissions
grep -n "user_id.*owner\|owner.*user_id\|grant.*self\|access.user_id" \
crate/server/src/core/kms/permissions.rs
# Step 7 — KMIP lifecycle state filter: Destroyed / Compromised block operations
grep -n "Destroyed\|Compromised\|PreActive\|Deactivated\|state.*check\|filter.*state" \
crate/server/src/core/retrieve_object_utils.rs
# Step 8 — Public endpoints: verify /health, /version, /server-info leak no data
grep -rn "health\|version\|server.info\|configure\|service\|wrap" \
crate/server/src/start_kms_server.rs | head -30
# Read actual health and version handler to confirm response content
cat crate/server/src/routes/health.rs 2>/dev/null | head -60
# Step 9 — Enterprise routes: verify AWS/Azure/Google/DKE routes cannot call
# standard KMIP operations using their own auth as a bypass
grep -rn "dispatch\|kms\.\|KMS\b" \
crate/server/src/routes/aws_xks/ \
crate/server/src/routes/azure_ekm/ \
crate/server/src/routes/google_cse/ \
crate/server/src/routes/ms_dke/ --include="*.rs" | head -30
# Step 10 — Redis PermTriple: concurrent grant + revoke atomicity
grep -n "PermTriple\|insert\|delete\|transaction\|atomic\|pipeline\|multi" \
crate/server_database/src/stores/redis/permissions.rs | head -20
# Step 11 — EnsureAuth: confirm it is a last-resort fallback, not a global bypass
cat crate/server/src/middlewares/ensure_auth.rs
12.4 Checklist
-
force_default_username=truecannot be set via any unauthenticated endpoint or environment variable injection -
privileged_userslist is logged at startup so admins can detect unauthorized changes -
Get→ all-operations implicit grant is intentional, documented, and cannot cross user boundaries -
A non-owner holding
Getpermission cannot callgrant_access()to escalate other users -
A user cannot grant
Createpermission to themselves or others unless they are inprivileged_users -
/health,/version,/server-inforeturn no object metadata, user identities, or internal state - Enterprise routes (XKS, EKM, CSE, DKE) authenticate independently and cannot reach standard KMIP key material without passing the full KMIP auth chain
-
KMIP lifecycle transitions from
CompromisedorDestroyedare irreversible and enforced at DB level -
Redis
PermTripleupdates are atomic (no TOCTOU between concurrent grant and revoke requests)
12.5 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server/src/core/retrieve_object_utils.rscrate/server/src/core/kms/permissions.rscrate/server/src/config/command_line/clap_config.rs(forforce_default_username)
| ID | File:Line | Severity | Description |
|---|---|---|---|
| EXT0-1 | retrieve_object_utils.rs:191 | Medium | permissions.contains(&KmipOperation::Get) is used as the universal "has some access" check. Any user with Get permission on an object is treated as having permission for ALL operations on it (Encrypt, Decrypt, Sign, Verify, GetAttributes, etc.). This is an intentional design decision but undocumented as a security policy. It makes permission grants broader than the receiver may expect. |
| EXT0-2 | core/kms/permissions.rs:23–100 | ✅ | grant_access() correctly enforces: (1) only the owner can grant, (2) Create can only be granted by privileged users to non-privileged users, (3) self-grant is prevented. Logic is sound. |
| EXT0-3 | config/command_line/clap_config.rs | ✅ | force_default_username defaults to false. When false, the authenticated user's identity is used. No anonymous or identity-collapse by default. |
| EXT0-4 | config/command_line/clap_config.rs | ✅ | privileged_users defaults to None (empty list). Privilege escalation via config is absent by default. |
| EXT0-5 | core/kms/permissions.rs — wildcard "*" | ✅ | The "*" wildcard Create permission is documented and guarded: only privileged_users can grant Create, and it cannot be granted to another privileged user. Correct. |
Recommended fix:
- EXT0-1: Document the
Get-implies-all-operations policy explicitly in the KMIP operation access control spec and in operator documentation. Consider adding a fine-grained per-operation permission check (separateEncrypt,Decrypt,Signpermissions) for objects where the Get permission holder should not have crypto access. This is a design-level decision.
13. EXT-1 – Cryptographic Key Lifecycle & Zeroization
OWASP ASVS V6 (Stored Cryptography) Sensitive cryptographic material (private keys, AES keys, shared secrets) must be zeroized from memory immediately after use. Residual key material in heap memory enables cold-boot and process-dump attacks.
13.1 Scope
| Area | Key files |
|---|---|
| Key wrapping cache | crate/server/src/core/wrapping/wrap.rs |
| Key unwrap paths | crate/server/src/core/wrapping/unwrap.rs |
| PKCS#11 key objects | crate/clients/pkcs11/provider/src/kms_object.rs |
| Crypto operations | crate/crypto/src/ |
| KMIP key material types | crate/kmip/src/ — KeyMaterial, EncryptedKeyBlock |
13.2 Investigation Steps
# Step 1 — Baseline: count all zeroize usages in the workspace
grep -rn "zeroize\|Zeroizing\|ZeroizeOnDrop\|SecretBox" \
crate/ --include="*.rs" | wc -l
# Step 2 — Find Vec<u8> likely holding key material WITHOUT Zeroizing<> wrapper
# Focus on operations that touch raw key bytes
grep -rn "Vec<u8>\|Box<\[u8\]>\|key_bytes\|key_material\|private_key\|secret_key" \
crate/server/src/core/operations/ --include="*.rs" \
| grep -v "Zeroizing\|zeroize\|#\[derive.*Zeroize\|//\|test_" | head -30
# Step 3 — Wrapping cache lifecycle: entries must be zeroized on eviction and drop
grep -n "cache\|remove\|evict\|drop\|DashMap\|HashMap\|clear\|Zeroizing" \
crate/server/src/core/wrapping/wrap.rs
# Step 4 — KMIP type zeroization: KeyMaterial and EncryptedKeyBlock implement Zeroize?
grep -rn "impl Zeroize\|impl Drop\|#\[derive.*Zeroize\|ZeroizeOnDrop" \
crate/kmip/src/ --include="*.rs"
# Step 5 — Key bytes in error messages (could surface in logs)
grep -rn 'format!.*\bkey\b\|error!.*\bkey\b\|warn!.*\bkey\b' \
crate/server/src/core/operations/ --include="*.rs" | head -15
# Step 6 — PKCS#11 provider: key material lifecycle before drop
grep -n "Zeroizing\|zeroize\|drop\|key_value\|private\|CK_BYTE" \
crate/clients/pkcs11/provider/src/kms_object.rs | head -30
# Step 7 — Unsafe block inventory (potential for bypassing Drop guarantees)
cargo geiger --workspace --output-format Ratio 2>/dev/null | head -30
13.3 Findings
Status: ⚠️ Review needed
Files inspected:
crate/server/src/core/operations/derive_key.rscrate/server/src/core/wrapping/wrap.rscrate/crypto/src/crypto/symmetric/symmetric_ciphers.rscrate/server/src/core/operations/mac.rs
| ID | File:Line | Severity | Description |
|---|---|---|---|
| EXT1-1 | operations/derive_key.rs:397,421 | Medium | derive_key() returns Vec<u8> for the wrapped/derived key material. The caller stores this in a ByteString which is not Zeroizing. If the derived key is sensitive (a root key, a DEK), it remains in heap memory as plaintext until the allocator reuses that memory. 96 other files in the codebase correctly use Zeroizing<Vec<u8>>. |
| EXT1-2 | core/wrapping/wrap.rs (unwrap cache) | Medium | The DashMap/HashMap used as the unwrapping cache stores unwrapped (plaintext) key objects in process RAM. No TTL, no max-size, no explicit zeroization on eviction is visible in wrap.rs. A memory dump of the server process exposes all recently unwrapped keys. |
| EXT1-3 | crypto/src/crypto/ (96 files) | ✅ | Broad use of Zeroizing<T> and ZeroizeOnDrop trait implementations throughout the crypto layer. Key material in bytes_set_de.rs:137 is wrapped in ZeroizeOnDrop. Good coverage. |
| EXT1-4 | operations/mac.rs:22 | ✅ | HMAC output (Vec<u8>) is not secret key material; does not require zeroization. The HMAC key is a borrowed slice — caller is responsible for its lifecycle. No issue in the MAC module itself. |
Recommended fix:
- EXT1-1: Change the
derive_keyreturn type toZeroizing<Vec<u8>>(or wrap the result before returning). PropagateZeroizingthroughByteStringusage if that type supports it. - EXT1-2: Add a TTL-based eviction (e.g. 60 seconds) or use
mlock/Zeroizingwrappers on cache values. On eviction, callzeroize()before dropping. Consider using a dedicated memory-safe cache likesecrecy::Secret<T>for cached key objects.
14. EXT-2 – Denial of Service / Resource Exhaustion
OWASP ASVS V12 / CWE-400 All user-controlled resource consumption must be bounded: request body size, TTLV nesting depth, database result set cardinality, and concurrent connection count.
14.1 Scope
| Area | Key files |
|---|---|
| Actix-web payload limit | crate/server/src/start_kms_server.rs |
| TTLV binary parser depth | crate/kmip/src/ttlv/wire/ttlv_bytes_deserializer.rs |
| TTLV XML parser depth | crate/kmip/src/ttlv/xml/parser.rs |
| Locate result pagination | crate/server_database/src/ |
| Batch request handling | crate/server/src/core/operations/dispatch.rs |
| Rate limiting | crate/server/src/middlewares/ |
14.2 Investigation Steps
# Step 1 — HTTP body size limit (Actix default is 256 KB)
grep -n "LimitPayloadSize\|max_payload_size\|PayloadConfig\|max_body\|content_length" \
crate/server/src/start_kms_server.rs crate/server/src/routes/kmip.rs
# Step 2 — TTLV binary recursion depth guard before recursive call
grep -n "depth\|recursion\|max_depth\|stack\|recursive\|fn parse\|fn decode\|fn from_ttlv" \
crate/kmip/src/ttlv/wire/ttlv_bytes_deserializer.rs
# Step 3 — TTLV XML: entity expansion (billion laughs), XXE, recursive entities
grep -n "expand_entities\|entity\|xml_parse\|XmlParser\|depth\|recursive\|ENTITY" \
crate/kmip/src/ttlv/xml/parser.rs
# Step 4 — Locate result set: is it bounded by max_items or a database LIMIT?
grep -n "Locate\|limit\|max_results\|LIMIT\|pagination\|fetch_all\|count\|MaxItems" \
crate/server/src/core/operations/locate.rs 2>/dev/null
grep -n "SELECT\|LIMIT\|offset\|page" \
crate/server_database/src/stores/sql/locate_query.rs | head -20
# Step 5 — KMIP batch requests: unbounded RequestBatchItem count?
grep -n "RequestBatchItem\|batch_items\|iter\|for.*batch\|MaximumResponseSize" \
crate/server/src/core/operations/dispatch.rs | head -20
# Step 6 — Rate limiting on KMIP endpoint
grep -rn "RateLimiter\|Governor\|leaky\|throttle\|rate\|max_conn" \
crate/server/src/middlewares/ --include="*.rs"
# Step 7 — Allocation without bound (Semgrep TTLV parser)
semgrep --config p/rust \
crate/kmip/src/ttlv/ --lang rust 2>/dev/null \
| grep -i "alloc\|capacity\|len\|size\|vec" || true
14.3 Findings
Status: ❌ Vulnerability found
Files inspected:
crate/server/src/start_kms_server.rscrate/kmip/src/ttlv/wire/ttlv_bytes_deserializer.rscrate/kmip/src/ttlv/xml/parser.rscrate/server/src/core/operations/locate.rs
| ID | File:Line | Severity | Description |
|---|---|---|---|
| EXT2-1 | start_kms_server.rs:767-768 | High | HTTP request body limit is 10_000_000_000 bytes (10 GB) — same as A04-1. Any client can send a 10 GB payload, exhausting server RAM and causing OOM / process crash. No pre-read size check. |
| EXT2-2 | ttlv_bytes_deserializer.rs:56 | High | read_ttlv() recurses without a depth counter. A crafted deeply-nested TTLV binary blob (e.g. 100 000 levels of nested Structure items) will overflow the stack and crash the process (stack overflow). This code path is reached before authentication. |
| EXT2-3 | ttlv/xml/parser.rs:196 | Medium | The TTLV XML parser has a depth counter variable but the parse loop contains no maximum depth enforcement — the counter is incremented but never checked against a limit. Deep XML nesting can cause the same stack overflow as the binary parser. |
| EXT2-4 | operations/locate.rs:96-101 | Medium | MaximumItems in a Locate request is optional and fully client-controlled. When absent, all matching objects are returned. A user who owns many objects (or to whom many are shared) can trigger a very large DB query and large response, consuming CPU, DB, and network resources. |
| EXT2-5 | All middlewares | High | No rate limiting (see A04-2). Without request rate limits, all DoS vectors listed above are amplifiable by a single unauthenticated client flooding the server. |
Recommended fix:
- EXT2-2 / EXT2-3: Add depth tracking to both parsers with
const MAX_TTLV_DEPTH: usize = 64and early-return errors when exceeded. This is the highest priority fix as it is reachable before authentication. - EXT2-1: Reduce payload limit to a realistic maximum (32–64 MB). See A04-1 fix.
- EXT2-4: Cap
MaximumItemsserver-side: if absent or > configuredmax_locate_items(default 1 000), clamp the SQL LIMIT tomax_locate_items. - EXT2-5: Implement rate limiting (see A04-2 fix).
15. Remediation Priority Matrix
All confirmed findings from sections 2–14, ordered by severity.
| ID | Section | File:Line | Severity | CVSS (est.) | Status | Assigned to | Due |
|---|---|---|---|---|---|---|---|
| A03-2 / EXT2-2 | A03 Injection / EXT-2 DoS | ttlv_bytes_deserializer.rs:56 | High | 7.5 | ✅ Fixed | 2026-04-14 | |
| A04-1 / EXT2-1 | A04 Insecure Design / EXT-2 DoS | start_kms_server.rs:767-768 | High | 7.5 | ✅ Fixed | 2026-04-14 | |
| A04-2 / EXT2-5 | A04 Insecure Design / EXT-2 DoS | All server middlewares | High | 7.5 | ✅ Fixed | 2026-04-14 | |
| A07-1 | A07 Auth Failures | jwt_config.rs:170 | High | 8.1 | ✅ Fixed | 2026-04-14 | |
| A07-6 | A07 Auth Failures | All auth endpoints | High | 7.3 | ✅ Fixed | 2026-04-14 | |
| A09-1 | A09 Logging | config/command_line/db.rs:160,168 | High | 7.2 | ✅ Fixed | 2026-04-14 | |
| A02-3 / EXT1-2 | A02 Crypto / EXT-1 Zeroization | core/wrapping/wrap.rs | Medium | 5.5 | Open | ||
| A03-3 / EXT2-3 | A03 Injection / EXT-2 DoS | ttlv/xml/parser.rs:196 | Medium | 5.9 | ✅ Fixed | 2026-04-14 | |
| A04-3 / EXT2-4 | A04 Insecure Design / EXT-2 DoS | operations/locate.rs:96-101 | Medium | 5.3 | ✅ Fixed | 2026-04-14 | |
| A05-1 / A01-1 | A05 Misconfiguration / A01 Access | start_kms_server.rs:776–962 | Medium | 5.4 | ✅ Fixed | 2026-04-14 | |
| A05-3 / A07-5 | A05 Misconfiguration / A07 Auth | jwt_config.rs:10,155 | Medium | 5.0 | ⚠️ Mitigated | 2026-04-14 | |
| A07-2 | A07 Auth Failures | api_token_auth.rs:126 | Medium | 5.9 | ✅ Fixed | 2026-04-14 | |
| A08-2 | A08 Integrity | start_kms_server.rs:737 | Medium | 4.3 | ✅ Fixed | 2026-04-14 | |
| A09-2 | A09 Logging | config/command_line/tls_config.rs:81 | Medium | 4.0 | ✅ Fixed | 2026-04-14 | |
| A10-1 | A10 SSRF | clients/ckms/src/config.rs:115 | Medium | 4.8 | ⚠️ Mitigated | 2026-04-14 | |
| EXT1-1 | EXT-1 Zeroization | operations/derive_key.rs:397,421 | Medium | 4.0 | ✅ Fixed | 2026-04-14 | |
| A02-2 | A02 Crypto | actions/mac.rs:17 | Low | 3.1 | Open | ||
| A06-1 | A06 Components | Cargo.toml (rand advisory) | Low | 3.7 | Open | ||
| A06-2 | A06 Components | Cargo.toml (dup crates) | Low | 2.0 | Open | ||
| A07-3 | A07 Auth Failures | tls_auth.rs:147 | Low | 2.0 | Open | ||
| A07-4 | A07 Auth Failures | start_kms_server.rs:759 | Low | 2.6 | ✅ Fixed | 2026-04-14 | |
| A08-1 | A08 Integrity | KMIP structs | Low | 2.0 | Open | ||
| A09-3 | A09 Logging | jwt_token_auth.rs:115 | Low | 2.0 | ✅ Fixed | 2026-04-14 | |
| A09-4 | A09 Logging | core/operations/ | Low | 2.0 | Open | ||
| A10-2 / A10-3 | A10 SSRF | jwks.rs, ui_auth.rs | Low | 2.3 | ✅ Fixed | 2026-04-14 | |
| EXT0-1 | EXT-0 Authorization | retrieve_object_utils.rs:191 | Low | 3.1 | Open | ||
| A02-1 | A02 Crypto | symmetric_ciphers.rs:429,784 | Info | N/A | Closed (FP) | ||
| A01-2 | A01 Access | routes/health.rs:47 | Info | N/A | Open |
Severity definitions (CVSS 3.1 base score ranges)
| Severity | CVSS score | Response SLA |
|---|---|---|
| Critical | 9.0 – 10.0 | Fix before next release; block merge |
| High | 7.0 – 8.9 | Fix within 1 sprint |
| Medium | 4.0 – 6.9 | Fix within 3 sprints |
| Low | 0.1 – 3.9 | Schedule in backlog |
| Info | N/A | Document / accept risk |
16. Report Sign-off
| Role | Name | Signature | Date |
|---|---|---|---|
| Lead auditor | GitHub Copilot (automated) | — | 2026-04-13 |
| Security reviewer | (human review pending) | ||
| Engineering lead | (human review pending) |
Automated audit completed: 2026-04-13 Next audit scheduled: Quarterly, or on every major dependency or KMIP spec change.
Review frequency: Quarterly, or on every major dependency update / KMIP spec change.
Summary statistics
| Severity | Count |
|---|---|
| High | 6 |
| Medium | 10 |
| Low | 10 |
| Info / FP | 3 |
| Total | 29 |
No Critical (CVSS ≥ 9.0) findings were identified. The most urgent items are the TTLV recursion depth limit (stack-overflow DoS reachable before auth), 10 GB payload limit (memory exhaustion), missing rate limiting, JWT algorithm confusion (authentication bypass potential), and database credential leak in logs.
Eviden KMS — Multi-Framework Security Audit
Document type: Security Audit Plan & Report
Frameworks: NIST CSF 2.0 / SSDF (SP 800-218) · CIS Controls v8 · ISO/IEC 27034 · OSSTMM
Repository: Eviden/kms
Workspace root: crate/ (Rust workspace) + ui/ (React/TypeScript)
Audit script: .mise/scripts/audit/multi_framework.sh — run bash .mise/scripts/audit/multi_framework.sh to reproduce all automated checks
See also .mise/scripts/audit/audit.sh for the unified entry-point that runs both OWASP and multi-framework checks.
Table of Contents
- Scope & Methodology
- NIST Cybersecurity Framework 2.0
- NIST SSDF SP 800-218
- CIS Controls v8
- ISO/IEC 27034 — Application Security
- OSSTMM
- Cross-Framework Remediation Matrix
- Automated Audit Checks
- Report Sign-off
1. Scope & Methodology
1.1 In-scope components
| Component | Technology | Risk level |
|---|---|---|
KMS server binary (cosmian_kms) | Rust (Actix-web, tokio) | Critical |
KMIP protocol engine (cosmian_kmip) | Rust | High |
| JWT/JWKS authentication middleware | Rust (jsonwebtoken, reqwest) | High |
| Database backends (SQLite, PostgreSQL, Redis-findex) | Rust (sqlx, redis) | High |
CLI client (ckms) | Rust (clap) | Medium |
| WASM client | Rust → WASM | Medium |
| Web UI | React 19 / TypeScript / Ant Design | Medium |
| OpenSSL 3.6.x (custom build) | C (bundled, vendored) | High |
1.2 Out of scope
- Physical HSM devices (Utimaco, Proteccio, Crypt2Pay) — covered by vendor certifications
- Third-party cloud services (AWS XKS, Azure EKM, GCP CMEK) — covered by cloud-provider SLAs
- Infrastructure layer (OS, network) — covered by deployment hardening guides
1.3 Methodology
This audit combines:
- Automated static analysis —
cargo audit,cargo deny,semgrep,gitleaks,grep-based pattern checks (orchestrated by.mise/scripts/audit/multi_framework.sh) - Manual code review — targeted review of authentication, cryptographic key handling, input parsing, and inter-service communication paths
- Integration testing — Rust
#[test]modules incrate/clients/clap/src/tests/security/andcrate/server/src/middlewares/jwt/jwks.rs - Control gap analysis — mapping findings to each framework's control catalogue
2. NIST Cybersecurity Framework 2.0
NIST CSF 2.0 organises controls into six functions: Govern, Identify, Protect, Detect, Respond, Recover.
2.1 GOVERN (GV)
| Control | Requirement | Status | Evidence |
|---|---|---|---|
| GV.OC-01 | Organisational context understood | ✅ | SECURITY.md, CONTRIBUTING.md define security scope and disclosure process |
| GV.OC-05 | Legal/regulatory requirements tracked | ✅ | FIPS 140-3 documentation maintained at certifications_and_compliance/fips.md |
| GV.RM-01 | Risk management strategy | ✅ | OWASP audit (owasp_security_audit.md) + this document |
| GV.SC-06 | Supplier/component vetting | ✅ | deny.toml (bans, licenses); deny.toml bans serde_json::unbounded_depth |
2.2 IDENTIFY (ID)
| Control | Requirement | Status | Evidence |
|---|---|---|---|
| ID.AM-01 | Asset inventory | ✅ | SBOM at sbom/ + CBOM at cbom/ |
| ID.AM-02 | Cryptographic inventory | ✅ | CBOM (cbom/cbom.cdx.json); NIST-approved algorithms documented |
| ID.RA-01 | Vulnerability identification | ✅ | cargo audit in CI; advisory DB updated weekly |
| ID.RA-06 | Risk response prioritised | ✅ | OWASP remediation priority matrix; see §7 |
2.3 PROTECT (PR)
| Control | Requirement | Status | Evidence |
|---|---|---|---|
| PR.AA-01 | Authentication | ✅ | OAuth2/OIDC via JWKS; JWT algorithm allowlist (RS256/PS256/ES256 only) |
| PR.AA-03 | Multi-factor authentication supported | ⚠️ | MFA delegated to OIDC provider; KMS does not enforce MFA directly |
| PR.AC-01 | Access control policy | ✅ | Per-object KMIP access control in crate/access/; privileged_users config |
| PR.AC-03 | Protected remote access | ✅ | TLS mutual auth supported; JWKS HTTPS guard (startup validation) |
| PR.DS-01 | Data-at-rest protection | ✅ | Database encrypted by wrapping keys; FIPS-grade AES-256 |
| PR.DS-02 | Data-in-transit protection | ✅ | TLS 1.2+ required; no legacy TLS 1.0/1.1 configuration |
| PR.DS-10 | Data destruction | ✅ | Zeroize applied to key material; Destroy KMIP operation |
| PR.PS-01 | Configuration management | ✅ | TOML config file; documented defaults; no hard-coded secrets |
2.4 DETECT (DE)
| Control | Requirement | Status | Evidence |
|---|---|---|---|
| DE.CM-01 | Networks monitored | ⚠️ | OTLP/Prometheus metrics exported; alerting rules are deployment-specific |
| DE.CM-03 | Personnel activity monitored | ✅ | All KMIP operations logged via tracing, with user identity |
| DE.CM-09 | Computing hardware and software monitored | ✅ | OTEL metrics (request counts, error rates, latency) |
2.5 RESPOND (RS) & RECOVER (RC)
| Control | Requirement | Status | Evidence |
|---|---|---|---|
| RS.CO-02 | Incidents reported | ✅ | SECURITY.md — responsible disclosure process |
| RC.RP-01 | Recovery plan | ⚠️ | Backup/restore procedures are deployment-specific; SQLite WAL docs available |
3. NIST SSDF SP 800-218
SSDF organises secure development practices into four groups: Prepare (PO), Protect (PS), Produce (PW), Respond (RV).
3.1 PO — Prepare the organisation
| Practice | KMS implementation | Status |
|---|---|---|
| PO.1 — Security requirements | OWASP audit plan; FIPS certification requirements | ✅ |
| PO.3 — Secure development environment | Nix reproducible builds; vendored OpenSSL | ✅ |
| PO.5 — Security training | CONTRIBUTING.md coding rules; AI agent instructions | ✅ |
3.2 PS — Protect the software
| Practice | KMS implementation | Status |
|---|---|---|
| PS.1 — Code integrity | Signed releases; GPG-signed packages; git tags | ✅ |
| PS.2 — Supply chain | deny.toml bans + license checks; vendored deps | ✅ |
| PS.3 — Archive and protect releases | GPG-signed deb/rpm/dmg; GitHub Releases | ✅ |
3.3 PW — Produce well-secured software
| Practice | Sub-practice | KMS implementation | Status |
|---|---|---|---|
| PW.1 | Design aligned with requirements | KMIP 2.1 compliant; FIPS 140-3 mode | ✅ |
| PW.4.4 | Validate inputs | TTLV depth limit (MAX_TTLV_DEPTH = 64); XML depth limit; JSON depth via serde_json built-in | ✅ |
| PW.5.1 | Ban vulnerable components | serde_json::unbounded_depth banned in deny.toml | ✅ |
| PW.6.1 | Use vetted libraries | ring, openssl, jsonwebtoken — all widely audited | ✅ |
| PW.7.1 | Avoid unsafe practices | unsafe count < 30; clippy::unwrap_used enforced in #[deny] | ✅ |
| PW.7.2 | Document unsafe usage | All unsafe blocks in FIPS-interface FFI wrappers; commented | ✅ |
| PW.8.1 | Test during development | Unit + integration + E2E tests; Playwright UI tests | ✅ |
| PW.8.2 | Code review | PR reviews required; AI agent assisted review | ✅ |
3.4 RV — Respond to vulnerabilities
| Practice | KMS implementation | Status |
|---|---|---|
| RV.1.1 — Monitor vulnerabilities | cargo audit in CI (weekly advisory DB sync) | ✅ |
| RV.1.2 — Deny HIGH/CRITICAL CVEs | cargo audit --deny warnings in CI; breaks build | ✅ |
| RV.2.2 — Assess and prioritise | OWASP remediation priority matrix | ✅ |
| RV.3.3 — Test remediation | Regression tests added for every finding (see test files) | ✅ |
4. CIS Controls v8
Relevant CIS Controls mapped to KMS implementation:
4.1 Inventory & Configuration
| CIS Control | Description | KMS status |
|---|---|---|
| CIS 1 — Asset inventory | SBOM + CBOM generated and committed | ✅ |
| CIS 2 — Software asset inventory | Cargo.lock / pnpm-lock.yaml pinned; reproducible builds | ✅ |
| CIS 4.1 — Secure configuration | Default bind 0.0.0.0; TLS required in production; serde_json::unbounded_depth banned | ✅ |
| CIS 4.2 — Default account hardening | No default credentials; OIDC-mandatory in production mode | ✅ |
4.2 Access Control
| CIS Control | Description | KMS status |
|---|---|---|
| CIS 5 — Account management | Per-user KMIP object ownership; privileged_users whitelist | ✅ |
| CIS 6 — Access control management | Grant/Revoke KMIP operations; access-control tests (security/access_control.rs) | ✅ |
| CIS 12.2 — Network traffic filtering | CORS restricted (no wildcard origin by default) | ✅ |
| CIS 13.9 — Encrypt data in transit | TLS 1.2+ required; legacy TLS absent from config | ✅ |
| CIS 13.10 — Prevent SSRF | JWKS HTTP client Policy::none() (no redirect following) | ✅ |
| CIS 16 — Application software security | JWKS HTTPS startup guard; JWT algorithm allowlist | ✅ |
4.3 Continuous monitoring
| CIS Control | Description | KMS status |
|---|---|---|
| CIS 8.2 — Collect audit log data | tracing structured logs; OTLP export; rolling log option | ✅ |
| CIS 8.5 — Collect detailed audit logs | User identity logged with every KMIP operation | ✅ |
| CIS 10.2 — Protection of data backups | SQLite WAL mode; documented restore procedure | ⚠️ |
5. ISO/IEC 27034 — Application Security
ISO 27034 defines Organisational Normative Frameworks (ONF) and Application Normative Frameworks (ANF) with four assurance levels (L1–L4).
5.1 Assurance level mapping
| Level | Requirement | KMS evidence |
|---|---|---|
| L1 — Basic | Documented security requirements | OWASP audit; this document; SECURITY.md |
| L2 — Standard | Input validation; CORS; error handling | TTLV depth limits; CORS tests; structured error types |
| L3 — Advanced | Access control; audit trails; key lifecycle | KMIP ACL; tracing logs; Destroy + zeroization |
| L4 — Highly secure | Formal verification of cryptographic properties | FIPS 140-3 mode (validated provider); algorithm allowlist |
5.2 Application Normative Framework controls
| ANF control | Description | KMS implementation | Status |
|---|---|---|---|
| ANF-1 — Input validation | All KMIP inputs validated before processing | TTLV parser depth limit; serde type validation | ✅ |
| ANF-2 — Authentication | OIDC token validated on every request | JwksManager verifies signature, expiry, algorithm | ✅ |
| ANF-3 — Authorisation | Object-level KMIP permissions checked | crate/access/ module; GetAttributes checks | ✅ |
| ANF-4 — Cryptographic controls | FIPS-approved algorithms only in default mode | FIPS provider; algorithm policy documented | ✅ |
| ANF-5 — Audit logging | All security-relevant events logged | tracing at INFO/WARN/ERROR; operation ID tracked | ✅ |
| ANF-6 — Error handling | Errors do not expose internal details | KmsError sanitised before HTTP response | ✅ |
| ANF-7 — Dependency management | Regular CVE scanning | cargo audit in CI; cargo deny on every PR | ✅ |
| ANF-8 — Secure communications | Transport encryption enforced | TLS 1.2+; JWKS HTTPS-only startup guard | ✅ |
6. OSSTMM
The Open Source Security Testing Methodology Manual (OSSTMM) defines five security channels: Human, Physical, Wireless, Telecommunications, Data Networks. The KMS is primarily a data-network application.
6.1 Data Networks channel
| OSSTMM section | Test area | Finding | Status |
|---|---|---|---|
| 5.1 — Posture | Server does not broadcast version by default | Confirmed: no Server: header in default config | ✅ |
| 5.3 — Enumeration | KMIP endpoint returns 422 (not 404) for invalid bodies | curl -X POST -d '{}' .../kmip/2_1 → 422 | ✅ |
| 5.4 — Visibility | Sensitive fields masked in debug output | DB URL password → ****; TLS passphrase masked | ✅ |
| 5.6 — Access | CORS headers do not reflect attacker origin | CORS tests cors_config.rs (C1–C3) confirm | ✅ |
| 5.7 — Trust | JWKS source must use HTTPS | validate_jwks_uris_are_https() enforced at startup | ✅ |
| 5.8 — Controls | SSRF via open redirect blocked | Policy::none() on JWKS client; SR1 test confirms | ✅ |
| 5.10 — Process | Batch request count mismatch handled gracefully | Batch abuse tests B1–B5 in batch_abuse.rs | ✅ |
| 5.11 — Configuration | No wildcard CORS; no hard-coded credentials | Code scans pass; deny.toml bans enforced | ✅ |
6.2 Residual risk summary
| Risk area | Residual risk | Mitigation |
|---|---|---|
| MFA enforcement | Low–Medium | Depends on OIDC provider configuration |
| SQLite backup integrity | Low | WAL mode; deployment guide recommends periodic backups |
| Rate limiting | Low | Not implemented at KMS level; recommend reverse-proxy (nginx, Caddy) |
| Side-channel attacks | Very low | FIPS provider; constant-time primitives via OpenSSL |
7. Cross-Framework Remediation Matrix
The table below maps each finding to its framework references, severity, and corresponding code change or test:
| ID | Finding | Severity | Frameworks | Remediation | Status |
|---|---|---|---|---|---|
| F-01 | JWKS URIs could use HTTP (man-in-the-middle risk) | High | CSF PR.AC-03, CIS 16, OSSTMM 5.7 | validate_jwks_uris_are_https() in start_kms_server.rs + J1–J4 tests | ✅ Closed |
| F-02 | serde_json::unbounded_depth feature not banned | Medium | SSDF PW.5.1, CIS 4.1 | Added [[bans.features]] in deny.toml | ✅ Closed |
| F-03 | JWKS HTTP client followed redirects (SSRF vector) | High | CSF ID.RA, OWASP A10, OSSTMM 5.8 | Policy::none() already in parse_jwks(); SR1–SR2 regression tests added | ✅ Closed |
| F-04 | JWT algorithm allowlist not covered by tests | Medium | CSF PR.AA-01, SSDF PW.8.1, ISO 27034 ANF-2 | A1–A6 tests in jwt_config.rs using production constant | ✅ Closed |
| F-05 | DB URL password visible in debug logs | Medium | CSF PR.DS-01, OSSTMM 5.4 | mask_db_url_password() + N1–N5 regression tests | ✅ Closed |
| F-06 | Batch count mismatch not explicit-tested | Low | SSDF PW.4.4, OWASP A04 | B1–B5 tests in batch_abuse.rs | ✅ Closed |
| F-07 | CORS policy not integration-tested | Low | ISO 27034 L2, CIS 12.2, OSSTMM 5.6 | C1–C3 tests in cors_config.rs | ✅ Closed |
| F-08 | Privilege-bypass boundary untested | Low | CSF PR.AC-01, CIS 5/6, ISO 27034 L4 | PB1–PB4 tests in privilege_bypass.rs | ✅ Closed |
8. Automated Audit Checks (audit.sh)
.mise/scripts/audit/multi_framework.sh contains 21 automated checks that can be run locally or in CI:
bash .mise/scripts/audit/multi_framework.sh # run all checks
bash .mise/scripts/audit/multi_framework.sh --verbose # show additional detail
bash .mise/scripts/audit/audit.sh # run unified OWASP + multi-framework
| Check | Framework(s) | Description |
|---|---|---|
| 1 | SSDF PW.1.1 | gitleaks — no hard-coded secrets |
| 2 | SSDF PW.7.2 | unsafe block count < 30 |
| 3 | SSDF RV.1.2 | cargo audit — no HIGH/CRITICAL CVEs |
| 4 | SSDF PW.5.1 | cargo deny bans |
| 5 | CIS 4.1 / OWASP A05 | serde_json unbounded_depth banned |
| 6 | CIS 8.2 | OTLP/rolling log configuration present |
| 7 | CIS 4.1 | Safe default bind address present |
| 8 | CIS 16 / OSSTMM Trust | JWKS HTTPS startup guard present |
| 9 | OSSTMM Visibility | DB URL password masking (**** placeholder) |
| 10 | OSSTMM Visibility | TLS passphrase masking |
| 11 | OWASP A10 / CSF ID.RA | JWKS HTTP client disables redirect following |
| 12 | ISO 27034 L2 / CIS 12.2 | CORS header not wildcard by default |
| 13 | SSDF PW.4.4 | TTLV binary/XML recursion depth limit |
| 14 | CSF PR.AA-01 | JWT algorithm allowlist enforced |
| 15 | CIS 13.9 | No legacy TLS 1.0/1.1 configuration |
| 16 | SSDF PW.4.4 | No bare panic!() in production paths |
| 17 | CIS 5.1 | Privileged user list not hard-coded in source |
| 18 | CSF PR.DS-01 | Sensitive key material uses Zeroize |
| 19 | OSSTMM / SSDF | unwrap() count in server/src/ < 5 |
| 20 | ISO 27034 L3 | Access-control module present |
| 21 | CSF DE.CM | semgrep static analysis (if installed) |
9. Report Sign-off
| Role | Name | Date | Signature |
|---|---|---|---|
| Security Reviewer | GitHub Copilot (automated) | 2026-04-16 | — |
| Lead Developer | Eviden Engineering | — | Pending |
| Security Officer | Eviden Security | — | Pending |
Overall status: ✅ All automated checks pass — 8 findings identified and closed.
Next review date: Before next major release or when any of the following occur:
- A new authentication mechanism is added
- A new dependency with cryptographic primitives is introduced
- A new external integration (cloud provider, HSM) is added
Runtime Network Security Audit
This report documents the live runtime security assessment methodology and expected results for the Eviden KMS server. The analysis targets the running server process over the network — complementing static source analysis and multi-framework compliance reports.
Run the analyser with:
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://HOST:PORT \
[--cert client.pem] [--key client.key] [--ca ca.pem]
Assessment Architecture
graph TD
A([Security Analyst]) -->|"runtime_security.sh"| B[Runtime Analyser]
B --> C[Reachability Probe]
B --> D[TLS Inspector]
B --> E[Certificate Chain]
B --> F[HTTP Headers]
B --> G[mTLS Verifier]
B --> H[KMIP Protocol Probes]
B --> I[Optional: nmap / sslyze / nuclei]
C --> J[(cbom/runtime/)]
D --> J
E --> J
F --> J
G --> J
H --> J
I --> J
J --> K[runtime_results.json]
J --> L[tls_analysis.txt]
J --> M[certificate.pem]
J --> N[http_headers.txt]
J --> O[kmip_probes.json]
Network & Attack Surface Map
graph LR
subgraph Internet ["Public Internet / Zero-trust network"]
C1([CLI client])
C2([Web UI])
C3([Enterprise app])
A([Attacker])
end
subgraph DMZ ["DMZ / Load Balancer"]
LB["TLS Termination or passthrough"]
end
subgraph KMS ["KMS Server Process"]
direction TB
P9998["Port 9998 — HTTPS/KMIP\n(main)"]
AUTH["Auth middleware\n(JWT / mTLS / API-key)"]
KMIP_ROUTE["KMIP 2.1 routes"]
UI_ROUTE["Web UI routes\n/ui/"]
HEALTH["Health — /version"]
end
subgraph DB ["Persistent Storage"]
SQL[(SQLite / PostgreSQL\nRedis-findex)]
end
C1 -- "HTTPS + mTLS / JWT" --> LB
C2 -- "HTTPS + auth cookie" --> LB
C3 -- "HTTPS + API key" --> LB
A -. "scan / probe" .-> LB
LB --> P9998
P9998 --> AUTH
AUTH --> KMIP_ROUTE
AUTH --> UI_ROUTE
AUTH --> HEALTH
KMIP_ROUTE --> SQL
| Surface | Exposure | Mitigation |
|---|---|---|
| Port 9998 / KMIP endpoint | External | mTLS or JWT, TLS 1.2+ only |
| Web UI | External | Cookie auth, CSP header |
/version health endpoint | External | Read-only, no secrets |
| Server certificate | Public | Auto-renew, SHA-256+, RSA-2048+ |
| Database | Internal only | Not exposed to network |
TLS Security Scorecard
graph LR
S3("SSLv3") -- REJECT --> N1["POODLE — CVE-2014-3566"]
T10("TLS 1.0") -- REJECT --> N2["BEAST / PCI-DSS deprecated"]
T11("TLS 1.1") -- REJECT --> N3["Deprecated — RFC 8996"]
T12("TLS 1.2") -- ACCEPT --> Y1["FIPS 140-3 minimum"]
T13("TLS 1.3") -- ACCEPT --> Y2["Preferred — PFS enforced"]
style S3 fill:#ef4444,color:#fff,stroke:#dc2626
style T10 fill:#ef4444,color:#fff,stroke:#dc2626
style T11 fill:#f97316,color:#fff,stroke:#ea580c
style T12 fill:#22c55e,color:#fff,stroke:#16a34a
style T13 fill:#16a34a,color:#fff,stroke:#15803d
style N1 fill:#fee2e2,color:#991b1b,stroke:#fca5a5
style N2 fill:#fee2e2,color:#991b1b,stroke:#fca5a5
style N3 fill:#ffedd5,color:#9a3412,stroke:#fdba74
style Y1 fill:#dcfce7,color:#166534,stroke:#86efac
style Y2 fill:#dcfce7,color:#166534,stroke:#86efac
| Protocol | Expected | Reason |
|---|---|---|
| SSLv3 | ❌ Rejected | POODLE attack (CVE-2014-3566) |
| TLS 1.0 | ❌ Rejected | BEAST, POODLE, deprecated PCI-DSS 3.2 |
| TLS 1.1 | ❌ Rejected | Deprecated per RFC 8996 |
| TLS 1.2 | ✅ Accepted | Minimum for FIPS 140-3 |
| TLS 1.3 | ✅ Accepted | Preferred — mandatory for new deployments |
pie title Accepted Cipher Suites by Category
"ECDHE-AESGCM (strong)" : 4
"DHE-AESGCM (PFS)" : 2
"AES256-SHA256 (compat)" : 1
"Weak / rejected" : 0
| Category | Example Cipher | Status | FIPS 140-3 | Forward Secrecy |
|---|---|---|---|---|
| ECDHE-RSA-AES256-GCM-SHA384 | TLS 1.2 ECDHE | ✅ Allowed | ✅ | ✅ |
| ECDHE-RSA-AES128-GCM-SHA256 | TLS 1.2 ECDHE | ✅ Allowed | ✅ | ✅ |
| TLS_AES_256_GCM_SHA384 | TLS 1.3 | ✅ Allowed | ✅ | ✅ |
| TLS_CHACHA20_POLY1305_SHA256 | TLS 1.3 | ✅ Allowed | ⚠️ non-FIPS only | ✅ |
| NULL / aNULL | Export | ❌ Rejected | ❌ | ❌ |
| RC4 / DES / 3DES | Legacy | ❌ Rejected | ❌ | ❌ |
| MD5-based | Legacy | ❌ Rejected | ❌ | ❌ |
| EXPORT-grade | Legacy | ❌ Rejected | ❌ | ❌ |
sequenceDiagram
participant C as Client
participant S as KMS Server (TLS 1.3)
C->>S: ClientHello (supported protocols, ciphers)
S-->>C: ServerHello (TLS 1.3, TLS_AES_256_GCM_SHA384)
S-->>C: Certificate (RSA-2048 / ECDSA-256, SHA-256 signed)
S-->>C: CertificateVerify
S-->>C: Finished
C->>S: [Optional] Certificate (mTLS)
C->>S: Finished
Note over C,S: Symmetric keys derived from ephemeral ECDHE<br/>(Perfect Forward Secrecy)
C->>S: POST /kmip/2_1 (encrypted)
S-->>C: KMIP ResponseMessage (encrypted)
Certificate Chain Analysis
graph TB
ROOT["Root CA\nself-signed or public CA\nKey: RSA-4096 or EC-384\nSig: SHA-256"]
INTER["Intermediate CA optional\nKey: RSA-2048 or EC-256\nSig: SHA-256 Valid: 3 years"]
LEAF["KMS Server Certificate\nSAN: kms.example.com\nKey: RSA-2048 or EC-256\nSig: SHA-256 Valid: 1 year max"]
ROOT --> INTER
INTER --> LEAF
- Key algorithm: RSA ≥ 2048 bits or EC ≥ P-256
- Signature: SHA-256 minimum (SHA-1 rejected by modern browsers and RFC 9155)
- SAN: must match server hostname — bare CN no longer sufficient (RFC 2818)
- Expiry: warning at 30 days; auto-renewal recommended (ACME/Let's Encrypt)
- OCSP stapling: recommended for client-side revocation checking
HTTP Security Headers
graph LR
subgraph Required ["Required Headers"]
HSTS["Strict-Transport-Security\nmax-age=31536000 includeSubDomains"]
XCTO["X-Content-Type-Options: nosniff"]
end
subgraph Recommended ["Recommended Headers"]
XFO["X-Frame-Options: DENY"]
CSP["Content-Security-Policy\ndefault-src self"]
CC["Cache-Control: no-store"]
end
subgraph Avoid ["Must not disclose"]
SRV["Server: omit or generic"]
CORS_W["CORS wildcard forbidden on KMIP"]
end
| Header | Expected Value | Importance | OWASP |
|---|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Required | A05 |
X-Content-Type-Options | nosniff | Required | A05 |
X-Frame-Options | DENY | Recommended | A05 |
Content-Security-Policy | default-src 'self'; script-src 'self' | Recommended | A03 |
Cache-Control | no-store on API routes | Recommended | A02 |
Server | Empty or generic | Avoid disclosure | A05 |
CORS on /kmip/* | None or restricted origin | Required | A01 |
mTLS Authentication Model
sequenceDiagram
participant CLI as ckms CLI
participant KMS as KMS Server
participant DB as Database
CLI->>KMS: TLS ClientHello
KMS-->>CLI: ServerHello + Certificate
KMS-->>CLI: CertificateRequest (if mTLS mode)
CLI->>KMS: Certificate (client cert, signed by trusted CA)
CLI->>KMS: CertificateVerify
Note over CLI,KMS: TLS session established
CLI->>KMS: POST /kmip/2_1 (encrypted TTLV)
KMS->>KMS: Extract CN from client cert → username
KMS->>DB: Look up access control for user
KMS-->>CLI: KMIP Response
| Mode | How it works | When to use |
|---|---|---|
| mTLS | Client presents X.509 certificate signed by trusted CA | Internal services, CLI tooling |
| JWT (OAuth2) | Bearer token from Auth0 / Keycloak / OIDC provider | Web UI, end-user access |
| API key | Shared secret in header | Machine-to-machine, simple integrations |
| No auth | Disabled — dev/test only (--auth-type none) | Local development only |
# Test mTLS with ckms-generated certs
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://localhost:9998 \
--cert test_data/certs/client.crt \
--key test_data/certs/client.key \
--ca test_data/certs/server_ca.crt
KMIP Protocol Security Probes
flowchart TD
P1["Empty payload probe\nPOST /kmip/2_1 {}"] -->|"Expected: 400/422"| OK1([PASS])
P2["Oversized BatchCount\nBatchCount: 99999"] -->|"Expected: 400/422/413"| OK2([PASS])
P3["SQL injection in UID\n'OR 1=1; DROP TABLE"] -->|"Expected: 400/422/401"| OK3([PASS])
P4["70 MiB payload\nAbove 64 MiB limit"] -->|"Expected: 400/413"| OK4([PASS])
P5["Rate limit probe\n10 rapid requests"] -->|"429 expected for excess"| OK5([PASS / INFO])
style OK1 fill:#22c55e,color:#fff
style OK2 fill:#22c55e,color:#fff
style OK3 fill:#22c55e,color:#fff
style OK4 fill:#22c55e,color:#fff
style OK5 fill:#84cc16,color:#fff
| Probe | Payload | Expected HTTP | Risk if wrong |
|---|---|---|---|
| Empty KMIP request | {} | 400 or 422 | Server crash / 500 |
| OversizedBatchCount | BatchCount: 99999 | 400, 422, or 413 | DoS / OOM |
| SQL injection in UID | ' OR '1'='1'; DROP ... | 400, 422, 401 | SQL injection |
| 70 MiB payload | Random bytes | 400 or 413 | DoS / memory exhaustion |
| Rapid 10 requests | Empty KMIP | 422 (or 429 if rate-limit active) | Brute-force |
Threat Model (STRIDE)
mindmap
root((KMS Server\nAttack Surface))
Spoofing
Fake client certificate
JWT token forgery
MITM on HTTP
Tampering
Replay KMIP request
Key ID enumeration
Packet injection
Repudiation
Missing audit log
Log injection
Information Disclosure
TLS version downgrade
Server header leaks version
Error message leaks DB schema
Denial of Service
OversizedBatchCount
Large payload flood
TLS session exhaustion
Elevation of Privilege
CORS wildcard on KMIP
JWT scope confusion
Insecure object ownership
| Threat | STRIDE | Mitigation | Status |
|---|---|---|---|
| MITM — weak TLS version | Tampering | TLS 1.2+ enforced; SSLv3/TLS1.0/1.1 rejected | ✅ Mitigated |
| Weak cipher negotiation | Tampering | NULL/RC4/DES/EXPORT rejected by server | ✅ Mitigated |
| Certificate spoofing | Spoofing | mTLS or JWT required; CA pinning optional | ✅ Mitigated |
| SQL injection via UID | Tampering | Parameterised queries in all DB backends | ✅ Mitigated |
| OOM via large batch | DoS | BatchCount validated; payload size limit 64 MiB | ✅ Mitigated |
| Rate-based brute-force | DoS | Rate limiting middleware (configurable) | ⚠️ Configurable |
| Server version disclosure | Info Disclosure | Server header suppressed | ✅ Mitigated |
| CORS wildcard on KMIP | Elevation of Privilege | No CORS header on /kmip/* | ✅ Mitigated |
| Expired certificate | Spoofing | 30-day expiry warning in checker | ✅ Monitored |
| Insecure direct object refs | Elevation of Privilege | Object ownership enforced in DB | ✅ Mitigated |
Running the Analyser
Prerequisites
# Required (always present on Linux)
openssl version # ≥ 3.0
curl --version # ≥ 7.68
# Optional — enable richer analysis when installed
apt-get install nmap # port scan + TLS NSE scripts
pip3 install sslyze # deep TLS / cert-transparency analysis
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest # template scanner
Basic run (plain HTTPS)
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://localhost:9998 \
--insecure # skip cert verification on self-signed cert
Full run with mTLS
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://kms.prod.example.com:9998 \
--cert certs/client.crt \
--key certs/client.key \
--ca certs/ca.crt \
--report documentation/docs/certifications_and_compliance/audit/runtime_security_audit_latest.md
Output files
cbom/runtime/
├── runtime_results.json ← machine-readable summary (all checks + status)
├── tls_analysis.txt ← raw openssl s_client output
├── cert_details.txt ← openssl x509 -text of server certificate
├── certificate.pem ← server certificate in PEM format
├── http_headers.txt ← HTTP response headers
├── mtls_analysis.txt ← mTLS negotiation log
├── kmip_probes.json ← KMIP protocol probe results
├── nmap.txt ← nmap scan (if installed)
├── sslyze.json ← sslyze report (if installed)
└── nuclei.txt ← nuclei scan (if installed)
Exit codes
| Code | Meaning |
|---|---|
0 | All checks passed |
1 | One or more FAIL findings (critical) |
2 | Tool error (missing required utility or bad arguments) |
Integration with CI
Add to .github/workflows/main_base.yml as a post-deploy smoke test:
- name: Runtime Security Scan
run: |
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://localhost:9998 \
--insecure \
--report cbom/runtime_security_report.md
env:
KMS_URL: https://localhost:9998
| Report | Layer | Tool |
|---|---|---|
| OWASP Source Audit | Static — source code | scan_source.py + risk_score.py |
| Multi-framework Audit | Static — policy compliance | multi_framework.sh |
| Runtime Security Audit (this file) | Dynamic — running server | runtime_security.sh |
KMIP Support
The Eviden KMS server implements both KMIP 1.x and 2.x interfaces. KMIP (Key Management Interoperability Protocol) is an OASIS standard designed to standardize communication between key management systems and encryption clients.
Connection Options
-
Binary Protocol: Available on port 5696
- TLS secured
- Client certificate required for authentication
-
JSON Protocol: Available on port 9998 via REST POST
- Optional TLS security
- Multiple authentication mechanisms supported
- Endpoints:
/kmip: Handles KMIP 1.x and 2.xRequestMessage/kmip/2_1: Specifically for KMIP 2.1RequestMessageor operations likeCreate,Encrypt,Decrypt, etc.
Implementation Details
Internally, all KMIP messages are translated to KMIP 2.1 specifications and converted back to KMIP 1.x when necessary. The Eviden KMS server implements a targeted subset of the KMIP 2.1 protocol.
Purpose of KMIP
The OASIS KMIP standard aims to:
- Define a comprehensive protocol for communication between encryption systems and enterprise applications
- Support diverse applications including email, databases, and storage devices
- Eliminate redundant and incompatible key management processes
- Enhance data security while reducing costs associated with multiple products
Scope of Implementation
KMIP is an extensive specification. While the Eviden KMS server does not implement the entire standard, it supports the features necessary for advanced cryptographic use cases. The implementation continues to evolve to meet customer requirements, though like most KMS servers, it doesn't support all possible cryptographic objects and operations.
The following pages document the supported features of the KMIP 2.1 specification and Cosmian-specific extensions.
KMIP support by Cosmian KMS
This page summarizes the KMIP coverage in Cosmian KMS. The support status is
derived from the actual implementation in crate/server/src/core/operations.
Cosmian KMS Server supports KMIP versions: 2.1, 2.0, 1.4, 1.3, 1.2, 1.1, 1.0
Legend:
- ✅ Fully supported
- ❌ Not implemented
- 🚫 Deprecated
- N/A Not applicable (operation/attribute not defined in that KMIP version)
KMIP Baseline Profile Compliance
Baseline Server: ✅ Compliant (all 9 required + 18/18 optional)
The Baseline Server profile (defined in KMIP Profiles v2.1 Section 4.1) requires:
- Required operations: Discover Versions, Query, Create, Register, Get, Destroy, Locate, Activate, Revoke
- Optional operations: Many additional operations for extended functionality
KMIP Coverage
Messages
| Message | Support |
|---|---|
| Request Message | ✅ |
| Response Message | ✅ |
Operations by KMIP Version
The following table shows operation support across all KMIP versions.
| Operation | 1.0 | 1.1 | 1.2 | 1.3 | 1.4 | 2.0 | 2.1 |
|---|---|---|---|---|---|---|---|
| Activate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Add Attribute | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Archive | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Cancel | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Certify | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Check | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Create | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Create Key Pair | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Create Split Key | N/A | N/A | N/A | ❌ | ❌ | ❌ | ❌ |
| Decrypt | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Delete Attribute | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| DeriveKey | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Destroy | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Discover Versions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Encrypt | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Export | N/A | N/A | N/A | N/A | ✅ | ✅ | ✅ |
| Get | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Get Attribute List | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Get Attributes | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Get Usage Allocation | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Hash | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Import | N/A | N/A | N/A | N/A | ✅ | ✅ | ✅ |
| Join Split Key | N/A | N/A | N/A | ❌ | ❌ | ❌ | ❌ |
| Locate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| MAC | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| MAC Verify | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Notify | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Obtain Lease | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Poll | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Put | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Query | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| RNG Retrieve | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| RNG Seed | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Re-certify | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Re-key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Re-key Key Pair | N/A | N/A | ✅ | ✅ | ✅ | ✅ | ✅ |
| Recover | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Register | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Revoke | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Set Attribute (Modify) | N/A | N/A | ✅ | ✅ | ✅ | ✅ | ✅ |
| Sign | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Signature Verify | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Validate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Methodology
- Operations marked ✅ are backed by a Rust implementation file under
crate/server/src/core/operations. - Operations marked ❌ are defined in the KMIP specification but not implemented in Cosmian KMS.
- Operations marked N/A do not exist in that particular KMIP version.
- This documentation is auto-generated by analyzing source code and KMIP specifications.
If you spot a mismatch or want to extend coverage, please open an issue or PR.
Managed Objects
The following table shows managed object support across all KMIP versions.
| Managed Object | 1.0 | 1.1 | 1.2 | 1.3 | 1.4 | 2.0 | 2.1 |
|---|---|---|---|---|---|---|---|
| Certificate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Symmetric Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Public Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Private Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Split Key | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Template | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 |
| Secret Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Opaque Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| PGP Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
Notes:
- Opaque Object import support is present (see
import.rs). - PGP Key types appear in digest and attribute handling but full object import/register is not implemented, hence ❌.
- Template objects are deprecated in newer KMIP versions.
Base Objects
The following table shows base object support across all KMIP versions.
| Base Object | 1.0 | 1.1 | 1.2 | 1.3 | 1.4 | 2.0 | 2.1 |
|---|---|---|---|---|---|---|---|
| Attribute | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Credential | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Key Block | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Key Value | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Key Wrapping Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Key Wrapping Specification | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Transparent Key Structures | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Template-Attribute Structures | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Server Information | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Extension Information | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Data Length | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Signature Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| MAC Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Nonce | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Correlation Value | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Init Indicator | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Final Indicator | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| RNG Parameters | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Profile Information | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Validation Information | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Capability Information | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Authenticated Encryption Additional Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Authenticated Encryption Tag | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Notes:
- AEAD Additional Data and Tag are supported in encrypt/decrypt APIs.
- Nonce and RNG Parameter are used by symmetric encryption paths.
- Base objects are fundamental structures present across all KMIP versions.
Transparent Key Structures
The following table shows transparent key structure support across all KMIP versions.
| Structure | 1.0 | 1.1 | 1.2 | 1.3 | 1.4 | 2.0 | 2.1 |
|---|---|---|---|---|---|---|---|
| Symmetric Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| DSA Private Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| DSA Public Key | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| RSA Private Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| RSA Public Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| DH Private Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
| DH Public Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
| EC Private Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| EC Public Key | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| ECDSA Private Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
| ECDSA Public Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
| ECDH Private Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
| ECDH Public Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
| ECMQV Private Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
| ECMQV Public Key | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
Note: EC/ECDSA support is present; DH/DSA/ECMQV are not implemented.
Attributes
| Attribute | Current |
|---|---|
| Activation Date | ✅ |
| Alternative Name | ✅ |
| Always Sensitive | ✅ |
| Application Specific Information | ✅ |
| Archive Date | ✅ |
| Attribute Index | ✅ |
| Certificate Attributes | ✅ |
| Certificate Length | ✅ |
| Certificate Type | ✅ |
| Comment | ✅ |
| Compromise Date | ✅ |
| Compromise Occurrence Date | ✅ |
| Contact Information | ✅ |
| Critical | ✅ |
| Cryptographic Algorithm | ✅ |
| Cryptographic Domain Parameters | ✅ |
| Cryptographic Length | ✅ |
| Cryptographic Parameters | ✅ |
| Cryptographic Usage Mask | ✅ |
| Deactivation Date | ✅ |
| Description | ✅ |
| Destroy Date | ✅ |
| Digest | ✅ |
| Digital Signature Algorithm | ✅ |
| Extractable | ✅ |
| Fresh | ✅ |
| Initial Date | ✅ |
| Key Format Type | ✅ |
| Key Value Location | ✅ |
| Key Value Present | ✅ |
| Last Change Date | ✅ |
| Lease Time | ✅ |
| Link | ✅ |
| Name | ✅ |
| Never Extractable | ✅ |
| Nist Key Type | ✅ |
| Object Group | ✅ |
| Object Group Member | ✅ |
| Object Type | ✅ |
| Opaque Data Type | ✅ |
| Original Creation Date | ✅ |
| PKCS#12 Friendly Name | ✅ |
| Process Start Date | ✅ |
| Protect Stop Date | ✅ |
| Protection Level | ✅ |
| Protection Period | ✅ |
| Protection Storage Masks | ✅ |
| Quantum Safe | ✅ |
| Random Number Generator | ✅ |
| Revocation Reason | ✅ |
| Rotate Automatic | ✅ |
| Rotate Date | ✅ |
| Rotate Generation | ✅ |
| Rotate Interval | ✅ |
| Rotate Latest | ✅ |
| Rotate Name | ✅ |
| Rotate Offset | ✅ |
| Sensitive | ✅ |
| Short Unique Identifier | ✅ |
| State | ✅ |
| Unique Identifier | ✅ |
| Usage Limits | ✅ |
| Vendor Attribute | ✅ |
| X.509 Certificate Identifier | ✅ |
| X.509 Certificate Issuer | ✅ |
| X.509 Certificate Subject | ✅ |
Notes:
- GetAttributes returns a union of metadata attributes and those embedded in KeyBlock structures.
- "Vendor Attributes" are available via the Cosmian vendor namespace and are accessible via GetAttributes.
- A ✅ indicates the attribute is used or updated by at least one KMIP operation implementation in
crate/server/src/core/operations, including attribute handlers (Add/Delete/Set/Get Attribute). - Most attributes are present across all KMIP versions with some additions in newer versions.
The KMIP 2.1 specification pre-defines a set of 9 cryptographic objects. Eviden supports the use of 4 of these objects
| Objects | Cryptographic primitives |
|---|---|
| Certificate | X509 |
| Certificate Request | - |
| Opaque Object | - |
| PGP Key | - |
| Private Key | Covercrypt, X25519, Ed25519, X448, Ed448, NIST EC, RSA |
| Public Key | Covercrypt, X25519, Ed25519, X448, Ed448, NIST EC, RSA |
| Secret Data | - |
| Split Key | - |
| Symmetric key | SSE, AES, FPE, Salsa20, XChacha20, Findex |
Notes:
- Certificates can be
- imported using the
Importoperation as X509 (PEM, DER) or PKCS12 (PFX) files. - created using the
Certifyoperation from a PKCS#10 Certificate Request or from an existing public key.
- imported using the
- For the supported algorithms for key wrapping, encryption and decryption, see the supported algorithms page.
- For the supported formats, see the supported formats page.
KMIP Objects may be manipulated in various standardized formats.
Import - Export
The KMIP 2.1 specification states that keys have a default Key Format Type that SHALL be produced by KMIP servers. When requesting the export of an Object without specifying the Key Format Type, a default Key Format Type by object (and algorithm) should be used as listed in the following table:
| Type | Default Key Format Type | Available Key Format Types Import/Export |
|---|---|---|
| Certificate | X.509 | X.509 |
| Certificate Request | PKCS#10 | PKCS#10 |
| Opaque Object | Opaque | |
| PGP Key | Raw | |
| Secret Data | Raw | |
| Symmetric Key | Raw | Raw |
| Split Key | Raw | |
| RSA Private Key | PKCS#1 | PKCS#1, PKCS#8, Transparent RSA Private Key |
| RSA Public Key | PKCS#1 | PKCS#1, PKCS#8 (SPKI), Transparent RSA Public Key |
| EC Private Key | Transparent EC Private Key | Transparent EC Private Key, PKCS#8, EC Private Key (SEC1) |
| EC Public Key | Transparent EC Public Key | Transparent EC Public Key, PKCS#8 (SPKI) |
| DSA Private Key | Transparent DSA Private Key | |
| DSA Public Key | Transparent DSA Public Key |
- All ASN.1 based formats are available as
PEMorDERencoded SPKIis denotedPKCS8for public keys in KMIPSEC1(calledECPrivateKeyin KMIP) is only available for NIST curves (i.e. not for curve 25519 and curve 448) private keys.- The
Dfield of theTransparent EC Private Keyis:- the (absolute) value of the Big Integer of the scalar for NIST curves
- the Big Integer value of the private key raw bytes (as big endian) for Curve 25519 and Curve 448
- The
Q Stringfield of theTransparent EC Public Keyis:- the uncompressed point octet form as defined in RFC5480 and used in certificates and TLS records for NIST curves.
- the raw bytes of the public key for Curve 25519 and Curve 448
Internal storage
The IETF now recommends using PKCS#8 and Subject Public Key Info (SPKI) as default formats for inter-operability. This server enforces the KMIP 2.1 default export formats above but the storage formats used in the database are:
PKCS#8 DERfor RSA and EC private Keys (RFC 5208 and 5958).SPKI DER(RFC 5480) for RSA and EC public keys, using the Key Format Type PKCS#8, since SPKI is not listed.X509 DERfor certificates (RFC 5280).PKCS#10 DERfor certificate requests (RFC 2986).TransparentSymmetricKeyfor symmetric keysRawfor opaque objects and Secret Data
Users requesting keys are therefore encouraged to request them in these storage formats to avoid conversions and match recent RFCs.
The Eviden KMS server supports the tagging of objects. Tags are arbitrary strings that can be attached to objects. Tags can be used to group objects together, and to find objects for most operations, such as export, import, encrypt, decrypt, etc.
In addition, the KMS server will automatically add a system tag to objects based on the object type:
_sk: for a private key_pk: for a public key_kk: for a symmetric key_uk: for a Covercrypt user decryption key_cert: for a X509 certificate_sd: for a secret data_oo: for an opaque object
Since there is no provision in the KMIP 2.1 specification for tagging. The Eviden KMS server implements tagging using the following KMIP 2.1 extensions:
-
When
Attributesare passed as part of the KMIP operation, such as in theCreate,Create Key Pair,Locate,CertifyandImportoperations, the tags are passed asVendorAttributeswith the server's configured vendor identification (default:cosmian, configurable via--vendor-identification/KMS_VENDOR_IDENTIFICATION) and attribute nametag. The value is the serialization of the tags as a JSON array of strings. -
When unique identifiers are passed as part of the KMIP operation, such as in the
Certify,Encrypt,Export,Decrypt,Get,Get Attributes,Revoke, andDestroyoperations, the tags are in the unique identifier itself as a serialized JSON array e.g.[ "tag1", "tag2" ].
Example
Export the Symmetric key (tag _kk) with user tag myTag:
{
"tag": "Export",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "[\"_kk\",\"myTag\"]"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "AsRegistered"
}
]
}
In chapter 4, the KMIP 2.1 specification specifies a list of 63 Attributes, mostly made of enumerations and data structures, often nested in each other. Despite this impressive list, and as expected in such a large specification, KMIP allows for extensions to support new cryptographic schemes such as the ones enabled by Eviden.
Extensions in KMIP consist mostly in augmenting enumerations with new values and attributing a specific prefix values, usually 0x8880 to the new variants.
To support Covercrypt, Cosmian is using a few extensions listed below.
Key Format Type
The Key Format Type attribute is a required attribute of a Cryptographic Object.
It is set by the server, but a particular Key Format Type MAY be requested by the client if the cryptographic material is produced by the server (i.e., Create, Create Key Pair, Create Split Key, Re-key, Re-key Key Pair, Derive Key) on the client's behalf. The server SHALL comply with the client's requested format or SHALL fail the request. When the server calculates a Digest for the object, it SHALL compute the digest on the data in the assigned Key Format Type, as well as a digest in the default KMIP Key Format Type for that type of key and the algorithm requested (if a non-default value is specified).
Extensions
CoverCryptSecretKey = 0x8880_000C,
CoverCryptPublicKey = 0x8880_000D,
Cryptographic Algorithm
The Cryptographic Parameters attribute is a structure that contains a set of OPTIONAL fields that describe certain cryptographic parameters to be used when performing cryptographic operations using the object. Specific fields MAY pertain only to certain types of Managed Objects. The Cryptographic Parameters attribute of a Certificate object identifies the cryptographic parameters of the public key contained within the Certificate.
The Cryptographic Algorithm is also used to specify the parameters for cryptographic operations. For operations involving digital signatures, either the Digital Signature Algorithm can be specified or the Cryptographic Algorithm and Hashing Algorithm combination can be specified.
Random IV can be used to request that the KMIP server generate an appropriate IV for a cryptographic operation that uses an IV. The generated Random IV is returned in the response to the cryptographic operation.
IV Length is the length of the Initialization Vector in bits. This parameter SHALL be provided when the specified Block Cipher Mode supports variable IV lengths such as CTR or GCM.
Tag Length is the length of the authenticator tag in bytes. This parameter SHALL be provided when the Block Cipher Mode is GCM.
The IV used with counter modes of operation (e.g., CTR and GCM) cannot repeat for a given cryptographic key. To prevent an IV/key reuse, the IV is often constructed of three parts: a fixed field, an invocation field, and a counter as described in [SP800-38A] and [SP800-38D]. The Fixed Field Length is the length of the fixed field portion of the IV in bits. The Invocation Field Length is the length of the invocation field portion of the IV in bits. The Counter Length is the length of the counter portion of the IV in bits.
Initial Counter Value is the starting counter value for CTR mode (for [RFC3686] it is 1).
Extensions
CoverCrypt = 0x8880_0004,
Vendor Attributes
All keys managed by the Eviden KMS server are primarily a KeyMaterial made of bytes. Some keys, typically those of ABE, also carry information regarding the underlying access policies. This information is carried together with the keys using VendorAttributes
Typically a vendor attribute is made of 3 values: a Vendor Identification - set to the server's configured vendor ID (default: cosmian, configurable via --vendor-identification / KMS_VENDOR_IDENTIFICATION) - and a tuple Attribute Name, Attribute Value.
Covercrypt uses a few vendor attributes which names can be seen in the code attributes.rs file.
The attributes names and corresponding values used for a given KeyFormatType are as follows:
-
VENDOR_ATTR_COVER_CRYPT_POLICY = "cover_crypt_policy": the JSONified Policy found in the master keys. -
VENDOR_ATTR_COVER_CRYPT_ACCESS_POLICY = "cover_crypt_access_policy": the JSONified boolean Access Policy found in a user key
In addition, the VENDOR_ATTR_COVER_CRYPT_ATTR = "cover_crypt_attributes" name is used in Locate requests to identify User Decryption Keys holding certain Policy Attributes.
The easiest way to call the KMIP API is to use the cosmian Command Line Interface
or one of the Eviden cloudproof libraries which provide wrapper calls
in the corresponding language.
Without the use of a library, the client must build the JSON TTLV messages from
an Operation
as described in the KMIP 2.1 specification, and issue an HTTP POST call to the /kmip/2_1 endpoint
of the server.
Multiple operations can be sent in a single call using the Messages API .
!!!info "Easily building JSON TTLV messages"
Building JSON TTLV messages is a complex task and the easiest way to get started is to use
the [KMS CLI](../../kms_clients/index.md) in `JSON mode` mode to print the corresponding request and response messages.
The `JSON mode` is activated by passing the `--kms-print-json` flag to the `cosmian` command.
See the [JSON mode example](#json-mode-example) below.
To send multiple requests in a single call, se the Messages API .
Sample JSON TTLV messages
Please refer to the various operations pages for sample JSON TTLV messages.
JSON mode example
This creates a (default AES 256) symmetric key which will be tagged with the string myKey.
ckms --kms-print-json sym keys create --tag myKey
The CLI will then show the JSON TTLV requests and response:
2024-09-13T13:39:20.001395Z INFO ThreadId(01) cosmian_kms_client::kms_rest_client: ==>
{
"tag": "Create",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
},
{
"tag": "CryptographicUsageMask",
"type": "Integer",
"value": 2108
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "TransparentSymmetricKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B226D794B6579225D"
}
]
}
]
}
]
}
]
}
2024-09-13T13:39:20.018203Z INFO ThreadId(01) cosmian_kms_client::kms_rest_client <==
{
"tag": "CreateResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "925f2175-0676-4785-b9d9-61fff30771f3"
}
]
}
The symmetric key was successfully generated.
Unique identifier: 925f2175-0676-4785-b9d9-61fff30771f3
Tags:
- myKey
OpenAPI Specification and Swagger UI
The Eviden KMS server publishes its complete API as an OpenAPI 3.1 specification and serves an interactive Swagger UI browser directly from the server binary.
Endpoints
| Endpoint | Method | Description |
|---|---|---|
/openapi.yaml | GET | Full OpenAPI 3.1 schema in YAML format |
/swagger | GET | Interactive Swagger UI (HTML page, locally served) |
No authentication is required to access either endpoint; the UI itself uses the configured authentication mechanism to authorize API calls made through the browser.
Using the Swagger UI
Navigate to <server_url>/swagger in a browser.
https://<your-kms-host>:9998/swagger
The page displays all documented operations grouped by tag:
| Tag | Operations |
|---|---|
| KMIP | TTLV-over-HTTP via POST /kmip/2_1 and POST /kmip/1_4 |
| REST Crypto API | Encrypt, decrypt, sign, verify, and MAC under /v1/crypto |
| Server | Health, version, and server-info endpoints |
| Access control | Grant, revoke, list, and check object permissions |
| HSM | HSM status and diagnostics |
| Download | CLI binary download endpoint |
Authentication in the UI
When the KMS is configured with JWT bearer authentication, click the Authorize button
in the Swagger UI and enter your token. The UI will send it as an Authorization: Bearer <token>
header on every subsequent request.
Downloading the spec
curl -O https://<your-kms-host>:9998/openapi.yaml
The downloaded YAML can be imported into any OpenAPI-compatible tooling:
-
Postman —
Import > OpenAPIto generate a full collection with example requests. -
Insomnia —
Import > OpenAPI 3.0. -
openapi-generator — generate a typed client in any language:
openapi-generator-cli generate \ -i openapi.yaml \ -g python \ -o ./kms-client-python -
swagger-codegen — similar code-generation approach.
Security
All assets (JavaScript bundle and stylesheet) are served directly from the KMS binary — there is no external CDN dependency. The server is therefore fully usable in air-gapped environments.
The Swagger UI page is protected by the following HTTP response headers:
| Header | Value |
|---|---|
Content-Security-Policy | default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none' |
The frame-ancestors 'none' directive prevents the page from being embedded in an <iframe>, protecting against clickjacking.
Relationship to the JSON TTLV API
The OpenAPI spec documents the HTTP transport layer of the KMS API. The KMIP operations
themselves are sent as JSON TTLV payloads in the body of POST /kmip/2_1 or POST /kmip/1_4.
See The JSON TTLV KMIP API for the full description of the KMIP message format.
Spec version and server URL
The version field in the OpenAPI YAML is injected dynamically to match the running KMS
binary version. When the kms_public_url configuration option is set, the servers[].url
field is replaced with the configured public URL, making the downloaded spec self-contained
for use in external tooling.
See Configuration file for the
kms_public_url option.
Chapter 8 of the KMIP 2.1
specification defines the Messages functionality, which enables sending/receiving multiple requests/responses at
once (also known as bulk mode).
This is the standard way to communicate with the KMIP server using the Binary protocol on port 5696 or the JSON protocol
on port 9998 and endpoint /kmip.
The /kmip/2_1 endpoint is a Eviden extension allowing the posting of Operations directly to the server without
the need for a RequestMessage wrapper.
This is particularly useful for operations like Encrypt and Decrypt.
Multiple operations can be included in a single RequestMessage query.
The server processes these operations sequentially, though they appear to execute simultaneously.
Each batch item contains an independent request.
For every request message sent, the server returns a response message containing the result status of the requested operation, along with any relevant result data or error messages.
Request and response example
Below are canonical KMIP 2.1 message examples, following the mandatory XML schema AKLC-M-1-21.xml. Each request and response is shown in JSON TTLV format.
1. CreateKeyPair
{
"tag": "RequestMessage",
"type": "Structure",
"value": [
{
"tag": "RequestHeader",
"type": "Structure",
"value": [
{ "tag": "ProtocolVersion", "type": "Structure", "value": [
{ "tag": "ProtocolVersionMajor", "type": "Integer", "value": 2 },
{ "tag": "ProtocolVersionMinor", "type": "Integer", "value": 1 }
] },
{ "tag": "ClientCorrelationValue", "type": "TextString", "value": "AKLC-M-1-21 step=0" },
{ "tag": "BatchCount", "type": "Integer", "value": 1 }
]
},
{
"tag": "BatchItem",
"type": "Structure",
"value": [
{ "tag": "Operation", "type": "Enumeration", "value": "CreateKeyPair" },
{ "tag": "RequestPayload", "type": "Structure", "value": [
{ "tag": "CommonAttributes", "type": "Structure", "value": [
{ "tag": "CryptographicAlgorithm", "type": "Enumeration", "value": "RSA" },
{ "tag": "CryptographicLength", "type": "Integer", "value": 2048 }
] },
{ "tag": "PrivateKeyAttributes", "type": "Structure", "value": [
{ "tag": "Name", "type": "Structure", "value": [
{ "tag": "NameValue", "type": "TextString", "value": "AKLC-M-1-21-private" },
{ "tag": "NameType", "type": "Enumeration", "value": "UninterpretedTextString" }
] },
{ "tag": "CryptographicUsageMask", "type": "Integer", "value": "Sign" }
] },
{ "tag": "PublicKeyAttributes", "type": "Structure", "value": [
{ "tag": "Name", "type": "Structure", "value": [
{ "tag": "NameValue", "type": "TextString", "value": "AKLC-M-1-21-public" },
{ "tag": "NameType", "type": "Enumeration", "value": "UninterpretedTextString" }
] },
{ "tag": "CryptographicUsageMask", "type": "Integer", "value": "Verify" }
] }
] }
]
}
]
}
{
"tag": "ResponseMessage",
"type": "Structure",
"value": [
{
"tag": "ResponseHeader",
"type": "Structure",
"value": [
{ "tag": "ProtocolVersion", "type": "Structure", "value": [
{ "tag": "ProtocolVersionMajor", "type": "Integer", "value": 2 },
{ "tag": "ProtocolVersionMinor", "type": "Integer", "value": 1 }
] },
{ "tag": "TimeStamp", "type": "DateTime", "value": "$NOW" },
{ "tag": "BatchCount", "type": "Integer", "value": 1 }
]
},
{
"tag": "BatchItem",
"type": "Structure",
"value": [
{ "tag": "Operation", "type": "Enumeration", "value": "CreateKeyPair" },
{ "tag": "ResultStatus", "type": "Enumeration", "value": "Success" },
{ "tag": "ResponsePayload", "type": "Structure", "value": [
{ "tag": "PrivateKeyUniqueIdentifier", "type": "TextString", "value": "$UNIQUE_IDENTIFIER_0" },
{ "tag": "PublicKeyUniqueIdentifier", "type": "TextString", "value": "$UNIQUE_IDENTIFIER_1" }
] }
]
}
]
}
2. GetAttributes (Private Key)
{
"tag": "RequestMessage",
"type": "Structure",
"value": [
{
"tag": "RequestHeader",
"type": "Structure",
"value": [
{ "tag": "ProtocolVersion", "type": "Structure", "value": [
{ "tag": "ProtocolVersionMajor", "type": "Integer", "value": 2 },
{ "tag": "ProtocolVersionMinor", "type": "Integer", "value": 1 }
] },
{ "tag": "ClientCorrelationValue", "type": "TextString", "value": "AKLC-M-1-21 step=1" },
{ "tag": "BatchCount", "type": "Integer", "value": 1 }
]
},
{
"tag": "BatchItem",
"type": "Structure",
"value": [
{ "tag": "Operation", "type": "Enumeration", "value": "GetAttributes" },
{ "tag": "RequestPayload", "type": "Structure", "value": [
{ "tag": "UniqueIdentifier", "type": "TextString", "value": "$UNIQUE_IDENTIFIER_0" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "State" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "CryptographicUsageMask" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "UniqueIdentifier" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "ObjectType" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "CryptographicAlgorithm" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "CryptographicLength" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "Digest" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "InitialDate" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "LastChangeDate" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "ActivationDate" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "OriginalCreationDate" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "RandomNumberGenerator" },
{ "tag": "AttributeReference", "type": "Enumeration", "value": "KeyFormatType" }
] }
]
}
]
}
{
"tag": "ResponseMessage",
"type": "Structure",
"value": [
{
"tag": "ResponseHeader",
"type": "Structure",
"value": [
{ "tag": "ProtocolVersion", "type": "Structure", "value": [
{ "tag": "ProtocolVersionMajor", "type": "Integer", "value": 2 },
{ "tag": "ProtocolVersionMinor", "type": "Integer", "value": 1 }
] },
{ "tag": "TimeStamp", "type": "DateTime", "value": "$NOW" },
{ "tag": "BatchCount", "type": "Integer", "value": 1 }
]
},
{
"tag": "BatchItem",
"type": "Structure",
"value": [
{ "tag": "Operation", "type": "Enumeration", "value": "GetAttributes" },
{ "tag": "ResultStatus", "type": "Enumeration", "value": "Success" },
{ "tag": "ResponsePayload", "type": "Structure", "value": [
{ "tag": "UniqueIdentifier", "type": "TextString", "value": "$UNIQUE_IDENTIFIER_0" },
{ "tag": "Attributes", "type": "Structure", "value": [
{ "tag": "State", "type": "Enumeration", "value": "PreActive" },
{ "tag": "CryptographicUsageMask", "type": "Integer", "value": "Sign" },
{ "tag": "UniqueIdentifier", "type": "TextString", "value": "$UNIQUE_IDENTIFIER_0" },
{ "tag": "ObjectType", "type": "Enumeration", "value": "PrivateKey" },
{ "tag": "CryptographicAlgorithm", "type": "Enumeration", "value": "RSA" },
{ "tag": "CryptographicLength", "type": "Integer", "value": 2048 },
{ "tag": "Digest", "type": "Structure", "value": [
{ "tag": "HashingAlgorithm", "type": "Enumeration", "value": "SHA_256" },
{ "tag": "DigestValue", "type": "ByteString", "value": "8eb422ae2b006a05d3c8a542a28536735241b6dc1c37926bc8007bd6220d9230" },
{ "tag": "KeyFormatType", "type": "Enumeration", "value": "PKCS_1" }
] },
{ "tag": "InitialDate", "type": "DateTime", "value": "$NOW" },
{ "tag": "LastChangeDate", "type": "DateTime", "value": "$NOW" },
{ "tag": "OriginalCreationDate", "type": "DateTime", "value": "$NOW" },
{ "tag": "RandomNumberGenerator", "type": "Structure", "value": [
{ "tag": "RNGAlgorithm", "type": "Enumeration", "value": "ANSIX9_31" },
{ "tag": "CryptographicAlgorithm", "type": "Enumeration", "value": "AES" },
{ "tag": "CryptographicLength", "type": "Integer", "value": 256 }
] },
{ "tag": "KeyFormatType", "type": "Enumeration", "value": "PKCS_1" }
] }
] }
]
}
]
}
3. Destroy (Private Key)
{
"tag": "RequestMessage",
"type": "Structure",
"value": [
{
"tag": "RequestHeader",
"type": "Structure",
"value": [
{ "tag": "ProtocolVersion", "type": "Structure", "value": [
{ "tag": "ProtocolVersionMajor", "type": "Integer", "value": 2 },
{ "tag": "ProtocolVersionMinor", "type": "Integer", "value": 1 }
] },
{ "tag": "ClientCorrelationValue", "type": "TextString", "value": "AKLC-M-1-21 step=3" },
{ "tag": "BatchCount", "type": "Integer", "value": 1 }
]
},
{
"tag": "BatchItem",
"type": "Structure",
"value": [
{ "tag": "Operation", "type": "Enumeration", "value": "Destroy" },
{ "tag": "RequestPayload", "type": "Structure", "value": [
{ "tag": "UniqueIdentifier", "type": "TextString", "value": "$UNIQUE_IDENTIFIER_0" }
] }
]
}
]
}
{
"tag": "ResponseMessage",
"type": "Structure",
"value": [
{
"tag": "ResponseHeader",
"type": "Structure",
"value": [
{ "tag": "ProtocolVersion", "type": "Structure", "value": [
{ "tag": "ProtocolVersionMajor", "type": "Integer", "value": 2 },
{ "tag": "ProtocolVersionMinor", "type": "Integer", "value": 1 }
] },
{ "tag": "TimeStamp", "type": "DateTime", "value": "$NOW" },
{ "tag": "BatchCount", "type": "Integer", "value": 1 }
]
},
{
"tag": "BatchItem",
"type": "Structure",
"value": [
{ "tag": "Operation", "type": "Enumeration", "value": "Destroy" },
{ "tag": "ResultStatus", "type": "Enumeration", "value": "Success" },
{ "tag": "ResponsePayload", "type": "Structure", "value": [
{ "tag": "UniqueIdentifier", "type": "TextString", "value": "$UNIQUE_IDENTIFIER_0" }
] }
]
}
]
}
In chapter 6, the KMIP 2.1 specifications describe 57 potential operations that can be performed on a KMS.
Supported Operations
Out of this list, the Eviden KMS server only requires 12 operations to provide all required functionalities to support the cryptographic schemes available on the server.
The list of supported Operations is that of the menu entries below this one.
Messages and Bulk Operations
A KMIP request may be made by POSTing a single Operation serialized as JSON TTLV, or by combining multiple operations
in a Message request. See the bulk mode page for more details.
No support for "ID Placeholders"
KMIP states that a number of the operations are affected by a mechanism referred to as the ID Placeholder. It is a variable stored inside the server that is preserved during the execution of a batch of operations.
Maintaining this value requires maintaining a state during a batch session across multiple requests and potentially multiple servers. The performance gain of using placeholder IDs is not obvious, and the added complexity of maintaining sessions across multiple servers when scaling horizontally is not worth in the Eviden view for the type of operations conducted on the server.
The Eviden KMS servers are kept stateless to simplify horizontal scaling and therefore do not support placeholder IDs for now.
Specification
This operation requests one or more attributes associated with a Managed Object. The object is specified by its Unique Identifier, and the attributes are specified by their name in the request. If a specified attribute has multiple instances, then all instances are returned. If a specified attribute does not exist (i.e., has no value), then it SHALL NOT be present in the returned response. If none of the requested attributes exist, then the response SHALL consist only of the Unique Identifier. The same Attribute Reference SHALL NOT be present more than once in a request.
If no Attribute Reference is provided, the server SHALL return all attributes.
Implementation
This operation can be applied to all supported objects.
Example - A symmetric key
Get the attributes of a symmetric key by its unique identifier 027cced1-ff2b-4bd3-a200-db1041583bdc.
Corresponding KMS CLI command:
ckms attributes get -i 027cced1-ff2b-4bd3-a200-db1041583bdc
The request has an empty AttributeReference structure, which means that all
attributes are requested.
The response contains all the system and user tags associated with the key. This is the hex encoded value of a JSON array with value
["MySymmetricKey", "_kk"]
The VendorIdentification field in the response reflects the server's configured vendor ID
(default: cosmian, configurable via --vendor-identification / KMS_VENDOR_IDENTIFICATION).
{
"tag": "GetAttributes",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "AttributeReference",
"type": "Structure",
"value": []
}
]
}
{
"tag": "GetAttributesResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
},
{
"tag": "CryptographicUsageMask",
"type": "Integer",
"value": 2108
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "TransparentSymmetricKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SplitKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D7953796D6D65747269634B6579222C225F6B6B225D"
}
]
}
]
}
]
}
]
}
Example - A NIST P-256 private key
Get the attributes of a NIST P-256 private key.
Corresponding KMS CLI command:
ckms attributes get -i 927adccb-f59a-4cc9-a9e3-1eeb958c601f
The request has an empty AttributeReference structure, which means that
all attributes are requested.
In the response, please note:
- the
RecommendedCurveisP256, the KMIP name for NIST P-256 - the
tagis the hex encoded value of a JSON array with value["_sk"], the system tag for a private key
{
"tag": "GetAttributes",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "927adccb-f59a-4cc9-a9e3-1eeb958c601f"
},
{
"tag": "AttributeReference",
"type": "Structure",
"value": []
}
]
}
{
"tag": "GetAttributesResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "927adccb-f59a-4cc9-a9e3-1eeb958c601f"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "ECDH"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
},
{
"tag": "CryptographicDomainParameters",
"type": "Structure",
"value": [
{
"tag": "QLength",
"type": "Integer",
"value": 256
},
{
"tag": "RecommendedCurve",
"type": "Enumeration",
"value": "P256"
}
]
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "TransparentECPrivateKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B225F736B225D"
}
]
}
]
}
]
}
]
}
Example - A certificate imported as part of a PKCS#12 container
Get the attributes of the certificate imported as part of a PKCS#12 container (see Import for reference to the imported PKCS#12 container). The certificate is linked to a private key was signed by an intermediate certificate imported as part of the same container.
Corresponding KMS CLI command:
ckms attributes get -i d2f4e937-dda9-4a86-bbe8-c866646a612f
The request has an empty AttributeReference structure, which means that all attributes are requested.
Please note in the response:
- the
Linkto the private key - the
Linkto the intermediate certificate - the presence of all the system and user tags associated with the certificate. This is the hex encoded value of a JSON array with value
{
"tag": "GetAttributes",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "d2f4e937-dda9-4a86-bbe8-c866646a612f"
},
{
"tag": "AttributeReference",
"type": "Structure",
"value": []
}
]
}
{
"tag": "GetAttributesResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "d2f4e937-dda9-4a86-bbe8-c866646a612f"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "X509"
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PrivateKeyLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "bf614d45-5a3e-49b9-95c0-5586d3c0d17b"
}
]
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "CertificateLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "0c9028bc-c518-40d3-8362-12a1edfddab0"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "Certificate"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B225F63657274222C225F636572745F636E3D4D7920736572766572222C225F636572745F73706B693D36353565303430393938383461663363636133653362313164393038626238666432373237306263222C224D79504B43533132222C225F636572745F6973737565723D30633930323862632D633531382D343064332D383336322D313261316564666464616230222C225F636572745F736B3D62663631346434352D356133652D343962392D393563302D353538366433633064313762225D"
}
]
}
]
}
]
}
]
}
Specification
This operation requests the server to either add or modify an attribute. The request contains the Unique Identifier of the Managed Object to which the attribute pertains, along with the attribute and value. If the object did not have any instances of the attribute, one is created. If the object had exactly one instance, then it is modified. If it has more than one instance an error is raised. Read-Only attributes SHALL NOT be added or modified using this operation.
Implementation
This operation can be applied to all supported objects. One or more attributes can be set at once. The operation is idempotent, meaning that if the attribute is already set, the operation will not fail.
Example - A symmetric key
Set an attribute of a symmetric key by its unique identifier 027cced1-ff2b-4bd3-a200-db1041583bdc.
Corresponding KMS CLI command:
First, create a symmetric key:
ckms sym keys create my_symmetric_key
ckms attributes set -i my_symmetric_key --activation-date 1726211157791
The request sets the activation date of a symmetric key.
The response contains all the system and user tags associated with the key. This is the hex encoded value of a JSON array with value
Attribute set successfully
Unique identifier: 6209aa2a-900f-4a1c-b2ca-9b4af1bbd1d1
{
"tag": "SetAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
},
{
"tag": "NewAttribute",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "CertificateLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "certificate_id"
}
]
}
]
}
]
}
{
"tag": "SetAttributeResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
}
]
}
Example - Set links on Certificate
Set the links on a certificate object. It will set 2 KMIP attributes.
Corresponding KMS CLI command:
ckms attributes set -i 03948573-9348-aaaa-aaaa-93857383 --public-key-id xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz --private-key-id xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz
The request set the KMIP links of the public key and the private key of the underlying certificate.
The SetAttribute operation being unitary, 2 requests are sent to the server, one for each link.
Output is:
Attribute set successfully
Unique identifier: 6209aa2a-900f-4a1c-b2ca-9b4af1bbd1d1
[
{
"LinkType": "PublicKeyLink",
"LinkedObjectIdentifier": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
Attribute set successfully
Unique identifier: 6209aa2a-900f-4a1c-b2ca-9b4af1bbd1d1
[
{
"LinkType": "PrivateKeyLink",
"LinkedObjectIdentifier": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
{
"tag": "SetAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
},
{
"tag": "NewAttribute",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PublicKeyLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
}
]
}
]
}
{
"tag": "SetAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
},
{
"tag": "NewAttribute",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PrivateKeyLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
}
]
}
]
}
{
"tag": "SetAttributeResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
}
]
}
Specification
This operation requests the server to modify an attribute value associated with a Managed Object. The request contains
the Unique Identifier of the Managed Object whose attribute is to be modified, along with the attribute and its new
value. Unlike SetAttribute, ModifyAttribute is intended to replace the value of an existing attribute — it does
not create the attribute if it is absent.
Read-Only attributes SHALL NOT be modified using this operation.
Implementation
This operation can be applied to all supported objects.
Supported attributes
The following KMIP attributes can be modified:
| Attribute | Notes |
|---|---|
ActivationDate | Pre-Active objects only. If the new date ≤ now the object automatically transitions to Active (KMIP spec §3.22). |
CryptographicAlgorithm | Replaces the algorithm of the managed object. |
CryptographicLength | Replaces the key length in bits. |
CryptographicParameters | Replaces the cryptographic parameters structure. |
CryptographicDomainParameters | Replaces the domain parameters structure. |
CryptographicUsageMask | Replaces the bitmask of allowed cryptographic usages. |
DeactivationDate | Sets or replaces the deactivation date. |
Digest | Replaces the digest structure. |
Link | Replaces the linked object identifier for the given link type. |
Name | Replaces the first Name entry if one exists, otherwise adds it. |
ObjectGroup | Replaces the object group string. |
ObjectType | Replaces the object type. |
UniqueIdentifier | Replaces the unique identifier attribute. |
VendorAttribute | Replaces a vendor attribute value identified by vendor ID + attribute name. |
Read-only attributes
The following attributes are read-only and SHALL NOT be modified. Any attempt returns an
Attribute_Read_Only error:
StateCertificateLength
Example - Modify the cryptographic length of a symmetric key
Corresponding KMS CLI command:
ckms sym keys create my_symmetric_key
ckms attributes set -i my_symmetric_key --cryptographic-length 128
ckms attributes modify -i my_symmetric_key --cryptographic-length 256
Output:
Attribute modified successfully
Unique identifier: my_symmetric_key
{
"tag": "ModifyAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
},
{
"tag": "NewAttribute",
"type": "Structure",
"value": [
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
}
]
}
]
}
{
"tag": "ModifyAttributeResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
}
]
}
Example - Modify the cryptographic algorithm
ckms attributes modify -i my_symmetric_key --cryptographic-algorithm chacha20
{
"tag": "ModifyAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
},
{
"tag": "NewAttribute",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "ChaCha20"
}
]
}
]
}
{
"tag": "ModifyAttributeResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
}
]
}
Example - Modify the activation date on a Pre-Active key
ActivationDate can only be modified on Pre-Active objects. Setting a date that is in the past or equal to the
current time will automatically transition the object to the Active state.
ckms attributes modify -i my_preactive_key --activation-date 1773571883
{
"tag": "ModifyAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_preactive_key"
},
{
"tag": "NewAttribute",
"type": "Structure",
"value": [
{
"tag": "ActivationDate",
"type": "DateTime",
"value": "2026-03-15T10:11:23+00:00"
}
]
}
]
}
{
"tag": "ModifyAttributeResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_preactive_key"
}
]
}
Example - Read-only attribute rejection
Attempting to modify a read-only attribute such as State will return an Attribute_Read_Only error:
{
"tag": "ModifyAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_symmetric_key"
},
{
"tag": "NewAttribute",
"type": "Structure",
"value": [
{
"tag": "State",
"type": "Enumeration",
"value": "Active"
}
]
}
]
}
{
"tag": "ResponseMessage",
"type": "Structure",
"value": [
{
"tag": "ResponseHeader",
"type": "Structure",
"value": [
{
"tag": "ProtocolVersion",
"type": "Structure",
"value": [
{ "tag": "ProtocolVersionMajor", "type": "Integer", "value": 2 },
{ "tag": "ProtocolVersionMinor", "type": "Integer", "value": 1 }
]
},
{ "tag": "TimeStamp", "type": "DateTime", "value": "2026-03-15T10:11:23+00:00" },
{ "tag": "BatchCount", "type": "Integer", "value": 1 }
]
},
{
"tag": "BatchItem",
"type": "Structure",
"value": [
{ "tag": "Operation", "type": "Enumeration", "value": "ModifyAttribute" },
{ "tag": "ResultStatus", "type": "Enumeration", "value": "OperationFailed" },
{ "tag": "ResultReason", "type": "Enumeration", "value": "Attribute_Read_Only" },
{ "tag": "ResultMessage", "type": "TextString", "value": "DENIED" }
]
}
]
}
Specification
This operation requests the server to delete an attribute associated with a Managed Object. The request contains the Unique Identifier of the Managed Object whose attribute is to be deleted, the Current Attribute of the attribute. Attributes that are always REQUIRED to have a value SHALL never be deleted by this operation. Attempting to delete a non-existent attribute or specifying an Current Attribute for which there exists no attribute value SHALL result in an error. If no Current Attribute is specified in the request, and an Attribute Reference is specified, then all instances of the specified attribute SHALL be deleted.
Implementation
This operation can be applied to all supported objects. One or more attributes can be set at once.
Example - Delete links on Certificate
First, for the demo purpose create a certificate:
ckms certificates certify --generate-key-pair --subject-name C=yo --algorithm rsa2048 -c my_certificate
Delete the links on a certificate object.
Corresponding KMS CLI command:
ckms attributes delete -i my_certificate --public-key-id xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz --private-key-id xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz --certificate-id xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz
The request deletes the KMIP links of the public key and the private key of the underlying certificate.
The DeleteAttribute operation being unitary, 3 requests are sent to the server, one for each link.
Output is:
Attribute deleted successfully
Unique identifier: my_certificate
[
{
"LinkType": "PublicKeyLink",
"LinkedObjectIdentifier": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
Attribute deleted successfully
Unique identifier: my_certificate
[
{
"LinkType": "PrivateKeyLink",
"LinkedObjectIdentifier": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
Attribute deleted successfully
Unique identifier: my_certificate
[
{
"LinkType": "CertificateLink",
"LinkedObjectIdentifier": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
{
"tag": "DeleteAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_certificate"
},
{
"tag": "CurrentAttribute",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PublicKeyLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
}
]
}
]
}
{
"tag": "DeleteAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_certificate"
},
{
"tag": "CurrentAttribute",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PrivateKeyLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
}
]
}
]
}
{
"tag": "DeleteAttribute",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_certificate"
},
{
"tag": "CurrentAttribute",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "CertificateLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "xxxxxxxx-yyyy-yyyy-yyyy-zzzzzzzzzzzz"
}
]
}
]
}
]
}
{
"tag": "DeleteAttributeResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "my_certificate"
}
]
}
Specifications
This request is used to generate a Certificate object for a public key. This request supports the certification of a new public key, as well as the certification of a public key that has already been certified (i.e., certificate update). Only a single certificate SHALL be requested at a time.
The Certificate Request object MAY be omitted, in which case the public key for which a Certificate object is generated SHALL be specified by its Unique Identifier only. If the Certificate Request Type and the Certificate Request objects are omitted from the request, then the Certificate Type SHALL be specified using the Attributes object.
The Certificate Request is passed as a Byte String, which allows multiple certificate request types for X.509 certificates (e.g., PKCS#10, PEM, etc.) to be submitted to the server.
The generated Certificate object whose Unique Identifier is returned MAY be obtained by the client via a Get operation in the same batch, using the ID Placeholder mechanism.
For the public key, the server SHALL create a Link attribute of Link Type Certificate pointing to the generated certificate. For the generated certificate, the server SHALL create a Link attribute of Link Type Public Key pointing to the Public Key.
The server SHALL copy the Unique Identifier of the generated certificate returned by this operation into the ID Placeholder variable.
If the information in the Certificate Request conflicts with the attributes specified in the Attributes, then the information in the Certificate Request takes precedence.
Implementation
The KMIP implementation does not:
- specify how the signer is selected and whether self-signing is allowed
- specify how the certificate extensions are provided
- and only supports Certificate Signing Request (CSR) and certifying public keys
Eviden has extended the specifications and offers 4 possibilities to generate a certificate
- Providing a Certificate Signing Request (CSR)
- Providing a public key id to certify as well as a subject name
- Providing an existing certificate id to re-certify
- Generating a keypair then signing the public key to generate a certificate specifying a subject name and an algorithm
The signer is specified by providing an issuer private key id and/or an issuer certificate via the Links in the attributes of the request. If only one of this parameter is specified, the other one will be inferred from the links of the cryptographic object behind the provided parameter.
If no signer is provided, the certificate will be self-signed. It is not possible to self-sign a CSR.
When re-certifying a certificate, if no certificate unique identifier is provided, the original certificate id will be used and the original certificate will be replaced by the new one. In all other cases, a random certificate id will be generated.
Post-quantum (PQC) certificates
The Eviden KMS generates fully standards-compliant X.509 v3 certificates for all NIST-standardized post-quantum algorithms:
- ML-DSA (CRYSTALS-Dilithium) — RFC 9881:
self-signed or CA-signed; the KMS automatically adds a critical
keyUsageextension withdigitalSignature. - SLH-DSA (SPHINCS+) — draft-ietf-lamps-x509-slh-dsa:
self-signed or CA-signed; same
digitalSignaturekey usage. - ML-KEM (CRYSTALS-Kyber) — RFC 9935:
always CA-issued (ML-KEM cannot self-sign); the KMS automatically adds a critical
keyUsageextension withkeyEnciphermentonly.
See Post-Quantum X.509 Certificates for detailed usage instructions, OID tables, CLI examples, and cross-algorithm PKI guidance.
Supply X509 extensions (optional)
Specify X509 extensions for a Certify operation is possible using the KMS CLI.
The --certificate-extensions arg (short version -e) expects a path to a configuration file
written in ini format (roughly the same format
as OpenSSL X509 v3 cert extension cnf format).
The extensions may be part of a paragraph called v3_ca.
Example of a configuration file containing v3_ca parag describing extensions to add:
[v3_ca]
basicConstraints=critical,CA:FALSE,pathlen:0
keyUsage=keyCertSign,digitalSignature
extendedKeyUsage=emailProtection
crlDistributionPoints=URI:http://cse.example.com/crl.pem
These extensions are embedded in the Certify request within the vendor attributes.
Example of the corresponding KMS CLI command:
ckms certificates certify \
-r my_cert.csr -k 854d7914-3b1d-461a-a2dd-7aad27043b56 -d 365 -t "MyCert" \
-e /some/path/to/ext.cnf
Example - PKCS#10 Certificate Signing Request
Certify a PKCS#10 Certificate Signing Request (CSR) with the issuer private key unique identifier
854d7914-3b1d-461a-a2dd-7aad27043b56, and set the certificate requested validity to 365 days and
the tag to MyCert.
The corresponding KMS CLI command is:
ckms certificates certify -r my_cert.csr -k 854d7914-3b1d-461a-a2dd-7aad27043b56 -d 365 -t "MyCert"
Note: the KMS CLIent converts the CSR from PEM TO DER before creating the JSON TTLV and sending it to the server.
{
"tag": "Certify",
"type": "Structure",
"value": [
{
"tag": "CertificateRequestType",
"type": "Enumeration",
"value": "PEM"
},
{
"tag": "CertificateRequestValue",
"type": "ByteString",
"value": "2D2D2D2D2D424547494E20434552544946494341544520524551554553542D2D2D2D2D0A4D494944704443434167774341514177587A454C4D416B474131554542684D43526C49784444414B42674E564241674D41306C6B526A454F4D417747413155450A427777465547467961584D784544414F42674E5642416F4D42304E7663323170595734784444414B42674E564241734D4131496D524445534D424147413155450A4177774A5647567A6443424D5A57466D4D4949426F6A414E42676B71686B6947397730424151454641414F43415938414D49494269674B4341594541773045470A575355754F4E59526C5A3077506139524A7057416C577351515A5050675350786E354D5777464E4F383671676856666378314C387169515079315147687172320A764F766D577A366D752F59772F5663366E44644744694B54555564537341305167566474643770366B71317341393071364C30416E63384D384D46392F6F536F0A7145642F6C4F436774744F6D55667842566C314B6D7146434146464854786E4B5737387954332F3438386B57373952516B6D41367733416246377361787639500A706843365A634F76514F6836644D42326E4E6C574C67537670312B3948674455635956394D53575A6D2B376C524F5468552B41676433363364355A57574F41470A495659544E5A2F6E746B69705270717251352B7356694863752F4E4F544D757733524C632F575347736D6A594E57616465304C6D2F58685032684D67416D6F350A306474792B36307970437342573269504A6652755152743342644249632B3971637946326176786C457431414446556A49726B305353516F39774A45313953440A68534A414A33782B4D31466C6D4C2B34464832726E69777555615A6F6844506938567542367A634430747732524F664471586A2F5A4B356C7A4A6D745A6B53790A5636704B54485035737558372B6A3848324A35554A496F46487A44484764674E315A724C3570773563305A6D65634B516D5756796F394854614B364641674D420A414147674144414E42676B71686B6947397730424151734641414F4341594541594236615738625549306361466443356939334F376542345530535A414745740A612F546B5133486C764456364F2B327A64735042304F4672385262355171784134776A3843536579466C7A775666497172756A48457831557150706E2B7932720A4C6C397236754C7257725A753568664C767749752B774C6A617644425662354E2B7159536548357643334A582B4652385A64787A6B5754776465464C6F4273340A434749456D46494D2F2B666E79676E6B4C455254566B6738337339534B44736838316772755438302F6135365649636D656E373470584830514641615368766F0A7A52486F7670766A5631735A416265595365796B69564E53497179734166594A33327168744173366E5367796751637A546773756A4F746C63776653432B71550A497A4D623932325A654B5445427A7A3859326351394D6245714850787276664B5A675A4A43306B57342F482B736F2B5659776A684956337048705842527944640A6359637275732B434D335A416A456439585A6C39466D37454555736E346D7459486F497541394167756949425152596B473469726863524E5449377A36755A2B0A77544E724D792B47646B436B5271424256714146374E3473696931356E334E716A3535637257452F642F38316B574E36495943504448586C4F38756B4A6E4B750A30524E6A4B52656551624377596B72464C7A4F5A677342674E6C626E364263470A2D2D2D2D2D454E4420434552544946494341544520524551554553542D2D2D2D2D0A"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PrivateKeyLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "854d7914-3b1d-461a-a2dd-7aad27043b56"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "Certificate"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "requested_validity_days"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "333635"
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D7943657274225D"
}
]
}
]
}
]
}
]
}
{
"tag": "CertifyResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "b7225902-a035-45e6-a3d2-fa65c0ca7af1"
}
]
}
Example - Public key
Certify a public key with unique id 45e56e67-d813-468f-9116-4d1e611a1828 using the issuer private
key
45e56e67-d813-468f-9116-4d1e611a1828.
Set the Subject Name of the certificate to C=FR, ST=IdF, L=Paris, O=AcmeTest, CN=bob@acme.com, the
tag to Bob and
the certificate requested validity to 365 days.
The corresponding KMS CLI command is
ckms certificates certify -p 45e56e67-d813-468f-9116-4d1e611a1828 -k 854d7914-3b1d-461a-a2dd-7aad27043b56 \
-d 365 -t "Bob" --subject-name "C=FR, ST=IdF, L=Paris, O=AcmeTest, CN=bob@acme.com"
Please note the following in the JSON TTLV of the request:
- the various Subject Name fields that are set for the certificate
- the Subject Name issuer fields are ignored: they will be copied from the certificate linked to the issuer private key
{
"tag": "Certify",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "45e56e67-d813-468f-9116-4d1e611a1828"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CertificateAttributes",
"type": "Structure",
"value": [
{
"tag": "CertificateSubjectCn",
"type": "TextString",
"value": "bob@acme.com"
},
{
"tag": "CertificateSubjectO",
"type": "TextString",
"value": "AcmeTest"
},
{
"tag": "CertificateSubjectOu",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateSubjectEmail",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateSubjectC",
"type": "TextString",
"value": "FR"
},
{
"tag": "CertificateSubjectSt",
"type": "TextString",
"value": "IdF"
},
{
"tag": "CertificateSubjectL",
"type": "TextString",
"value": "Paris"
},
{
"tag": "CertificateSubjectUid",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateSubjectSerialNumber",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateSubjectTitle",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateSubjectDc",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateSubjectDnQualifier",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerCn",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerO",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerOu",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerEmail",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerC",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerSt",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerL",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerUid",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerSerialNumber",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerTitle",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerDc",
"type": "TextString",
"value": ""
},
{
"tag": "CertificateIssuerDnQualifier",
"type": "TextString",
"value": ""
}
]
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PrivateKeyLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "854d7914-3b1d-461a-a2dd-7aad27043b56"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "Certificate"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "requested_validity_days"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "333635"
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B22426F62225D"
}
]
}
]
}
]
}
]
}
{
"tag": "CertifyResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "974b3a79-25a8-4ace-bdd9-70f5b07695c9"
}
]
}
Specification
This operation requests the server to generate a new symmetric key or generate Secret Data as a Managed Cryptographic Object.
The request contains information about the type of object being created, and some of the attributes to be assigned to the object (e.g., Cryptographic Algorithm, Cryptographic Length, etc.).
The response contains the Unique Identifier of the created object. The server SHALL copy the Unique Identifier returned in this operation into the ID Placeholder variable.
Implementation
This operation can be used to create a new symmetric key or a new Covercrypt user decryption key.
Example - Symmetric Key
Creating a 256 bit AES Symmetric Key with the tag MySymmetricKey.
The tags are assembled in a JSON array and encoded in hex.
The CryptographicUsageMask is optional.
Corresponding KMS CLI command:
ckms sym keys create --tag MySymmetricKey
{
"tag": "Create",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
},
{
"tag": "CryptographicUsageMask",
"type": "Integer",
"value": 2108
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "TransparentSymmetricKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "Attribute",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "TextString",
"value": "[\"MySymmetricKey\"]"
}
]
}
]
}
]
}
{
"tag": "CreateResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
}
]
}
Example - Covercrypt User Decryption Key
Creating a Covercrypt User Decryption Key with the tag MyUserKey and the access policy Security Level::Confidential && (Department::FIN || Department::HR)
(see Create Key Pair for the corresponding master key access structure).
Corresponding KMS CLI command:
ckms cc keys create-user-key -t "MyUserKey"\
b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9 \
"Security Level::Confidential && (Department::FIN || Department::HR)"
Please note:
- The tag(s) is (are) assembled in a JSON array and encoded in hex.
- The access policy is encoded in hex.
{
"tag": "Create",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "ParentLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "cover_crypt_access_policy"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5365637572697479204C6576656C3A3A436F6E666964656E7469616C20262620284465706172746D656E743A3A46494E207C7C204465706172746D656E743A3A485229"
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D79557365724B6579225D"
}
]
}
]
}
]
}
]
}
{
"tag": "CreateResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "df871e79-0923-47cd-9078-bbec83287c85"
}
]
}
Specification
This operation requests the server to generate a new public/private key pair and register the two corresponding new Managed Cryptographic Objects.
The request contains attributes to be assigned to the objects (e.g., Cryptographic Algorithm, Cryptographic Length, etc.). Attributes MAY be specified for both keys at the same time by specifying a Common Attributes object in the request.
Attributes not common to both keys (e.g., Name, Cryptographic Usage Mask) MAY be specified using the Private Key Attributes and Public Key Attributes objects in the request, which take precedence over the Common Attributes object.
For the Private Key, the server SHALL create a Link attribute of Link Type Public Key pointing to the Public Key. For the Public Key, the server SHALL create a Link attribute of Link Type Private Key pointing to the Private Key. The response contains the Unique Identifiers of both created objects. The ID Placeholder value SHALL be set to the Unique Identifier of the Private Key.
Implementation
Please see the supported objects for the list of key pairs that can be created with this operation.
Example - X25519 Key Pair
Creating an X25519 key pair with the tag MyECKeyPair.
Please note:
- The tag is set in a JSON array and is hex-encoded before being added to the KMIP request.
- The
KeyFormatTypeis set toECPrivateKey. - The
ObjectTypeis set toPrivateKey. - The
CryptographicAlgorithmis set toECDH. - The
RecommendedCurveis set toCURVE25519.
Corresponding KMS CLI command:
ckms ec keys create
{
"tag": "CreateKeyPair",
"type": "Structure",
"value": [
{
"tag": "CommonAttributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "ECDH"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 253
},
{
"tag": "CryptographicDomainParameters",
"type": "Structure",
"value": [
{
"tag": "QLength",
"type": "Integer",
"value": 253
},
{
"tag": "RecommendedCurve",
"type": "Enumeration",
"value": "CURVE25519"
}
]
},
{
"tag": "CryptographicUsageMask",
"type": "Integer",
"value": 2108
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "ECPrivateKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D7945434B657950616972225D"
}
]
}
]
}
]
}
]
}
{
"tag": "CreateKeyPairResponse",
"type": "Structure",
"value": [
{
"tag": "PrivateKeyUniqueIdentifier",
"type": "TextString",
"value": "1ac18648-ab17-4755-97a3-7a24b8198b97"
},
{
"tag": "PublicKeyUniqueIdentifier",
"type": "TextString",
"value": "52573030-0fed-4c67-b311-ceac944b2afc"
}
]
}
Example -Covercrypt Master Key Pair
Creating a Covercrypt master key pair with the following access structure specifications which is hex-encoded before being added to the KMIP request.
Note: it is much easier to use the KMS CLI to create Covercrypt master keys where a simple specification file can be used. Use the debug mode to get the hex-encoded access structure from the specifications.
For a specification file
{
"Security Level::<": [
"Protected",
"Confidential",
"Top Secret::+"
],
"Department": [
"RnD",
"HR",
"MKG",
"FIN"
]
}
The access structure to hex-encode to the call will be:
{
"version": "V2",
"last_attribute_value": 7,
"dimensions": {
"Security Level": {
"order": [
"Protected",
"Confidential",
"Top Secret"
],
"attributes": {
"Confidential": {
"rotation_values": [
6
],
"encryption_hint": "Classic",
"write_status": "EncryptDecrypt"
},
"Top Secret": {
"rotation_values": [
7
],
"encryption_hint": "Hybridized",
"write_status": "EncryptDecrypt"
},
"Protected": {
"rotation_values": [
5
],
"encryption_hint": "Classic",
"write_status": "EncryptDecrypt"
}
}
},
"Department": {
"order": null,
"attributes": {
"MKG": {
"rotation_values": [
3
],
"encryption_hint": "Classic",
"write_status": "EncryptDecrypt"
},
"FIN": {
"rotation_values": [
4
],
"encryption_hint": "Classic",
"write_status": "EncryptDecrypt"
},
"RnD": {
"rotation_values": [
1
],
"encryption_hint": "Classic",
"write_status": "EncryptDecrypt"
},
"HR": {
"rotation_values": [
2
],
"encryption_hint": "Classic",
"write_status": "EncryptDecrypt"
}
}
}
}
}
Corresponding KMS CLI command:
ckms cc keys create-master-key-pair -s access_structure_specifications.json
{
"tag": "CreateKeyPair",
"type": "Structure",
"value": [
{
"tag": "CommonAttributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "cover_crypt_policy"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "7B2276657273696F6E223A225632222C226C6173745F6174747269627574655F76616C7565223A372C2264696D656E73696F6E73223A7B225365637572697479204C6576656C223A7B226F72646572223A5B2250726F746563746564222C22436F6E666964656E7469616C222C22546F7020536563726574225D2C2261747472696275746573223A7B22436F6E666964656E7469616C223A7B22726F746174696F6E5F76616C756573223A5B365D2C22656E6372797074696F6E5F68696E74223A22436C6173736963222C2277726974655F737461747573223A22456E637279707444656372797074227D2C22546F7020536563726574223A7B22726F746174696F6E5F76616C756573223A5B375D2C22656E6372797074696F6E5F68696E74223A22487962726964697A6564222C2277726974655F737461747573223A22456E637279707444656372797074227D2C2250726F746563746564223A7B22726F746174696F6E5F76616C756573223A5B355D2C22656E6372797074696F6E5F68696E74223A22436C6173736963222C2277726974655F737461747573223A22456E637279707444656372797074227D7D7D2C224465706172746D656E74223A7B226F72646572223A6E756C6C2C2261747472696275746573223A7B224D4B47223A7B22726F746174696F6E5F76616C756573223A5B335D2C22656E6372797074696F6E5F68696E74223A22436C6173736963222C2277726974655F737461747573223A22456E637279707444656372797074227D2C2246494E223A7B22726F746174696F6E5F76616C756573223A5B345D2C22656E6372797074696F6E5F68696E74223A22436C6173736963222C2277726974655F737461747573223A22456E637279707444656372797074227D2C22522644223A7B22726F746174696F6E5F76616C756573223A5B315D2C22656E6372797074696F6E5F68696E74223A22436C6173736963222C2277726974655F737461747573223A22456E637279707444656372797074227D2C224852223A7B22726F746174696F6E5F76616C756573223A5B325D2C22656E6372797074696F6E5F68696E74223A22436C6173736963222C2277726974655F737461747573223A22456E637279707444656372797074227D7D7D7D7D"
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B5D"
}
]
}
]
}
]
}
]
}
{
"tag": "CreateKeyPairResponse",
"type": "Structure",
"value": [
{
"tag": "PrivateKeyUniqueIdentifier",
"type": "TextString",
"value": "b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9"
},
{
"tag": "PublicKeyUniqueIdentifier",
"type": "TextString",
"value": "0fd1f684-156c-4ca6-adc2-0a6f4b620463"
}
]
}
Specification
This operation requests the server to perform a decryption operation on the provided data using a Managed Cryptographic Object as the key for the decryption operation.
The request contains information about the cryptographic parameters (mode and padding method), the data to be decrypted, and the IV/Counter/Nonce to use. The cryptographic parameters MAY be omitted from the request as they can be specified as associated attributes of the Managed Cryptographic Object. The initialization vector/counter/nonce MAY also be omitted from the request if the algorithm does not use an IV/Counter/Nonce.
The response contains the Unique Identifier of the Managed Cryptographic Object used as the key and the result of the decryption operation.
The success or failure of the operation is indicated by the Result Status (and if failure, the Result Reason) in the response header.
Implementation
To see the list of supported cryptographic algorithms, please refer to Supported Algorithms.
Example - AES GCM decryption
Decrypting the text Hello, world! with symmetric key 027cced1-ff2b-4bd3-a200-db1041583bd (go to [Create](.
/_create.md) to see how to create the symmetric key).
Instead of using the UID of the key, we can use the unique tag of the key MySymmetricKey. The key must be uniquely
identified. It is possible to use multiple tags to identify a key; for instance symmetric keys automatically get a
system tag _kk. See tagging for more information on tags.
Corresponding KMS CLI command:
ckms sym decrypt /tmp/encrypted.bin -t "MySymmetricKey"
where /tmp/encrypted.bin contains the a concatenation of the the nonce, the encrypted and the authentication tag
in that order.
The JSON TTLV request the same information as in the Encrypt Response:
- the encrypted data
- the nonce: 12 bytes
- the authentication tag: 16 bytes
{
"tag": "Decrypt",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "[\"MySymmetricKey\"]"
},
{
"tag": "Data",
"type": "ByteString",
"value": "40D59A0735811135749A507FDEB3"
},
{
"tag": "IVCounterNonce",
"type": "ByteString",
"value": "DBDD622A64F7D65E75894B1B"
},
{
"tag": "AuthenticatedEncryptionTag",
"type": "ByteString",
"value": "50FCE680540BD3E96EFA9218A2F1009D"
}
]
}
{
"tag": "DecryptResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "Data",
"type": "ByteString",
"value": "48656C6C6F2C20776F726C64210A"
}
]
}
Example - Covercrypt
Decrypting the text Hello, world! with Covercrypt user decryption key df871e79-0923-47cd-9078-bbec83287c85 (go
to Create to see how to create the Covercrypt user decryption key).
Instead of using the UID of the key, we can use the unique tag of the key MyUserKey. The key must be uniquely
identified. It is possible to use multiple tags to identify a key; for instance Covercrypt user decryption keys
automatically get a system tag _uk. See tagging for more information on tags.
Corresponding KMS CLI command:
ckms cc decrypt /tmp/encrypted.bin -t "MyUserKey"
{
"tag": "Decrypt",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "[\"MyUserKey\"]"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "AEA6CF824612448B8445CAF46F9D987161706DAD6E43DFD1A57DD0F39869DC39A68096657A3EDC03CBC619D563744D2CC9819B6A9AB9A3893FD27F452F49A244A8CAA42279C4705D4D3A9E04D2B7887F0100D947F27D27BBD1D06F5A65087F73B8AAB617568761273282D4C14770FFCBA47200D02DDB4C48E1028DC5C50DE860A10A26E35AC405EFE6405486B56E9968594471075687D7BF6935BD003D"
}
]
}
{
"tag": "DecryptResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "df871e79-0923-47cd-9078-bbec83287c85"
},
{
"tag": "Data",
"type": "ByteString",
"value": "0048656C6C6F2C20776F726C64210A"
}
]
}
Specification
This operation is used to indicate to the server that the key material for the specified Managed Object SHALL be destroyed or rendered inaccessible. The meta-data for the key material SHALL be retained by the server. Objects SHALL only be destroyed if they are in either Pre-Active or Deactivated state.
Implementation
To destroy a key, it must be revoked using the Revoke operation first, unless it belongs to an external store,
such as an HSM.
Eviden has added an option Remove flag to the Destroy operation. If the Remove flag is set to true, the key
is completely removed from the database. This does not follow the KMIP 2.1 specification, but is useful in scenarios
where the key was incorrectly created and the ID must ne re-used or for GDPR compliance, when the key is associated
with personal data.
HSM keys are systematically removed when calling the destroy operation.
Unless, they are removed, destroyed keys are set in the state destroyed on the Eviden KMS Server. They can only be
retrieved using theExport operation. The Get operation will return an error. No key material will be returned by the
Export operation, only metadata.
Example - Symmetric key
Destroying key f54f14a3-5639-4054-8c23-54af891669db:
Corresponding cosmian command:
ckms sym keys destroy -k f54f14a3-5639-4054-8c23-54af891669db --remove
{
"tag": "Destroy",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "f54f14a3-5639-4054-8c23-54af891669db"
},
{
"tag": "Remove",
"type": "Boolean",
"value": true
}
]
}
{
"tag": "DestroyResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "f54f14a3-5639-4054-8c23-54af891669db"
}
]
}
Specification
This operation requests the server to perform an encryption operation on the provided data using a Managed Cryptographic Object as the key for the encryption operation.
The request contains information about the cryptographic parameters (mode and padding method), the data to be encrypted, and the IV/Counter/Nonce to use. The cryptographic parameters MAY be omitted from the request as they can be specified as associated attributes of the Managed Cryptographic Object. The IV/Counter/Nonce MAY also be omitted from the request if the cryptographic parameters indicate that the server shall generate a Random IV on behalf of the client or the encryption algorithm does not need an IV/Counter/Nonce. The server does not store or otherwise manage the IV/Counter/Nonce.
If the Managed Cryptographic Object referenced has a Usage Limits attribute, then the server SHALL obtain an allocation from the current Usage Limits value prior to performing the encryption operation. If the allocation is unable to be obtained, the operation SHALL return with a result status of Operation Failed and result reason of Permission Denied.
The response contains the Unique Identifier of the Managed Cryptographic Object used as the key and the result of the encryption operation.
The success or failure of the operation is indicated by the Result Status (and, if failure, the Result Reason) in the response header.
Implementation
To see the list of supported cryptographic algorithms, please refer to Supported Algorithms.
Example - AES GCM encryption
Encrypting the text Hello, world! with symmetric key 027cced1-ff2b-4bd3-a200-db1041583bd (go to Create
to see how to create the symmetric key).
Corresponding KMS CLI command:
ckms sym encrypt -t "MySymmetricKey" /tmp/hello_world.txt
Note: the file /tmp/hello_world.txt contains the text Hello, world!.
Please note that the response contains:
- the encrypted data
- the nonce: 12 bytes
- the authentication tag: 16 bytes
{
"tag": "Encrypt",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "[\"MySymmetricKey\"]"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "BlockCipherMode",
"type": "Enumeration",
"value": "GCM"
},
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "48656C6C6F2C20776F726C64210A"
}
]
}
{
"tag": "EncryptResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "Data",
"type": "ByteString",
"value": "40D59A0735811135749A507FDEB3"
},
{
"tag": "IVCounterNonce",
"type": "ByteString",
"value": "DBDD622A64F7D65E75894B1B"
},
{
"tag": "AuthenticatedEncryptionTag",
"type": "ByteString",
"value": "50FCE680540BD3E96EFA9218A2F1009D"
}
]
}
Example - Covercrypt
Encrypting the text Hello, world! with the Covercrypt master public key 0fd1f684-156c-4ca6-adc2-0a6f4b620463
(go to Create Key Pair to see how to create the mater key pair) and attributes Security Level::Confidential && Department::FIN.
Corresponding KMS CLI command:
ckms cc encrypt -k 0fd1f684-156c-4ca6-adc2-0a6f4b620463 \
/tmp/hello_world.txt "Security Level::Confidential && Department::FIN"
Note: the file /tmp/hello_world.txt contains the text Hello, world!.
In the request, please note that the Data parameter contains:
- the length of the bytes of the attributes:
47 = 2Fin hexadecimal - the attributes as bytes:
Security Level::Confidential && Department::FIN - the bytes to encrypt:
Hello, world!as UTF-8 bytes
{
"tag": "Encrypt",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "0fd1f684-156c-4ca6-adc2-0a6f4b620463"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "2F5365637572697479204C6576656C3A3A436F6E666964656E7469616C202626204465706172746D656E743A3A46494E0048656C6C6F2C20776F726C64210A"
}
]
}
{
"tag": "EncryptResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "0fd1f684-156c-4ca6-adc2-0a6f4b620463"
},
{
"tag": "Data",
"type": "ByteString",
"value": "AEA6CF824612448B8445CAF46F9D987161706DAD6E43DFD1A57DD0F39869DC39A68096657A3EDC03CBC619D563744D2CC9819B6A9AB9A3893FD27F452F49A244A8CAA42279C4705D4D3A9E04D2B7887F0100D947F27D27BBD1D06F5A65087F73B8AAB617568761273282D4C14770FFCBA47200D02DDB4C48E1028DC5C50DE860A10A26E35AC405EFE6405486B56E9968594471075687D7BF6935BD003D"
},
{
"tag": "IVCounterNonce",
"type": "ByteString",
"value": "1A2B3C4D5E6F708192A3B4C5D6E7F801"
},
{
"tag": "AuthenticatedEncryptionTag",
"type": "ByteString",
"value": "0DCB3857D841616BF7262193BC19CBC5"
}
]
}
Specification
This operation requests that the server returns a Managed Object specified by its Unique Identifier, together with its attributes.
The Key Format Type, Key Wrap Type, Key Compression Type and Key Wrapping Specification SHALL have the same semantics as for the Get operation. If the Managed Object has been Destroyed then the key material for the specified managed object SHALL not be returned in the response.
The server SHALL copy the Unique Identifier returned by this operations into the ID Placeholder variable.
Implementation
The Export operation - contrarily to the Getoperation - allows exporting objects which have been revoked or
destroyed.
When an object is destroyed, the key material cannot be exported anymore; only the attributes are returned.
To be able to export an Object the user must have the export permission on the object or be the object owner.
Key wrapping and unwrapping on export is supported for all keys. Please check the
algorithms page
for more details, including how to invoke
CKM_RSA_AES_KEY_WRAP
using CryptographicAlgorithm::RSA + PaddingMethod::None.
For the list of supported key formats, please check the formats page.
Examples - Check Get
An export example is provided below but it is in every point similar to the Get operation save for the
name of the operation. To run Export instead of Get with he KMS CLI, pass the --allow-revoked flag on the
command line.
Please check the Get page for more examples.
Example - Symmetric Key
Exporting a symmetric key 027cced1-ff2b-4bd3-a200-db1041583bdc (go to Create to see how to create the
symmetric key).
Instead of using the UID of the key, we can use the unique tag of the key MySymmetricKey. The key must be uniquely
identified. It is possible to use multiple tags to identify a key; for instance symmetric keys automatically get a
system tag _kk. See tagging for more information on tags.
The response is in Rawformat, the default format for symmetric keys specified by KMIP 2.1; see the [formats page](.
/formats.md) for details.
Corresponding KMS CLI command:
ckms sym keys export -t "MySymmetricKey" /tmp/sym_key.json --allow-revoked
{
"tag": "Export",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "[\"MySymmetricKey\"]"
},
{
"tag": "KeyWrapType",
"type": "Enumeration",
"value": "AsRegistered"
}
]
}
{
"tag": "ExportResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "Raw"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "0B3E539510BABD291BB9FEC2A390C833B05465F33374575CE4AAFFABD5E93020"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
},
{
"tag": "CryptographicUsageMask",
"type": "Integer",
"value": 2108
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "TransparentSymmetricKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
}
]
}
]
},
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
}
]
}
]
}
]
}
Specification
This operation requests that the server returns the Managed Object specified by its Unique Identifier. Only a single object is returned.
The response contains the Unique Identifier of the object, along with the object itself, which MAY be wrapped using a wrapping key as specified in the request. The following key format capabilities SHALL be assumed by the client; restrictions apply when the client requests the server to return an object in a particular format:
-
If a client registers a key in a given format, the server SHALL be able to return the key during the Get operation in the same format that was used when the key was registered.
-
Any other format conversion MAY be supported by the server.
If Key Format Type is specified to be PKCS#12 then the response payload shall be a PKCS#12 container as specified by [RFC7292].
The Unique Identifier shall be either that of a private key or certificate to be included in the response.
The container shall be protected using the Secret Data object specified via the private key or certificate's PKCS#12 Password Link. The current certificate chain shall also be included as determined by using the private key's Public Key link to get the corresponding public key (where relevant) and then using that public key's PKCS#12 Certificate Link to get the base certificate, and then using each certificate's Certificate Link to build the certificate chain. It is an error if there is more than one valid certificate chain.
Implementation
The Get operation allows exporting Active objects only.
When an object is Destroyed or Deactivated, the Export operation must be used instead.
Key wrapping and unwrapping on export is supported for all keys. Please check the algorithms page for more details.
For the list of supported key formats, please check the formats page.
Example - A symmetric key
Exporting a symmetric key 027cced1-ff2b-4bd3-a200-db1041583bdc (go to Create to see how to create the
symmetric key).
Instead of using the UID of the key, we can use the unique tag of the key my_symmetric_key. The key must be uniquely
identified. It is possible to use multiple tags to identify a key; for instance symmetric keys automatically get a
system tag _kk. See tagging for more information on tags.
The response is in Rawformat, the default format for symmetric keys specified by KMIP 2.1; see the [formats page](.
/formats.md) for details.
Corresponding KMS CLI command:
ckms sym keys create my_symmetric_key
ckms sym keys export -t my_symmetric_key /tmp/sym_key.json
{
"tag": "Get",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "[my_symmetric_key]"
},
{
"tag": "KeyWrapType",
"type": "Enumeration",
"value": "AsRegistered"
}
]
}
{
"tag": "GetResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "Raw"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "0B3E539510BABD291BB9FEC2A390C833B05465F33374575CE4AAFFABD5E93020"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
},
{
"tag": "CryptographicUsageMask",
"type": "Integer",
"value": 2108
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "TransparentSymmetricKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "SymmetricKey"
}
]
}
]
},
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "AES"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 256
}
]
}
]
}
]
}
Example - A wrapped Covercrypt user key
Exporting a wrapped Covercrypt user key df871e79-0923-47cd-9078-bbec83287c85 (go to Create to
see how to create the Covercrypt user key) after wrapping it with symmetric key
027cced1-ff2b-4bd3-a200-db1041583bdc using RFC 5649.
Corresponding KMS CLI command:
ckms cc keys export -k df871e79-0923-47cd-9078-bbec83287c85 /tmp/sym_key.json -w 027cced1-ff2b-4bd3-a200-db1041583bdc
Please note the presence of the KeyWrappingSpecification structure in the request with the unique identifier of
the symmetric key.
The response contains a KeyWrappingData structure with a reference to the symmetric key used for wrapping.
The encoding option is TTLVEncoding as specified ion the request, which indicates that the ciphertext
contains a JSON TTLV structure with the Key Material and its Attributes. Please refer to the KMIP specification for
more details.
{
"tag": "Get",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "df871e79-0923-47cd-9078-bbec83287c85"
},
{
"tag": "KeyWrappingSpecification",
"type": "Structure",
"value": [
{
"tag": "WrappingMethod",
"type": "Enumeration",
"value": "Encrypt"
},
{
"tag": "EncryptionKeyInformation",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
}
]
},
{
"tag": "EncodingOption",
"type": "Enumeration",
"value": "TTLVEncoding"
}
]
}
]
}
{
"tag": "GetResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "df871e79-0923-47cd-9078-bbec83287c85"
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "2DCB9F6F18570EE9400372953342590B13CDAE02DC92ABDE50A873239F4EDFC64081B861B9CAC050D6AEE890CF7167AD44739974507A6D2DAB532B886B369EB00794F2ED4D80BD510556C92FF022F20D1E2E810D1466AF9B526319F8529BA9AFA34964C37BC6070BA5489970C9565785FFF29C1669251DDB6C7A189BA8D9238B2B6D717F5A4680E5458931A994DC4698D1C6E1B1D4B296CFFFA7402911933092B428F8AA9669185ACFC1ADDC7CC8026F96BFA240283F9667D03C2BC597DB1677CFBFA7CB8B88E5AC9456722477845BA6AB075F30C1DAE9BB9D95E4DA67C7E1D69E7394DC8CF6F54040B279D50C6E5C6B1FB92AAB17FD7E766C3E826603EBA9FE357199CF937AAA844B37BC8DA7C7D28E18D9C8D2A44F473D39B377BB04FD0178CE5E78385D31D19420270F7A121AEF4844977E14A5B387EB5032ABA81BFC9BEF2343C58AA1F468E4007AAAA3E7725754B1127A2F89D15DBE4F8237008B68D00F4C00862560A4A5FCB9E47C9E802A70C3AEEEAED6DE4136FFBCF31F50B5745C1975A08CC818C81655F6C5E9DAE96E7E76F5D58EB0A1FC1D9A10839E8ACB7F0327544481CEB60CACFC299C18E40D453DF9466CC9B524CDC31ABADAB2EF78E617E6571D6BE2B4F78F057F68CCB4FD732F39CC1CD6F1AFF80804CF27765A777832E614FC01D6E9967328CA7938D9BE8560B19C1A85C3C99DA43AEE7850FEC158541C968E8287142C306F9E18DD46AF5C8774E91C1786208A595DDDEBA26B28F5F06FE6AD0F2773E65082FA354A293C4924508DD0CBD469711E71F455A83929E0BD5C4A6461CB5F2ED57B7A55E3EA74E99525917FF76488CD7B1CF24515FE77FBAB4D4C0F686A921D50D643C0E7058357B2313DF8D2B376B261DE966E33BF436AAF7EEB200E1E577E0C0B3D6C3C9B3F7199202AC9D7160B15D3DFEC1F395DCCA876AD50201CC85CB07B28160D60DFB6EAF8EC9F591642B946BBD3D9FBBD41565A42383848EE0D2C47AA2715C1AE1E937795098DBF9A161A25DD2705F84261041F4395B93BA49916B6F7A1D386FF0B1C31AF06A15B96D4E43E60510C1E6D9C613E2DDC7E9B0821E99AC1FC82235AFC472FBB4B49923D139F7801DAAA73022B6BF53E0E067A7F6BDB128BB3DF47B9DFC72B1DDE87A0D67EE446FD248BBD4E9CF9983CD0E38D1430672145EF2B84F8CA1C3B04E4CD3C0405BD82523F23057F89BBDBAA04F2241AF87A0CFA76917D34F69B021BEE26BE5DD4F31D446684948A366C23696E64A3B56A9B67541AE575BF4C18933EEB3EAC634590BE9E0995E355FFB66ED1C3D284F20D0246EFD286D98EC337DA91AB9BF62FDAFC80F76D94D9F132CDF75A70F39DE697B1619011E9C7DD5BE305CA699480B276C8B62356626196F00EDBE250512A39E3750DDA8B62B329F20B339630F5BAD63A5B9203CC05170A7BD2F40929886DDEB14EF55C3ED2D7228034F8A632B1E7A7D44272A87E131AF2FE09640496A6D74E88F3D67AA17732884F3EED6C9DF4EC4D41A81F47B0124DA017D4D7AF079F79A1795541A49FB3D8A7F17CA1167FF7B4467813F02A7C97E53BAFDA269EB6D85F6086C17B60763DBD753E1FCC642CCEE072C9AB41FC433CBBEA9E3B97389DD205E05A2BA5DF147032B8C721119A831A29F474F7D9D6CF14F887CC43F5343F94CEBEDA7228BB3A6F7429A58FFF595CA055522B18C32DCB7377E953B2099116517FD32DDD1566C8C0B759C7CEBEE1B8CC3C21B7A8735D791D1F964F8C41A3B02EB9BA47537D03B6226003CDB05C0315B8B9B5D36C44F7FFC242B8783D27D6F2C014396CC88B0AA6B03C798199B1D309A1130A1DFEE0862F8619C127FA922EC83816E0A1FDF24EF7F27EEF5D92E5035D4E5A1BD9F656D1A3F384E617DA90677FFDE819CD618B9A13DA1E4FBD6AE8B61AC1CEE8A5C7D93C4BB4BB97325E75E5264CFD22B0A58BA7D55CB84DD5DADDFBEEDAC39A96D7498017DF1564BC853643764D73EFB370B6E3CB6A876678657A1499B7AFE47F92AD3B946099F7A86E2EDB731CFC7E0560A618EE56944A90BCE1E5928A3B506AD02A197EA71FCF3E290FF2DDFBECC6F79CA8405D87F65D73F3F6E39AFD8BFEA8AA35F246CE8BC85226BF3D7FD70D8C56589A48D38AF721B97FC58B0D"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "ParentLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D79557365724B6579225D"
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "cover_crypt_access_policy"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5365637572697479204C6576656C3A3A436F6E666964656E7469616C20262620284465706172746D656E743A3A46494E207C7C204465706172746D656E743A3A485229"
}
]
}
]
}
]
}
]
},
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 1832
},
{
"tag": "KeyWrappingData",
"type": "Structure",
"value": [
{
"tag": "WrappingMethod",
"type": "Enumeration",
"value": "Encrypt"
},
{
"tag": "EncryptionKeyInformation",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
}
]
},
{
"tag": "EncodingOption",
"type": "Enumeration",
"value": "TTLVEncoding"
}
]
}
]
}
]
}
]
}
Example - An EC private key in PKCS#8, linked to a certificate
Exporting in PKCS#8 an EC private key bf614d45-5a3e-49b9-95c0-5586d3c0d17b which was imported as part of a PKCS#12
container.
Corresponding KMS CLI command:
ckms ec keys export /tmp/pkey.pem -f pkcs8-pem -k bf614d45-5a3e-49b9-95c0-5586d3c0d17b
Please note:
- the presence of the
KeyFormatTypein the request set toPKCS8 - the presence of a
Linkstructure in the response, which links the private key to the certificate
{
"tag": "Get",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "bf614d45-5a3e-49b9-95c0-5586d3c0d17b"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "PKCS8"
},
{
"tag": "KeyWrapType",
"type": "Enumeration",
"value": "AsRegistered"
}
]
}
{
"tag": "GetResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "bf614d45-5a3e-49b9-95c0-5586d3c0d17b"
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "PKCS8"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "302E020100300506032B656E042204207D282BE753D7DCAF8E741BBA62C1E8A88DB99161863D89C41275358774B37090"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "ECDH"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 253
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "PKCS8"
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PKCS12CertificateLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "d2f4e937-dda9-4a86-bbe8-c866646a612f"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
}
]
}
]
},
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "ECDH"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 253
}
]
}
]
}
]
}
Example - A certificate in X509
Exporting in X509 a certificate d2f4e937-dda9-4a86-bbe8-c866646a612f which was imported as part of a PKCS#12.
Corresponding KMS CLI command:
ckms certificates export /tmp/cert.x509 -f pem -c d2f4e937-dda9-4a86-bbe8-c866646a612f
The conversion from DER to PEM is done by the CLI.
Please note:
- the presence of the
KeyFormatTypein the request set toX509 - the presence of a
Linkstructure in the response, which links the certificate to the private key - the presence of a
CertificateValuestructure in the response, which contains the X509 DER encoding of the certificate
{
"tag": "Get",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "d2f4e937-dda9-4a86-bbe8-c866646a612f"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "X509"
},
{
"tag": "KeyWrapType",
"type": "Enumeration",
"value": "AsRegistered"
}
]
}
{
"tag": "GetResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "Certificate"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "d2f4e937-dda9-4a86-bbe8-c866646a612f"
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "CertificateType",
"type": "Enumeration",
"value": "X509"
},
{
"tag": "CertificateValue",
"type": "ByteString",
"value": "308201443081F7A003020102021004802E89DDF1412B9D8341571667EC9D300506032B657030133111300F06035504030C084B6D735375624341301E170D3233303930383133353033345A170D3234303330393034353033345A30143112301006035504030C094D7920736572766572302A300506032B656E032100124EAAD397D23A8A09847739EFD27E8232846E34AB4B73BDE0D3BC3BB30E842EA360305E301D0603551D0E04160414655E04099884AF3CCA3E3B11D908BB8FD27270BC301F0603551D230418301680148AA1C25FAA8B071496FE96AA8578D4DC6175AB71300C0603551D130101FF04023000300E0603551D0F0101FF0404030203E8300506032B65700341002FDDFC5EE8D0DD0626989F25EE8CEBDC4D28CBEB5AA397D650766426FF30D820662C178622CF2AB101A509ECF11E5F7D6D603181E3C91FBAA2EC2716651D2A0F"
}
]
}
]
}
Example - A PKCS#12 container
Export a PKCS#12 container using the unique identifier of the private key. The Private Key must have a link to:
- either a certificate with a link of type
PKCS12CertificateLinkorCertificateLink - or a link to a public key with a link of type
PublicKeyLink, the public key having a link to a certificate with a link of typeCertificateLink. - for intermediate certificates to be included, the certificate must have a link to a certificate with a link of type
CertificateLinkto its issuer.
Corresponding KMS CLI command:
ckms certificates export /tmp/exported.p12 -c bf614d45-5a3e-49b9-95c0-5586d3c0d17b -f pkcs12 -p secret
Please note:
- the presence of the
KeyFormatTypein the request set toPKCS12. - the presence of a
KeyWrappingSpecificationstructure in the request with the the secret used to seal the PKCS#12 container. - the
EncodingOptionis ignored in this case.
{
"tag": "Get",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "bf614d45-5a3e-49b9-95c0-5586d3c0d17b"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "PKCS12"
},
{
"tag": "KeyWrappingSpecification",
"type": "Structure",
"value": [
{
"tag": "WrappingMethod",
"type": "Enumeration",
"value": "Encrypt"
},
{
"tag": "EncryptionKeyInformation",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "secret"
}
]
},
{
"tag": "EncodingOption",
"type": "Enumeration",
"value": "TTLVEncoding"
}
]
}
]
}
{
"tag": "GetResponse",
"type": "Structure",
"value": [
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "bf614d45-5a3e-49b9-95c0-5586d3c0d17b"
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "PKCS12"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "308204660201033082042C06092A864886F70D010701A082041D04820419308204153082036706092A864886F70D010706A0820358308203540201003082034D06092A864886F70D010701301C060A2A864886F70D010C0106300E0408A1CE7477CB52D0FB02020800808203201250CC796DD733F83D1412EA850360420552BBD1D6086F55F14694F711BC1AA4940942B651FD196A33F157EA4642E8344C241751E439C3ECF5EFEDAE4602BCF0B624874F5F402F69C0C08BB241760017279B76EA3784CFF3C5CF8F69790D84DDB1702D345F19FBED027CDE104381D4F52CDE37AD8407D36428F371E6A0295006F80651D2A4394B2C7C468A1EDD0F500E51B1A3353CD3E4AB954AF1BE23A9203CEE4FE3D712A6191DAED8F9E391273A7EA1EF9549E9E48176FED98E6B2554A4871638DA1733443817012A5F80750203FDA0E6DED6C8DA27E151682362C184C53425547A60275A3638D2DCA0726FC87C46F4DA9418064E62F14D09085860DD1D13E096E0AB05BBE5CC2162E2973EC154E86819EDE3CCA8A4140EB003543BEDE901DB2F8A5FCBB2E80FEB2B2B2B22B2B4CB4D663D07178F4E93568261759DA834108EA7D1F8BF06947799EAED802436F3C2EAEE8D3218B98B1153B4926C052992C01EB75B3BC032C1A232FACFFC472403DC86C6DD8DF22D700A38DC86EB58B246BFDE3D737F1CEC218383DDDB986657E3AF57D4AC0299ED99D8468CED2D97F14375C4A9AA438086629AA8A651A01701894CF06AA28137A68A70977995E4CF9DBAC4373D483C7E2E1D889E2BEA47E92715F8D540A5C534C43E5E953532264DA581F3DD059E8974AE072C50368F44E93F29D8A34E56DD40338CC69271B14FA7E7CF68FB9D586A26337A449F7CC5222F2F4EFE411691B30E8E25532C1BB6EB9D28EE5EDAF6E54D5C29C38D678AE158425F7959F89B06B10010D7EC1B3BF67C340FE5621D679CA48F2B1AFCF603CAB6581883A32A8733BBE738A7A1F82CBEC590BF69475A3331EB5AC2684EAB6D737E3A1DFACA734A4AC96AEA0E883F9C7B720E68016EEABDC5C88C4B3F405F46B7290CE8BA5258B92BA14122A87624E172CECCF4766066E1AFAF8EF06D1896994265A27080BF3AAB7B73638482A8EF6527B8A8245E514238C8E80A5F9750A663D5468DC5D8460D4793AF77B1D39B1D2A0099114FA8FF8E2D80B10E9F91A295CED84AE3C30C73A27D1CA90CBED4582A7ED0015BAA58DA9850202D1903086802FC5705F5BE0C4FA9F1AD11B82A340ED3DC8A835D08396C3081A706092A864886F70D010701A08199048196308193308190060B2A864886F70D010C0A0102A05A3058301C060A2A864886F70D010C0103300E04089971B59CB1424F9502020800043818AC3DDA45F299AC2D5441F538E49BD14E2AF1DF51A28DC926616D4E16C3100C2B2D9111219688C5BD81F70DAB647B0C8A6F6844150F05033125302306092A864886F70D0109153116041460854FAEF5E61527293E6551F170EF7145957FC430313021300906052B0E03021A0500041459585C94B586A45D6D75323D09976AC88DBEE3CA0408B40773C6DA0DF8BD02020800"
}
]
}
]
}
]
}
]
}
Specification
This operation requests the server to perform a hash operation on provided data, using a specified Hashing Algorithm. The operation can be performed in a single request or as a series of requests for long data streams or by-parts cryptographic operations.
The response contains the hashed data.
When a stream or by-parts operation is requested:
- The server SHALL create a unique identifier, called correlation value if Init Indicator is True.
- The server SHALL expect one or more requests with the same correlation value if Init Indicator is True.
- The server SHALL return the Correlation Value in the response if Init Indicator is True.
- The server SHALL use the Correlation Value for subsequent Hash requests.
- The server SHALL close the stream or by-parts operation when Final Indicator is True.
Implementation
The Eviden KMS server supports the following hashing algorithms:
- SHA256
- SHA384
- SHA512
For the complete list of supported hashing algorithms, please check the algorithms page.
Example - Simple hash
Hashing data with SHA256.
Corresponding KMS CLI command:
ckms hash --algorithm sha3-512 --data 0011223344556677889900
{
"tag": "Hash",
"type": "Structure",
"value": [
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
},
{
"tag": "InitIndicator",
"type": "Boolean",
"value": false
},
{
"tag": "FinalIndicator",
"type": "Boolean",
"value": false
}
]
}
{
"tag": "HashResponse",
"type": "Structure",
"value": [
{
"tag": "Data",
"type": "ByteString",
"value": "F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA"
}
]
}
Example - Stream hash
Hashing a large file in multiple parts using SHA256.
Corresponding KMS CLI command:
# First part with init indicator
ckms hash --algorithm sha3-512 --data 0011223344556677889900 -i
# Middle part using correlation value
ckms hash --algorithm sha3-512 --correlation-value F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA --data 0011223344556677889900
# Final part with final indicator
ckms hash --algorithm sha3-512 --correlation-value 51A2F7FCA8DECFC106031BE935F28F6EEE7E3850BCDB9D9B41B0F623146D7F51E399FC8F76A8B14EB71463DB0F6D421EF431E33F8CE1897FF988237C890C808F -f --data 0011223344556677889900
{
"tag": "Hash",
"type": "Structure",
"value": [
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
},
{
"tag": "InitIndicator",
"type": "Boolean",
"value": true
},
{
"tag": "FinalIndicator",
"type": "Boolean",
"value": false
}
]
}
{
"tag": "HashResponse",
"type": "Structure",
"value": [
{
"tag": "CorrelationValue",
"type": "ByteString",
"value": "F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA"
}
]
}
{
"tag": "Hash",
"type": "Structure",
"value": [
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
},
{
"tag": "CorrelationValue",
"type": "ByteString",
"value": "F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA"
},
{
"tag": "InitIndicator",
"type": "Boolean",
"value": false
},
{
"tag": "FinalIndicator",
"type": "Boolean",
"value": false
}
]
}
{
"tag": "Hash",
"type": "Structure",
"value": [
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
},
{
"tag": "CorrelationValue",
"type": "ByteString",
"value": "51A2F7FCA8DECFC106031BE935F28F6EEE7E3850BCDB9D9B41B0F623146D7F51E399FC8F76A8B14EB71463DB0F6D421EF431E33F8CE1897FF988237C890C808F"
},
{
"tag": "InitIndicator",
"type": "Boolean",
"value": false
},
{
"tag": "FinalIndicator",
"type": "Boolean",
"value": true
}
]
}
{
"tag": "HashResponse",
"type": "Structure",
"value": [
{
"tag": "Data",
"type": "ByteString",
"value": "511BDAFDB2D059BD94FC72B8301ABF01DB9E02127420AED072B891A83952B88063DF3470225ACC6D46AD503E5E86B16BAEB581F218A148472120A9B541E1AF5D"
}
]
}
Specification
This operation requests the server to Import a Managed Object specified by its Unique Identifier. The request specifies the object being imported and all the attributes to be assigned to the object.
The attribute rules for each attribute for "Initially set by" and "When implicitly set" SHALL NOT be enforced as all attributes MUST be set to the supplied values rather than any server-generated values.
The response contains the Unique Identifier provided in the request or assigned by the server. The server SHALL copy the Unique Identifier returned by this operation into the ID Placeholder variable.
Implementation
Key unwrapping on import is supported for all keys. Please check the algorithms page for more details.
For the list of supported key formats, please check the formats page.
Example - A NIST P-256 EC private key in SEC1 format
Importing a NIST P-256 EC Private Key in SEC1 format.
Corresponding KMS CLI command:
ckms ec keys import cra../kms_clients/test_data/certificates/openssl/prime256v1-private-key.pem --key-format pem
The conversion from PEM to DER is done by the KMS CLI.
In the JSON TTLV requests, please note:
- the empty
UniqueIdentifierwhich requests the server to generate a newUniqueIdentifierfor the imported key. - the empty tags
[]in hex - the
KeyFormatTypeset toECPrivateKeywhich indicates to the server that the key is in SEC1 format.
{
"tag": "Import",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": ""
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "ReplaceExisting",
"type": "Boolean",
"value": false
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B5D"
}
]
}
]
}
]
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "ECPrivateKey"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "307702010104204CC0D4B807CED6BB2CCFE44D467D6A2A5D706B0E11E9352CF5CA8D3998790B83A00A06082A8648CE3D030107A14403420004A8D465338FB81879378BC9730A07A2BA455009E1B4606A58136C4A73C40B4BE7DDFE9D7959BC16E6BF8D6F2EF4BA4DB43A3DA29FA1A9D2ECA5AD30F129A0A5A4"
}
]
}
]
}
]
}
]
}
{
"tag": "ImportResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "927adccb-f59a-4cc9-a9e3-1eeb958c601f"
}
]
}
Example - A RSA 2048 private key in PKCS#8 format
Importing a RSA 2048 key in PKCS#8 format with tags MyRSAKeyand 2048.
Corresponding KMS CLI command:
ckms ec keys import cra../kms_clients/test_data/certificates/openssl/rsa-2048-private-key.pem --key-format pem --tag "MyRSAKey" --tag "2048"
The conversion from PEM to DER is done by the KMS CLI.
In the JSON TTLV Request, please note:
- the empty
UniqueIdentifierwhich requests the server to generate a newUniqueIdentifierfor the imported key. - the tags
["MyRSAKey","2048"]in hex - the
KeyFormatTypeset toPKCS8which indicates to the server that the key is in PKCS#8 format. - the
KeyMaterialwhich are the hex-encoded DER bytes of the PKCS#8 structure.
{
"tag": "Import",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": ""
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "ReplaceExisting",
"type": "Boolean",
"value": false
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D795253414B6579222C2232303438225D"
}
]
}
]
}
]
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "PKCS8"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "308204BD020100300D06092A864886F70D0101010500048204A7308204A30201000282010100B466EEF95ECB9CEC2F9AFA71F280C3F7671BD18C21819E08521D890CADF4D52EB02B33D2CEC25B45124F4977FC5EB43918FD0717697EBF09B0AD3143915DD233A248DBA42550ECE7530AA98C318F425915E1300600B873B24EB33715A93A96F7AC4198C1EFBD111B7D0D7100FCEB90A3B2549F4D9CDF1C08E0E14098ED07F5442FFFA9775F488778CE967AFB662FBC8FE9E353E778AA49E1976F818CC8C597D9DBFAAD219DA1B5B36037B3146DBB031AA43552B18D1B03AD789BE60B19FCD685ED774BC11E9E2C8D076CEBAB5BD21FB1EB80EDCCE55C47A8BB607A6B3311E9CFBC76E162C4F98FD30E87D39ED0A8BC07CA46C2653A2B04DD47998CDDD2744E5302030100010282010018572D163B6A98952B852B1675C456EC8A1E70430A804D1CCD4B8BE2C893D8B1B0765BCB2D377F0E0E3EE1684D864FA5C68FD94598E7CF89D4AB4192DEC9BC635819A17CFFC5EFF8F434E39475596177D8A26612E14501E344881CBE10F3C54BCC939B334B90047F637B8D4C3753E75396EBA104DD4E231FB58BDEE5E351680F9D5E8F0F555BDF09CECA4E83AE6CCDC0F6E8E07AA0A2EC96ABA1B57F53667B05957B0BE4CB9564CFEC672981CB1BB57BF4785563B87A6AC3354C68B83CD73C4896DB526A5D037224EBEAECDF01EC6F94B637FA2F3128EB1588294942601ECE5B0AEE98E222BD8779ED931734FE27F0C4ADACB586CCFE649FAA0273F333CC43CD02818100EF9732DA98D3AB9F561B602F74AAEFFEBAA4F5D8A3AC93BF560DC097AC853FCD246433D30FC294D81F6FF05B2DFD286155DAF4CFB3666DDA580A992DAE649DAA6B407FD240F07E87AF6DEEA93525EED90799888B488980470F70F749AC8C440B776D0CAF327706638AD46923D14FD5E5D25CDA0DE14FA9E5869F71104D6B9E7502818100C0C1F7B91012BB6794FE901039F0B93C08DFA0D1AB6308A444B34304EBAD516EB76CBE976551F38DA4B78CF67675882A4293765BDAA824CF7DF9912BB77D9CC986A5692CF06A520C0F00148110692EF25814420FB496C8FD60C1402D487980D457FB9B54004D58F19ACDA3317734EA39CFB07DE3446200E283AB6F68B82230A702818020E24CBD8A0A4B5CF4318FB313BD3E7164E6AD438DBB6B0FF0DCB4595CF970F7540E58BA984829ABBC2CDDFD75C3705E63AD48BA9531F2D3EC0F90549FC1F98DE16899E29EBD2370B6184D9075D5FE0155B4B1F40401B3548D7F00C1E0E7E392FB5241526E87BD9DBDF94770FE128A1620185469614A50D44AF4E94CC68385DD028181008129B8A06697D6C21B01D5713A12075DA6288BAFD3A361E8092D01ECAB2C11541A4F210B7BD645589596753BB5B71E0E0B5C9AC4042A05B890168A637BEA0D04B157E7B938445644444CEE706999C1DE9C8CBE939D94288C38A86623B1DBD12AF8E5DD7895573F116E84FB24AB5766D8644644A4E46EB35F1591EBEE84EC4C2302818042F72AC26114C103F011407A8189128E3C2A2CC59CEB559DF3DA198EA1D6A0023E98B7FDCBFEF61D82AC6176981CBD4B4B239DF39189DC15B246DE13B879AC82490C065BA3A007E5413F27CD998546BE17F30AD6A40E4A891CA84CD9D006239BB47E06024DA1DE35B791A79A57CBC5C501B16B1511138DCEB97F111E548F076D"
}
]
}
]
}
]
}
]
}
{
"tag": "ImportResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "8623605d-625b-4b4f-99c9-a2802e415609"
}
]
}
Example - Covercrypt user key with unwrapping on import
Importing a wrapped Covercrypt user key after unwrapping it with symmetric key
027cced1-ff2b-4bd3-a200-db1041583bdc using RFC 5649.
Corresponding KMS CLI command:
ckms cc keys import /tmp/sym_key.json -u
Note: the -u flag is used to indicate that the key should be unwrapped on import; the JSON file (obtained using the
export command) contains the wrapped key details.
In the JSON TTLV request, please note:
- the
KeyWrapTypeset toNotWrappedwhich indicates to the server that it should look into theKeyWrappingDatastructure to see how to unwrap the key. - the empty
UniqueIdentifierwhich requests the server to generate a newUniqueIdentifierfor the imported key.
{
"tag": "Import",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": ""
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "ReplaceExisting",
"type": "Boolean",
"value": false
},
{
"tag": "KeyWrapType",
"type": "Enumeration",
"value": "NotWrapped"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "ParentLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B5D"
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "cover_crypt_access_policy"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5365637572697479204C6576656C3A3A436F6E666964656E7469616C20262620284465706172746D656E743A3A46494E207C7C204465706172746D656E743A3A485229"
}
]
}
]
}
]
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "2DCB9F6F18570EE9400372953342590B13CDAE02DC92ABDE50A873239F4EDFC64081B861B9CAC050D6AEE890CF7167AD44739974507A6D2DAB532B886B369EB00794F2ED4D80BD510556C92FF022F20D1E2E810D1466AF9B526319F8529BA9AFA34964C37BC6070BA5489970C9565785FFF29C1669251DDB6C7A189BA8D9238B2B6D717F5A4680E5458931A994DC4698D1C6E1B1D4B296CFFFA7402911933092B428F8AA9669185ACFC1ADDC7CC8026F96BFA240283F9667D03C2BC597DB1677CFBFA7CB8B88E5AC9456722477845BA6AB075F30C1DAE9BB9D95E4DA67C7E1D69E7394DC8CF6F54040B279D50C6E5C6B1FB92AAB17FD7E766C3E826603EBA9FE357199CF937AAA844B37BC8DA7C7D28E18D9C8D2A44F473D39B377BB04FD0178CE5E78385D31D19420270F7A121AEF4844977E14A5B387EB5032ABA81BFC9BEF2343C58AA1F468E4007AAAA3E7725754B1127A2F89D15DBE4F8237008B68D00F4C00862560A4A5FCB9E47C9E802A70C3AEEEAED6DE4136FFBCF31F50B5745C1975A08CC818C81655F6C5E9DAE96E7E76F5D58EB0A1FC1D9A10839E8ACB7F0327544481CEB60CACFC299C18E40D453DF9466CC9B524CDC31ABADAB2EF78E617E6571D6BE2B4F78F057F68CCB4FD732F39CC1CD6F1AFF80804CF27765A777832E614FC01D6E9967328CA7938D9BE8560B19C1A85C3C99DA43AEE7850FEC158541C968E8287142C306F9E18DD46AF5C8774E91C1786208A595DDDEBA26B28F5F06FE6AD0F2773E65082FA354A293C4924508DD0CBD469711E71F455A83929E0BD5C4A6461CB5F2ED57B7A55E3EA74E99525917FF76488CD7B1CF24515FE77FBAB4D4C0F686A921D50D643C0E7058357B2313DF8D2B376B261DE966E33BF436AAF7EEB200E1E577E0C0B3D6C3C9B3F7199202AC9D7160B15D3DFEC1F395DCCA876AD50201CC85CB07B28160D60DFB6EAF8EC9F591642B946BBD3D9FBBD41565A42383848EE0D2C47AA2715C1AE1E937795098DBF9A161A25DD2705F84261041F4395B93BA49916B6F7A1D386FF0B1C31AF06A15B96D4E43E60510C1E6D9C613E2DDC7E9B0821E99AC1FC82235AFC472FBB4B49923D139F7801DAAA73022B6BF53E0E067A7F6BDB128BB3DF47B9DFC72B1DDE87A0D67EE446FD248BBD4E9CF9983CD0E38D1430672145EF2B84F8CA1C3B04E4CD3C0405BD82523F23057F89BBDBAA04F2241AF87A0CFA76917D34F69B021BEE26BE5DD4F31D446684948A366C23696E64A3B56A9B67541AE575BF4C18933EEB3EAC634590BE9E0995E355FFB66ED1C3D284F20D0246EFD286D98EC337DA91AB9BF62FDAFC80F76D94D9F132CDF75A70F39DE697B1619011E9C7DD5BE305CA699480B276C8B62356626196F00EDBE250512A39E3750DDA8B62B329F20B339630F5BAD63A5B9203CC05170A7BD2F40929886DDEB14EF55C3ED2D7228034F8A632B1E7A7D44272A87E131AF2FE09640496A6D74E88F3D67AA17732884F3EED6C9DF4EC4D41A81F47B0124DA017D4D7AF079F79A1795541A49FB3D8A7F17CA1167FF7B4467813F02A7C97E53BAFDA269EB6D85F6086C17B60763DBD753E1FCC642CCEE072C9AB41FC433CBBEA9E3B97389DD205E05A2BA5DF147032B8C721119A831A29F474F7D9D6CF14F887CC43F5343F94CEBEDA7228BB3A6F7429A58FFF595CA055522B18C32DCB7377E953B2099116517FD32DDD1566C8C0B759C7CEBEE1B8CC3C21B7A8735D791D1F964F8C41A3B02EB9BA47537D03B6226003CDB05C0315B8B9B5D36C44F7FFC242B8783D27D6F2C014396CC88B0AA6B03C798199B1D309A1130A1DFEE0862F8619C127FA922EC83816E0A1FDF24EF7F27EEF5D92E5035D4E5A1BD9F656D1A3F384E617DA90677FFDE819CD618B9A13DA1E4FBD6AE8B61AC1CEE8A5C7D93C4BB4BB97325E75E5264CFD22B0A58BA7D55CB84DD5DADDFBEEDAC39A96D7498017DF1564BC853643764D73EFB370B6E3CB6A876678657A1499B7AFE47F92AD3B946099F7A86E2EDB731CFC7E0560A618EE56944A90BCE1E5928A3B506AD02A197EA71FCF3E290FF2DDFBECC6F79CA8405D87F65D73F3F6E39AFD8BFEA8AA35F246CE8BC85226BF3D7FD70D8C56589A48D38AF721B97FC58B0D"
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "ParentLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9"
}
]
}
]
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D79557365724B6579225D"
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "cover_crypt_access_policy"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5365637572697479204C6576656C3A3A436F6E666964656E7469616C20262620284465706172746D656E743A3A46494E207C7C204465706172746D656E743A3A485229"
}
]
}
]
}
]
}
]
},
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "CryptographicLength",
"type": "Integer",
"value": 1832
},
{
"tag": "KeyWrappingData",
"type": "Structure",
"value": [
{
"tag": "WrappingMethod",
"type": "Enumeration",
"value": "Encrypt"
},
{
"tag": "EncryptionKeyInformation",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
}
]
},
{
"tag": "EncodingOption",
"type": "Enumeration",
"value": "TTLVEncoding"
}
]
}
]
}
]
}
]
}
{
"tag": "ImportResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "8bfcbfba-77d9-4850-874a-b7c7511b03ae"
}
]
}
Example - A PKCS#12 container
Importing a PKCS#12 container containing an EC private key, a certificate and an intermediate certificate.
Corresponding KMS CLI command:
ckms certificates import cra../kms_clients/test_data/certificates/p12/output.p12 --tag "MyPKCS12" -f pkcs12 -p secret
In the request, please note:
- the empty
UniqueIdentifierwhich requests the server to generate a newUniqueIdentifierfor the imported private key. The server will also generate unique identifiers for the certificate and the intermediate certificate but the latter are not returned in the response. To recover these identifiers, use theGet Attributesoperation on the private key and then on the certificate. - the tag
["MyPKCS12"]in hex. - the
KeyFormatTypeset toPKCS12which indicates to the server that the key is in PKCS#12 format. - the
KeyMaterialwhich are the hex-encoded DER bytes of the PKCS#12 structure. - the
LinkTypeset toPKCS12PasswordLinkwhich indicates to the server that the password is in theLinkedObjectIdentifierfield.
{
"tag": "Import",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": ""
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "ReplaceExisting",
"type": "Boolean",
"value": false
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "Link",
"type": "Structure",
"value": [
{
"tag": "LinkType",
"type": "Enumeration",
"value": "PKCS12PasswordLink"
},
{
"tag": "LinkedObjectIdentifier",
"type": "TextString",
"value": "secret"
}
]
}
]
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D79504B43533132225D"
}
]
}
]
}
]
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "KeyBlock",
"type": "Structure",
"value": [
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "PKCS12"
},
{
"tag": "KeyValue",
"type": "Structure",
"value": [
{
"tag": "KeyMaterial",
"type": "ByteString",
"value": "308204660201033082042C06092A864886F70D010701A082041D04820419308204153082036706092A864886F70D010706A0820358308203540201003082034D06092A864886F70D010701301C060A2A864886F70D010C0106300E04082A727ACADC7F30FE0202080080820320C807EF330DE2F0D9B5E4B47E457DBCAE52DB41BB85E627645E9C60B51FB4FD148D2DC1C262F64212DFFB07ED5D741E8CD4AED9F684AA20A1AA8CBA372437A5183967E0EA69F7417AE5AF6B18D45864A6508B95DA6302F3892A4FB68BB29580DCC70EE91AB124D029E029E60C04CA8E1037D741E865C7968AD77BB350CE5D91F7482410E8AB3579E3C3D12530B4F402A010BB10E4C33D50ADA3FE2D8105AF8B489D5F446C976F913C48F7232A3448D79B8E6BCE2B2AE72369713017077F6732CCE794A1EFD46F59C3CB5F03978B7DF613FA2B7E9C872967C92F059A857BA935C8A235235A29E65789ADB84B7F907F2B01B11E1EEF69967A187831C6DCA81C3B4140BC20421BCAA0114FD6F2692FDDBD8569D1DE14B6D1A58C85D15F2C9FF7C1A00FE77B10D1278ED6E9AF358E7D169724A0420D4D93ACBB531AD58EA95E65A31F95063BB1C6ED080D16EA85F0E041215BF5FC3FA7C301C8CFCC73BADF46DE1E7AD7AA599ECFCE60D12474A93CBB8E869A65822466DBA2E892617C7D1626EEEED90586B70C9354DF4F5451E4E14BE38D4E7893D7F118255E9F9CBDCF290E6AEA97EBA4599587FC9BD652F346E47A697FD7F497ABB7EE1B1D53A5A10ADD99AC3F635CBE440B8D34C20FF6CEB7D8F1FF4FF4A8F0BF3158B901A42631BFC8C11E0E607344BEE46BAAFAB049FA9AD3F8752AFF90ED26102DE1D905FD389E530F34534FD206B691A82C4E1B6BD180F2F2AE0C0FF7FC943B608A247EC5C49FAB7419222C17638AEA5B5DC225CD898CC6EDD7B98E6FF73CFE9C94795B7BAE7F53DE1BC0FA2C875F75D056B01A341358283294FBE6F5E76B0E03BDC7E497F69E31FC91895940CB654E5A0F669F58C820A2486BC35FA0BC17AF93959E9CD4CAAA0E1141E7E7A12B80F409D2B8B2E36B0E6637189A4180CE6E135702C4C6AB16FB96228FFE58AC92842845FA8A73B48571FFCCC3F7C513B94B72E69C115AC22D7891EE1A5518032C4661654486DC0F2808CEC195E80A0BA6501F0C6E1A454C5A6CD17137F10226EEB9182D7B848AAE0C5FF19FC5ED8EF1E19B45ECA1CAA45BDC7B913BEBB38D4F3B35BE8F5A70A9F58DFEEEBB68BDF83844DE4FE00CDA4745EF2194FF417D943081A706092A864886F70D010701A08199048196308193308190060B2A864886F70D010C0A0102A05A3058301C060A2A864886F70D010C0103300E04086CA064C6D55C2211020208000438FF5E786E0DB3C6D85C358321EF8E5BB0E8A057ACFC33E52281897F152239736B1F2DB061D712E8A83747A767C168737A515EFE1BE7EDAE3E3125302306092A864886F70D0109153116041460854FAEF5E61527293E6551F170EF7145957FC430313021300906052B0E03021A050004149CF1C7AF502B81AB981D5786E4800099B9D37D960408B970C0A9A2BDB46102020800"
}
]
}
]
}
]
}
]
}
{
"tag": "ImportResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "bf614d45-5a3e-49b9-95c0-5586d3c0d17b"
}
]
}
Example - A X509 Certificate
Importing a X509 certificate. The certificate must be imported an X509, DER encoded.
Corresponding KMS CLI command:
ckms certificates import --tag "MyImportedCert" cra../kms_clients/test_data/certificates/ca.crt -f pem
The conversion from PEM to DER is done by the CLI.
In the JSON TTLV request, please note:
- the empty
UniqueIdentifierwhich requests the server to generate a newUniqueIdentifierfor the imported certificate. - the tag
["MyImportedCert"]in hex. - the
ObjectTypeset toCertificatewhich indicates to the server that the key is in X509 format.
{
"tag": "Import",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": ""
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "Certificate"
},
{
"tag": "ReplaceExisting",
"type": "Boolean",
"value": false
},
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "5B224D79496D706F7274656443657274225D"
}
]
}
]
}
]
},
{
"tag": "Object",
"type": "Structure",
"value": [
{
"tag": "CertificateType",
"type": "Enumeration",
"value": "X509"
},
{
"tag": "CertificateValue",
"type": "ByteString",
"value": "3082033030820218020900C03CBFDC0BD87789300D06092A864886F70D01010B0500305A310B3009060355040613024652310C300A06035504080C03496446310E300C06035504070C0550617269733111300F060355040A0C0841636D6554657374311A301806035504030C1141636D65205465737420526F6F74204341301E170D3233303531393135323934355A170D3333303531363135323934355A305A310B3009060355040613024652310C300A06035504080C03496446310E300C06035504070C0550617269733111300F060355040A0C0841636D6554657374311A301806035504030C1141636D65205465737420526F6F7420434130820122300D06092A864886F70D01010105000382010F003082010A0282010100D61FF874D90172D96968F8DEA453A9D2ACD29886EAC934A18ED1172136FFE284EA702B14FA3BD2900782BCE489A6CF2FC8063F1C8BC13C52F92A3B72B44A343786B1A1DC7A3C49CA1EB24AAFF809F5AE3BB64120553B9B40E2E104966C9C8C0CF2DEBDA167FA804BDB1FBC66CDA82052F9918771FDE318D74E4894D51B808A06A10330C3E985EC2B0067C60F955AD74D64FD4667ABA76D9DC17F681B36391698BF2A3303665C19E2C20A9CADD174A49FD236E89E7541F3AACDC8453ECE094D1C886761A39CBBF809F5F27396E1C9CF431280C07670E87A3BCC9ED6C38037F53E5E006FE2D952D48D9B57D765061A5F8C2CA30CCE394DD2ED88EB6856623239190203010001300D06092A864886F70D01010B05000382010100C48C6AC67FD80062816E065637B64B17D8821299A8718CF04E7D3998C761E72C3030F27DD3C955754BFE25F3D750D15C6ABFFC887FD63B27A1C345B8F9C78BA886196866C49180C3BA37BF20D918B0EAD6051C1AEAB3C98798C43580AA10E7909F7F7F122E9349CC74FE6EFCF947C761945C3BABF68973773CC7B36FBF346D4D4286BB88BB45FA5388870F58BD192F6ED6B8541C269C7F4D77D62DE860E981CDB6D5E99579164C048C80898BF6B53E731AB97997FF48DA5FC8BB6357574CDB58BE6922ECA9CD644E7442177B66032665D186A9F6027ECF6295235922EF045285D9118182E12D608EAA21E5879B08B3BCA894D10E947625058B90796FC7FCDD57"
}
]
}
]
}
{
"tag": "ImportResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "fc0a018d-5581-44e5-baae-052c2ac98757"
}
]
}
Specification
This operation requests that the server search for one or more Managed Objects, depending on the attributes specified in the request. All attributes are allowed to be used. The request MAY contain a Maximum Items field, which specifies the maximum number of objects to be returned. If the Maximum Items field is omitted, then the server MAY return all objects matched or MAY impose an internal maximum limit due to resource limitations.
The request MAY contain an Offset Items field, which specifies the number of objects to skip that satisfy the identification criteria specified in the request. An Offset Items field of 0 is the same as omitting the Offset Items field. If both Offset Items and Maximum Items are specified in the request, the server skips Offset Items objects and returns up to Maximum Items objects.
If more than one object satisfies the identification criteria specified in the request, then the response MAY contain Unique Identifiers for multiple Managed Objects. Responses containing Unique Identifiers for multiple objects SHALL be returned in descending order of object creation (most recently created object first). Returned objects SHALL match all of the attributes in the request. If no objects match, then an empty response payload is returned. If no attribute is specified in the request, any object SHALL be deemed to match the Locate request. The response MAY include Located Items which is the count of all objects that satisfy the identification criteria.
The server returns a list of Unique Identifiers of the found objects, which then MAY be retrieved using the Get operation. If the objects are archived, then the Recover and Get operations are REQUIRED to be used to obtain those objects. If a single Unique Identifier is returned to the client, then the server SHALL copy the Unique Identifier returned by this operation into the ID Placeholder variable. If the Locate operation matches more than one object, and the Maximum Items value is omitted in the request, or is set to a value larger than one, then the server SHALL empty the ID Placeholder, causing any subsequent operations that are batched with the Locate, and which do not specify a Unique Identifier explicitly, to fail. This ensures that these batched operations SHALL proceed only if a single object is returned by Locate.
The Date attributes in the Locate request (e.g., Initial Date, Activation Date, etc.) are used to specify a time or a time range for the search. If a single instance of a given Date attribute is used in the request (e.g., the Activation Date), then objects with the same Date attribute are considered to be matching candidate objects. If two instances of the same Date attribute are used (i.e., with two different values specifying a range), then objects for which the Date attribute is inside or at a limit of the range are considered to be matching candidate objects. If a Date attribute is set to its largest possible value, then it is equivalent to an undefined attribute.
When the Cryptographic Usage Mask attribute is specified in the request, candidate objects are compared against this field via an operation that consists of a logical AND of the requested mask with the mask in the candidate object, and then a comparison of the resulting value with the requested mask. For example, if the request contains a mask value of 10001100010000, and a candidate object mask contains 10000100010000, then the logical AND of the two masks is 10000100010000, which is compared against the mask value in the request (10001100010000) and the match fails. This means that a matching candidate object has all of the bits set in its mask that are set in the requested mask, but MAY have additional bits set.
When the Usage Limits attribute is specified in the request, matching candidate objects SHALL have a Usage Limits Count and Usage Limits Total equal to or larger than the values specified in the request.
When an attribute that is defined as a structure is specified, all of the structure fields are not REQUIRED to be specified. For instance, for the Link attribute, if the Linked Object Identifier value is specified without the Link Type value, then matching candidate objects have the Linked Object Identifier as specified, irrespective of their Link Type.
When the Object Group attribute and the Object Group Member flag are specified in the request, and the value specified
for Object Group Member is Group Member Fresh, matching candidate objects SHALL be fresh objects from the object
group. If there are no more fresh objects in the group, the server MAY choose to generate a new object on-the-fly, based
on server policy. If the value specified for Object Group Member is Group Member Default, the server locates the
default object as defined by server policy.
The Storage Status Mask field is used to indicate whether on-line objects (not archived or destroyed), archived objects, destroyed objects or any combination of the above are to be searched.The server SHALL NOT return unique identifiers for objects that are destroyed unless the Storage Status Mask field includes the Destroyed Storage indicator. The server SHALL NOT return unique identifiers for objects that are archived unless the Storage Status Mask field includes the Archived Storage indicator.
Implementation
Locate allows finding objects:
- by their tags (see tagging)
- by their
Cryptographic Algorithm. Some supported values are:AES,RSA,ECDSA,ECDH,EC,ChaCha20,Poly1305,ChaCha20Poly1305,Ed25519,Ed448,CoverCrypt - by their
Key Format Type. Some supported values are:Raw,Opaque,PKCS1,PKCS8,X509,ECPrivateKey,TransparentSymmetricKey,TransparentRSAPrivateKey,TransparentRSAPublicKey,TransparentECPrivateKey,TransparentECPublicKey,PKCS12,CoverCryptSecretKey,CoverCryptPublicKey - by their links to other objects:
- a public key (
Public Key Link) - a private key (
Private Key Link) - a certificate (
Certificate Link)
- a public key (
- for certificates:
- by subject common name
- by certificate spki
Example - Symmetric Keys using the _kk tag
All symmetric keys are tagged with the system tag _kk.
Multiple tags can be used locate objects; a JSON array of tags is used to specify multiple tags which is then
serialized to hex.
{
"tag": "Locate",
"type": "Structure",
"value": [
{
"tag": "Attributes",
"type": "Structure",
"value": [
{
"tag": "Attribute",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "tag"
},
{
"tag": "AttributeValue",
"type": "TextString",
"value": "[\"_kk\"]"
}
]
}
]
}
]
}
{
"tag": "LocateResponse",
"type": "Structure",
"value": [
{
"tag": "LocatedItems",
"type": "Integer",
"value": 8
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "1a35b3be-1a1a-4798-a3aa-d9fc67298461"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "5dc81bb2-648f-485f-b804-c6ea45467056"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "6ce69a21-5b4b-470a-84e7-0e1385947527"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "ad9ba3be-93c7-4fac-a271-ef186fd645ce"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "bac520f6-461f-40e5-b8f2-7927d8ae310b"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "da5844b6-4d29-46b8-a657-9dfd449f8560"
},
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "ebddca55-6027-4c86-ac1f-6b38dcfd6ead"
}
]
}
Specification
This operation requests the server to perform a Message Authentication Code (MAC) operation on provided data using a specified MAC key and algorithm. The operation can be performed in a single request or as a series of requests for long data streams or by-parts cryptographic operations.
The response contains the MAC value or correlation value for streamed operations.
When a stream or by-parts operation is requested:
- The server SHALL create a unique identifier, called correlation value if Init Indicator is True.
- The server SHALL expect one or more requests with the same correlation value if Init Indicator is True.
- The server SHALL return the Correlation Value in the response if Init Indicator is True.
- The server SHALL use the Correlation Value for subsequent MAC requests.
- The server SHALL close the stream or by-parts operation when Final Indicator is True.
Implementation
The Eviden KMS server supports the following MAC algorithms:
- HMAC-SHA-1 (NIST SP 800-131A Rev. 2 — Acceptable)
- HMAC-SHA-224 (NIST SP 800-131A Rev. 2 — Acceptable)
- HMAC-SHA-256
- HMAC-SHA-384
- HMAC-SHA-512
For the complete list of supported MAC algorithms, please check the algorithms page.
Example - Simple MAC
Computing MAC with SHA3-512 using a MAC key.
Corresponding KMS CLI command:
ckms mac --mac-key-id 027cced1-ff2b-4bd3-a200-db1041583bdc --algorithm sha3-512 --data 0011223344556677889900
{
"tag": "Mac",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
}
]
}
{
"tag": "MacResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "Data",
"type": "ByteString",
"value": "F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA"
}
]
}
Example - Stream MAC
Computing MAC for a large file in multiple parts using SHA3-512.
Corresponding KMS CLI commands:
# First part with init indicator
ckms mac --mac-key-id 027cced1-ff2b-4bd3-a200-db1041583bdc --algorithm sha3-512 --data 0011223344556677889900 -i
# Middle part using correlation value
ckms mac --mac-key-id 027cced1-ff2b-4bd3-a200-db1041583bdc --algorithm sha3-512 --correlation-value F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA --data 0011223344556677889900
# Final part with final indicator
ckms mac --mac-key-id 027cced1-ff2b-4bd3-a200-db1041583bdc --algorithm sha3-512 --correlation-value 51A2F7FCA8DECFC106031BE935F28F6EEE7E3850BCDB9D9B41B0F623146D7F51E399FC8F76A8B14EB71463DB0F6D421EF431E33F8CE1897FF988237C890C808F -f --data 0011223344556677889900
{
"tag": "Mac",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
},
{
"tag": "InitIndicator",
"type": "Boolean",
"value": true
}
]
}
{
"tag": "MacResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "CorrelationValue",
"type": "ByteString",
"value": "F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA"
}
]
}
{
"tag": "Mac",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
},
{
"tag": "CorrelationValue",
"type": "ByteString",
"value": "F91DDB96D12CF8FAB0AA72224836D3F5F659A6634E3508A7C31DBC3727D2030254C57AD90AA5FB7F27FB3AAFABEAEB1204E4AF62BA2DE44E33E761B2C39DBACA"
}
]
}
{
"tag": "MacResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "CorrelationValue",
"type": "ByteString",
"value": "51A2F7FCA8DECFC106031BE935F28F6EEE7E3850BCDB9D9B41B0F623146D7F51E399FC8F76A8B14EB71463DB0F6D421EF431E33F8CE1897FF988237C890C808F"
}
]
}
{
"tag": "Mac",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "HashingAlgorithm",
"type": "Enumeration",
"value": "SHA3512"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "0011223344556677889900"
},
{
"tag": "CorrelationValue",
"type": "ByteString",
"value": "51A2F7FCA8DECFC106031BE935F28F6EEE7E3850BCDB9D9B41B0F623146D7F51E399FC8F76A8B14EB71463DB0F6D421EF431E33F8CE1897FF988237C890C808F"
},
{
"tag": "FinalIndicator",
"type": "Boolean",
"value": true
}
]
}
{
"tag": "MacResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "027cced1-ff2b-4bd3-a200-db1041583bdc"
},
{
"tag": "Data",
"type": "ByteString",
"value": "511BDAFDB2D059BD94FC72B8301ABF01DB9E02127420AED072B891A83952B88063DF3470225ACC6D46AD503E5E86B16BAEB581F218A148472120A9B541E1AF5D"
}
]
}
Specification
This request is used to generate a replacement key for an existing symmetric key. It is analogous to the Create operation, except that attributes of the replacement key are copied from the existing key, with the exception of the attributes listed in Re-key Attribute Requirements.
As the replacement key takes over the name attribute of the existing key, Re-key SHOULD only be performed once on a given key.
The server SHALL copy the Unique Identifier of the replacement key returned by this operation into the ID Placeholder variable.
For the existing key, the server SHALL create a Link attribute of Link Type Replacement Object pointing to the replacement key. For the replacement key, the server SHALL create a Link attribute of Link Type Replaced Key pointing to the existing key.
An Offset MAY be used to indicate the difference between the Initial Date and the Activation Date of the replacement key. If no Offset is specified, the Activation Date, Process Start Date, Protect Stop Date and Deactivation Date values are copied from the existing key. If Offset is set and dates exist for the existing key, then the dates of the replacement key SHALL be set based on the dates of the existing key as follows.
Implementation
The Re-Key Operation refreshes Symmetric keys.
Example - Refresh a Symmetric Key
Corresponding KMS CLI command:
ckms sym keys re-key -k 64c60363-6660-4fd4-9f30-c965a0f72fc3
{
"tag": "ReKey",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "64c60363-6660-4fd4-9f30-c965a0f72fc3"
}
]
}
{
"tag": "ReKeyResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "64c60363-6660-4fd4-9f30-c965a0f72fc3"
}
]
}
Specification
This request is used to generate a replacement key pair for an existing public/private key pair. It is analogous to the Create Key Pair operation, except that attributes of the replacement key pair are copied from the existing key pair, with the exception of the attributes listed in Re-key Key Pair Attribute Requirements tor.
As the replacement of the key pair takes over the name attribute for the existing public/private key pair, Re-key Key Pair SHOULD only be performed once on a given key pair.
For both the existing public key and private key, the server SHALL create a Link attribute of Link Type Replacement Key pointing to the replacement public and private key, respectively. For both the replacement public and private key, the server SHALL create a Link attribute of Link Type Replaced Key pointing to the existing public and private key, respectively.
The server SHALL copy the Private Key Unique Identifier of the replacement private key returned by this operation into the ID Placeholder variable.
An Offset MAY be used to indicate the difference between the Initial Date and the Activation Date of the replacement key pair. If no Offset is specified, the Activation Date and Deactivation Date values are copied from the existing key pair. If Offset is set and dates exist for the existing key pair, then the dates of the replacement key pair SHALL be set based on the dates of the existing key pair as follows
Implementation
The Re-Key Key Pair Operation is the main mechanism to rotate Covercrypt attributes on the Eviden KMS Server. By
updating, through this operation, the Policy held by a master secret key in it Vendor Attributes, the Eviden KMS Server
will automatically
- update the Policy held by the Master Public Key
- and re-key all non revoked User Decryption Keys holding the rotated policy attributes in a way that they will now be able to decrypt cipher texts encrypted with attributes before and after the rotation.
The operation has currently no other usages on the Eviden server.
Example - Rotate the Security Level::Confidential attribute
Corresponding KMS CLI command:
ckms cc keys rekey -k b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9 "Security Level::Confidential"
Using a JSON TTLV request to rotate the Security Level::Confidential attribute on a master secret key, construct a JSON object containing
an array of the attributes that must be rotated:
{
"RotateAttributes":
[
"Security Level::Confidential"
]
}
Then hex encode the JSON and add it as a VendorAttribute with name cover_crypt_policy_edit_action to the Re-Key Key Pair request.
The Private Key Unique Identifier of the Master Secret Key must be passed in the request.
{
"tag": "ReKeyKeyPair",
"type": "Structure",
"value": [
{
"tag": "PrivateKeyUniqueIdentifier",
"type": "TextString",
"value": "b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9"
},
{
"tag": "PrivateKeyAttributes",
"type": "Structure",
"value": [
{
"tag": "CryptographicAlgorithm",
"type": "Enumeration",
"value": "CoverCrypt"
},
{
"tag": "KeyFormatType",
"type": "Enumeration",
"value": "CoverCryptSecretKey"
},
{
"tag": "ObjectType",
"type": "Enumeration",
"value": "PrivateKey"
},
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorAttributes",
"type": "Structure",
"value": [
{
"tag": "VendorIdentification",
"type": "TextString",
"value": "cosmian"
},
{
"tag": "AttributeName",
"type": "TextString",
"value": "cover_crypt_policy_edit_action"
},
{
"tag": "AttributeValue",
"type": "ByteString",
"value": "7B22526F7461746541747472696275746573223A5B225365637572697479204C6576656C3A3A436F6E666964656E7469616C225D7D"
}
]
}
]
}
]
}
]
}
{
"tag": "ReKeyKeyPairResponse",
"type": "Structure",
"value": [
{
"tag": "PrivateKeyUniqueIdentifier",
"type": "TextString",
"value": "b652a48a-a48c-4dc1-bd7e-cf0e5126b7b9"
},
{
"tag": "PublicKeyUniqueIdentifier",
"type": "TextString",
"value": "0fd1f684-156c-4ca6-adc2-0a6f4b620463"
}
]
}
Specification
This request is used to generate a replacement certificate for an existing X.509 certificate. It is analogous to the Certify operation, except that the source is an already-issued certificate rather than a public key or CSR.
The server creates a new certificate with a fresh Unique Identifier, copies the subject public key and the requested validity period from the existing certificate, and re-signs it using the specified (or inherited) issuer key.
[KMIP 2.1], §6.1.6, "Certify" — "This request supports the certification of a new public key, as well as the certification of a public key that has already been certified (i.e., certificate update)."
The dedicated
ReCertifyoperation tag (distinct fromCertify) creates the replacement certificate as a new managed object with a new UID, and wires bidirectionalReplacementObjectLink/ReplacedObjectLinkattributes between old and new certificates.
Server behaviour:
- A new Certificate object is created with a fresh Unique Identifier.
- The new certificate is issued with the requested
Offset(activation delay) andNumberOfDaysvalidity, or the issuer's defaults if omitted. ReplacementObjectLinkis added to the old certificate pointing to the new UID.ReplacedObjectLinkis added to the new certificate pointing back to the old UID.- The new certificate enters Active state (or Pre-Active if
Offset > 0). - The old certificate is not automatically deactivated — its state remains
unchanged. Call
Revokeexplicitly to deactivate it when ready.
Request Payload
| Item | Required | Description |
|---|---|---|
UniqueIdentifier | No | UID of the existing certificate to re-certify. Defaults to the ID Placeholder if omitted. |
CertificateRequestType | No | Type of an optional accompanying certificate request (e.g., PKCS10). |
CertificateRequestValue | No | Raw certificate request bytes (PEM or DER). Overrides the subject information from the old cert. |
Offset | No | Seconds between Initial Date and the new certificate's Activation Date. 0 → Active immediately; > 0 → Pre-Active. |
Attributes | No | Desired attributes for the new certificate (e.g., issuer private key ID, issuer certificate ID, number of days). |
ProtectionStorageMasks | No | Permissible protection storage mask selections for the new object. |
Response Payload
| Item | Description |
|---|---|
UniqueIdentifier | The Unique Identifier of the newly created replacement certificate. |
Implementation
The ReCertify operation rotates an X.509 certificate. It is the certificate
equivalent of Re-Key for symmetric keys and Re-Key Key Pair for asymmetric
key pairs.
Key differences vs. Certify with certificate-id-to-re-certify:
| Aspect | ReCertify operation | Certify with existing cert UID |
|---|---|---|
| New UID | Always fresh | Optionally same as old |
| Object links | Bidirectional (old ↔ new) | Not set automatically |
| Old cert deactivation | Manual (call Revoke) | Manual (call Revoke) |
| KMIP operation tag | ReCertify | Certify |
CLI command:
ckms certificates certify \
--certificate-id-to-re-certify <OLD_CERT_UID> \
--issuer-private-key-id <ISSUER_SK_UID> \
--issuer-certificate-id <ISSUER_CERT_UID> \
--number-of-days 365
Example — Re-certify a self-signed certificate
{
"tag": "ReCertify",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "c3d4e5f6-0000-0000-0000-aabbccddeeff"
}
]
}
{
"tag": "ReCertifyResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "a1b2c3d4-1111-2222-3333-445566778899"
}
]
}
Example — Re-certify with a future activation date (Offset)
An Offset of 86400 (24 h) produces a Pre-Active certificate whose
Activation Date is set to Initial Date + 86400 s, allowing a zero-downtime
switchover by pre-staging the replacement before the old one expires.
{
"tag": "ReCertify",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "c3d4e5f6-0000-0000-0000-aabbccddeeff"
},
{
"tag": "Offset",
"type": "Interval",
"value": 86400
}
]
}
{
"tag": "ReCertifyResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "b2c3d4e5-aaaa-bbbb-cccc-ddeeff001122"
}
]
}
KMIP link chain after re-certification
flowchart LR
C0["Cert₀ (old)<br/>Active"] -->|ReplacementObjectLink| C1["Cert₁ (new)<br/>Active"]
C1 -->|ReplacedObjectLink| C0
The old certificate remains Active until explicitly revoked. To complete the
rotation:
# Revoke the old certificate when no longer needed
ckms certificates revoke --certificate-id <OLD_CERT_UID> \
--revocation-reason "Superseded"
Key Rotation
Cosmian KMS supports manual key rotation for all key types through the standard KMIP operations:
| KMIP operation | Applies to | CLI command |
|---|---|---|
Re-Key | Symmetric keys, secret data | ckms sym keys rekey |
Re-Key Key Pair | Asymmetric key pairs (RSA, EC, PQC, …) | ckms {rsa,ec,pqc} keys rekey |
ReCertify | X.509 certificates | ckms certificates certify --certificate-id-to-re-certify |
On every rotation the server:
- Generates a new cryptographic object (or new certificate) under a fresh UID.
- Sets a
ReplacementObjectLinkon the old object pointing to the new UID. - Sets a
ReplacedObjectLinkon the new object pointing back to the old UID. - Transitions the old key to Deactivated (KMIP §4.57, transition 6 — see below).
- Increments
x-rotate-generationand recordsx-rotate-dateon the new object.
Auto-rotation (scheduler-driven, policy-based) is covered separately in Auto-Rotation Policy. HSM key rotation is covered in HSM Key Rotation.
State restrictions
Only objects in the following states can be the source of a rotation:
| State | Rotation allowed? | Rationale |
|---|---|---|
| Active | ✅ | Primary valid source state. |
| Deactivated | ✅ | KMIP §6.1.46 permits it; a replacement key should still be issued. |
| Compromised | ✅ | Rotating a compromised key is the recommended incident response. |
| Pre-Active | ❌ | Key material was never activated — rotating unused material is premature. |
| Destroyed | ❌ | Object no longer exists. |
| Destroyed_Compromised | ❌ | Object no longer exists. |
This restriction applies to the source key only. The output of a rotation can enter
Pre-Activeif the request includes anOffset > 0(the new key's Activation Date is set toInitial Date + Offset).
Old key Deactivated after rotation
Why deactivation is enforced
A key in the Deactivated state SHALL NOT be used for applying cryptographic protection (encryption, signing, wrapping, MACing, deriving). It MAY still be used to process already-protected data (decryption, signature verification, unwrapping). This asymmetry is the key principle behind post-rotation key handling:
- Limit blast radius. If the old key material is compromised after rotation, no new data was ever encrypted with it — the damage is bounded.
- Enforce the cryptoperiod. NIST SP800-57-1 defines a cryptoperiod as the span during which a key is authorised to protect data. Key rotation ends that period; the Deactivated state makes the boundary enforceable by the server.
- Preserve backward compatibility. Consumers holding ciphertexts produced before rotation must still be able to decrypt. Deactivated keeps the key accessible for decryption without allowing it to encrypt new data.
How KMIP §4.57 mandates it
KMIP §4.57 defines the State attribute and lists the only legal state
transitions. Transition 6 governs Active → Deactivated and states that it
SHALL occur in one of three ways:
- The object's Deactivation Date is reached.
- A client issues a Revoke operation with a non-Compromised reason.
- A client Modify Attribute sets the Deactivation Date to now or the past.
Re-Key / Re-Key Key Pair are not listed as a direct cause of transition 6.
The spec mandates deactivation indirectly through path 1: the KMIP §4.33
Deactivation Date attribute rules list Re-key and Re-key Key Pair under
"When implicitly set", meaning the server MUST set the Deactivation Date on
the old key as part of the rotation operation. Because that date is set to
now (or already passed), the condition "Deactivation Date is reached"
immediately triggers transition 6.
In short: the spec does not have a direct Re-Key → Deactivated transition, but
it mandates deactivation by requiring the server to set the Deactivation Date
during Re-Key, which then fires transition 6 automatically.
Consequences
- The old key can no longer be used for Encrypt or Sign operations
(those require
Activestate). - The old key remains available for Decrypt and Verify (processing
operations accept
Active,Deactivated, andCompromisedstates per KMIP §3.31), so in-flight ciphertexts continue to decrypt. - You can call
Revokeon an already-Deactivated key; the call succeeds as a no-op (the state is already revoked). - You can call
Destroyon a Deactivated key directly — no priorRevokeis required.
Keysets
A keyset is a named group of related key generations. Each generation is
a distinct cryptographic key (different material, different UID) produced by
successive Re-Key operations.
Creating a SQL key in a keyset
For SQL-backed keys the key's UID must equal the keyset name from the
start. Supply both UniqueIdentifier and x-rotate-name in the same Create
request:
# Create a key whose UID is the keyset name
ckms sym keys create --key-id my-keyset --algorithm aes --length 256
ckms sym keys set-rotation-policy --key-id my-keyset --name my-keyset
Attempting set-rotation-policy --name X on a SQL key whose UID is not X
is rejected:
Invalid Request: SetAttribute: rotate_name ('X') must equal the key's UID — create the key with the keyset name as its ID
SQL keyset UID scheme
UIDs are assigned deterministically at each generation:
my-keyset ← gen 0 (UID equals the keyset name)
my-keyset@1 ← gen 1 (after first Re-Key)
my-keyset@2 ← gen 2 (after second Re-Key)
The Re-Key response always returns the new key's real UID (e.g. my-keyset@1).
Addressing syntax
A keyset can be referenced by name wherever a UniqueIdentifier is accepted
(Encrypt, Decrypt, Get, Re-Key, …):
| Syntax | Resolves to |
|---|---|
my-keyset | Latest generation (bare name = @latest) |
my-keyset@latest | Latest generation (explicit alias) |
my-keyset@first | Generation 0 |
my-keyset@0 | Generation 0 (numeric alias for @first) |
my-keyset@N | Generation N |
Encrypt / Sign always resolves to the latest generation.
Decrypt / Verify walks the chain newest-to-oldest until one generation succeeds, allowing ciphertexts encrypted with an older (now Deactivated) key to continue to decrypt after rotation.
@latestis a virtual alias. It is never stored in the database and is never returned in a response.my-keyset(bare name) also resolves to the latest generation even thoughmy-keysetis the literal UID of gen-0. To access gen-0 explicitly, usemy-keyset@0ormy-keyset@first.
Non-latest guard
Only the latest generation of a keyset can be rotated via Re-Key.
Attempting to rotate a retired member is rejected:
Invalid Request: ReKey: key '<uid>' is not the latest in its keyset —
only the latest generation can be rotated
Use my-keyset@0 (explicit generation) rather than my-keyset (bare name)
to target an older generation — and expect that call to fail.
Keyset internals (SQL)
Keyset state is stored as KMIP vendor attributes in the database:
| Attribute | Type | Meaning |
|---|---|---|
x-rotate-name | string | Keyset name; equals the key UID for gen-0. |
x-rotate-generation | i32 | 0 for gen-0, incremented on each Re-Key. |
x-rotate-latest | bool | true on the current key; false on older keys. |
KMIP link attributes mirror the chain for protocol compliance:
ReplacementObjectLink (old → new) and ReplacedObjectLink (new → old).
Keyset chain traversal for Decrypt / Verify uses
x-rotate-generation (sorted descending), not the link back-pointers.
Rotation flows by key type
1. Plain symmetric key
A plain symmetric key carries only its own policy.
What happens:
- Fresh key material is generated (same algorithm and length).
- The new key gets a new UID (
my-keyset@Nfor keyset keys, fresh UUID otherwise). ReplacedObjectLinkon the new key → old key.ReplacementObjectLinkon the old key → new key.- Old key → Deactivated.
KMIP link chain after two rotations:
flowchart LR
K0["Key₀ (gen 0)<br/>Deactivated"] -->|ReplacementObjectLink| K1["Key₁ (gen 1)<br/>Deactivated"]
K1 -->|ReplacementObjectLink| K2["Key₂ (gen 2)<br/>Active"]
K2 -->|ReplacedObjectLink| K1
K1 -->|ReplacedObjectLink| K0
CLI:
# Manual rotation of a SQL keyset key
ckms sym keys rekey --key-id my-keyset
# Response: new UID = my-keyset@1
# Manual rotation of a plain UUID key
ckms sym keys rekey --key-id <KEY_UID>
2. Wrapping key
A wrapping key is referenced by one or more wrapped keys via a
WrappingKeyLink attribute. Rotating a wrapping key re-wraps all its
dependants atomically.
What happens:
- A new wrapping key is created and committed to the database (Phase 1).
- Every key owned by the same user whose
WrappingKeyLinkpoints to the old wrapping key is fetched — regardless of its state (Active, Deactivated, Pre-Active, Compromised, …) — unwrapped in memory (plaintext never stored), and re-wrapped with the new wrapping key (Phase 2). - Each wrapped key's
WrappingKeyLinkis updated to the new wrapping key UID. - Standard rotation metadata is applied; old wrapping key → Deactivated.
No state filter on dependants. The server queries all keys with a
wrapping_key_idmatching the rotated key, with no restriction on their lifecycle state. Only the owner check applies: dependants owned by a different user are skipped (with a warning logged).
sequenceDiagram
participant Client
participant KMS
participant DB
Client->>KMS: Re-Key(wrapping_key_uid)
KMS->>DB: Phase 1 — create new wrapping key (committed)
loop For each wrapped dependant
KMS->>DB: retrieve wrapped key
KMS->>KMS: unwrap with old wrapping key
KMS->>KMS: re-wrap with new wrapping key
KMS->>DB: update WrappingKeyLink → new wrapping key UID
end
KMS->>DB: Phase 2 — retire old wrapping key (Deactivated, links set)
KMS-->>Client: Re-KeyResponse(new_wrapping_key_uid)
3. Wrapped key
A wrapped key stores its key material encrypted under a wrapping key.
What happens:
- The wrapped key is exported and unwrapped in memory using the current wrapping key (plaintext never stored).
- Fresh plaintext key material is generated from the unwrapped attributes.
- The new material is re-wrapped with the same wrapping key.
- The new ciphertext is stored under a new UID with an active
WrappingKeyLink. - Standard rotation metadata is applied; old wrapped key → Deactivated.
sequenceDiagram
participant Client
participant KMS
participant DB
Client->>KMS: Re-Key(wrapped_key_uid)
KMS->>DB: retrieve wrapped key + wrapping key
Note over KMS: unwrap in-memory (plaintext never stored)
KMS->>KMS: generate new key material
KMS->>KMS: re-wrap with same wrapping key
KMS->>DB: store new wrapped key (new UID, same WrappingKeyLink)
KMS->>DB: retire old key (Deactivated, ReplacementObjectLink → new key)
KMS-->>Client: Re-KeyResponse(new_key_uid)
4. Asymmetric key pair
Re-Key Key Pair targets the private key UID. The server resolves the
associated public key via the PublicKeyLink attribute.
What happens:
- A new private key + public key pair is generated (same algorithm).
- Both receive new UIDs; the new private key carries a
PublicKeyLinkto the new public key. - Standard
ReplacementObjectLink/ReplacedObjectLinklinks are set on both pairs. - Old private key and old public key → Deactivated.
sequenceDiagram
participant Client
participant KMS
participant DB
Client->>KMS: Re-Key Key Pair(private_key_uid)
KMS->>DB: retrieve private key
KMS->>DB: retrieve linked public key (PublicKeyLink)
KMS->>KMS: generate new key pair (same algorithm)
KMS->>DB: Phase 1 — store new private key + new public key
KMS->>DB: Phase 2 — retire old private key + public key (Deactivated, links)
KMS-->>Client: Re-Key Key PairResponse(new_sk_uid, new_pk_uid)
CLI:
# EC key pair
ckms ec keys rekey --key-id <PRIVATE_KEY_UID>
# RSA key pair
ckms rsa keys rekey --key-id <PRIVATE_KEY_UID>
# Post-quantum (ML-KEM, ML-DSA, SLH-DSA)
ckms pqc keys rekey --key-id <PRIVATE_KEY_UID>
5. Wrapped private key (Covercrypt)
A Covercrypt master private key follows the same Re-Key Key Pair flow. The
wrapped key is unwrapped in memory, the Covercrypt partition attributes are
re-keyed, and the new wrapped private key is stored under a fresh UID.
Setting a rotation policy on a wrapped private key always works: the
x-rotate-*attributes are stored in the metadata column (not inside the ciphertext block) and do not require the key to be unwrapped first.
6. Certificate renewal (ReCertify)
Certificate renewal creates a new certificate for the same key pair — no new key material is generated.
What happens:
- The existing certificate is retrieved and its issuer / subject are resolved.
- A new certificate is built and signed (same key pair, same issuer).
- The new certificate receives a fresh UID.
ReplacedObjectLinkon the new cert → old cert.ReplacementObjectLinkon the old cert → new cert.- All keys linked to the old certificate have their
CertificateLinkupdated. x-rotate-generationandx-rotate-dateare updated.
sequenceDiagram
participant Client
participant KMS
participant DB
Client->>KMS: ReCertify(old_cert_uid)
KMS->>DB: retrieve old certificate
KMS->>KMS: resolve issuer + subject from old cert
KMS->>KMS: build & sign new certificate (same key pair)
KMS->>DB: Phase 1 — store new cert (fresh UID)
KMS->>DB: Phase 2 — update old cert (ReplacementObjectLink)
KMS->>DB: Phase 2 — relink keys (CertificateLink → new cert)
KMS-->>Client: ReCertifyResponse(new_cert_uid)
Attribute changes (KMIP 2.1 §6.1.45):
| Attribute | New certificate | Old certificate |
|---|---|---|
Unique Identifier | Fresh UUID | Unchanged |
Initial Date | Now | Unchanged |
Link[ReplacedObjectLink] | → old cert UID | — |
Link[ReplacementObjectLink] | — | → new cert UID |
Link[PublicKeyLink] | Copied from old | Unchanged |
Link[PrivateKeyLink] | Copied from old | Unchanged |
Name | Inherited from old | Removed (per KMIP spec) |
State | Active | Active (not Deactivated — certificates are exempt from §4.57) |
x-rotate-generation | old + 1 | Unchanged |
x-rotate-date | Now | Unchanged |
CLI:
# Renew a CA-signed certificate (same key pair, new validity period)
ckms certificates certify \
--certificate-id-to-re-certify <OLD_CERT_UID> \
--issuer-private-key-id <ISSUER_SK_UID> \
--days 365
# Self-signed certificate renewal
ckms certificates certify \
--certificate-id-to-re-certify <OLD_CERT_UID> \
--days 3650
Standards:
| Standard | Relevance |
|---|---|
| KMIP 2.1 §6.1.45 | Normative definition of ReCertify |
| RFC 4210 §5.3.5–5.3.6 | CMP Key Update Request / Response (kur/kup) — the wire-protocol equivalent |
| RFC 5280 | X.509v3 certificate structure and validity periods |
7. KEK-protected key (server-wide key-encryption key)
When the KMS server is started with --key-encryption-key <KEK_UID>, every
object stored in the database is transparently wrapped by the KEK. Rotation
works identically to the wrapped-key flow above — the server unwraps in memory,
generates fresh material, re-wraps, and stores the result.
# Example server startup with SoftHSM2 KEK
cosmian_kms \
--database-type sqlite \
--hsm-model softhsm2 \
--hsm-slot 0 \
--hsm-password 12345678 \
--key-encryption-key "hsm::softhsm2::0::my-kek"
No special handling is required for rotation policy — SetAttribute on a
KEK-wrapped key writes the x-rotate-* attributes to the metadata column, not
into the ciphertext, so no unwrap is needed.
Rotation dispatch overview
flowchart TD
subgraph "Re-Key dispatch"
REQ["Re-Key / Re-Key Key Pair / ReCertify"] --> DISPATCH{"Object type?"}
DISPATCH -->|SymmetricKey, no dependants| PLAIN["Plain rekey<br/>(new material, new UID)"]
DISPATCH -->|SymmetricKey, has WrappingKeyLink dependants| WRAP_K["Wrapping-key rotation<br/>(Phase 1 commit → Phase 2 re-wrap)"]
DISPATCH -->|SymmetricKey, is wrapped| WRAP_D["Wrapped-key rotation<br/>(unwrap → new material → re-wrap)"]
DISPATCH -->|PrivateKey| ASYM["Re-Key Key Pair"]
DISPATCH -->|Certificate| CERT["ReCertify<br/>(same key pair, new cert UID)"]
PLAIN & WRAP_K & WRAP_D & ASYM & CERT --> META["Update metadata<br/>(generation++, date, links,<br/>old key → Deactivated)"]
end
KMIP attribute changes on manual rotation
When the user explicitly calls Re-Key (e.g. ckms sym keys rekey), the
following attributes are set on the old and new key:
| Attribute | Old key | New key |
|---|---|---|
Unique Identifier | unchanged | fresh UUID (or name@N for keyset keys) |
State | Deactivated (§4.57) | Active |
Link[ReplacementObjectLink] | → new key UID | — |
Link[ReplacedObjectLink] | — | → old key UID |
Link[WrappingKeyLink] | unchanged | copied from old key |
x-rotate-generation | unchanged | old value + 1 |
x-rotate-date | unchanged | timestamp of rotation |
x-rotate-interval | set to 0 (disabled) | 0 — must be re-armed explicitly on the new key |
x-rotate-name | unchanged | inherited from old key |
x-rotate-offset | unchanged | None (not inherited for manual rekey) |
Name | removed | inherited from old key |
Manual vs auto-rotation difference:
x-rotate-intervalis intentionally set to0(not inherited) on the new key after a manual rotation. This forces the operator to re-evaluate the rotation policy for the new key rather than blindly continuing the old schedule.# After a manual rekey, re-arm the rotation policy on the new key: ckms sym keys set-rotation-policy \ --key-id <NEW_KEY_UID> \ --interval 3600 \ --name "my-keyset"
Revoking superseded keys
After rotation the old key is Deactivated (not Destroyed). Its material persists so that in-flight Decrypt / Verify operations against old ciphertexts continue to work. Once all consumers have migrated, destroy the old key:
# Find the old key UID from the new key's ReplacedObjectLink attribute
ckms objects get-attributes --key-id <NEW_KEY_UID>
# Destroy the old key directly (Deactivated keys do not need a prior Revoke)
ckms sym keys destroy --key-id <OLD_KEY_UID>
If you need to place the old key into Compromised state (e.g. for audit
records), call Revoke first with a compromise reason:
# Symmetric key
ckms sym keys revoke -k <OLD_KEY_UID> "Superseded"
# Asymmetric key pair (revokes both private and linked public key)
ckms ec keys revoke -k <OLD_KEY_UID> "Superseded"
# Certificate
ckms certificates revoke -c <OLD_CERT_UID> "Superseded"
HSM Key Rotation
Cosmian KMS supports manual Re-Key for keys that reside on a
PKCS#11-capable Hardware Security Module (SoftHSM2, Utimaco, Proteccio, …).
The flow mirrors SQL-backed rotation but all keyset metadata lives in PKCS#11
attributes rather than the KMS database.
Capabilities
| Capability | Supported | Notes |
|---|---|---|
Manual Re-Key via KMIP | ✅ | Calls C_GenerateKey on the same HSM slot. |
Keyset membership (x-rotate-name) | ✅ | Stored in CKA_LABEL; keyset name must be the full base UID (hsm::model::slot::key_id). Supports @latest, @first, @N generation addressing. |
x-rotate-interval attribute | ✅ | Writes CKA_START_DATE / CKA_END_DATE for validity tracking. |
| Auto-rotation scheduler | ❌ | find_due_for_rotation never returns HSM UIDs; scheduler skips them. |
x-rotate-offset | ❌ | Not applicable to PKCS#11 scheduling; rejected with NotSupported. |
CKA_LABEL convention
HSM keyset metadata is stored entirely in the PKCS#11 CKA_LABEL attribute —
no SQL shadow rows are written.
CKA_LABEL value | Meaning |
|---|---|
{key_id} (plain, before enrollment) | Initial state after Create — key has not yet been added to a keyset |
{base_uid}::0::{key_id}@latest | Gen-0 key immediately after SetAttribute enrollment |
{base_uid}::{gen}::{base_id}@latest | Current latest key after any Re-Key |
{base_uid}::{gen}::{base_id} | Retired key (any generation that is no longer the latest) |
| (anything else) | Key does not belong to a keyset |
Where:
base_uid— the full base UID of the gen-0 key:hsm::<model>::<slot_id>::<key_id>. Because it embeds the slot ID, the keyset name is unique across all HSM slots. A key on slot 0 and a key on slot 1 with the same local name will have different keyset names (hsm::softhsm2::0::my-keyvshsm::softhsm2::1::my-key).gen— integer starting at0, incremented on everyRe-Key.base_id/key_id— the PKCS#11CKA_IDof the gen-0 key.
The label format is {rotate_name}::{gen}::{key_id}. For HSM keys,
rotate_name is the full base UID (hsm::softhsm2::0::my-hsm-key), which
already embeds the local key name. The same name then appears again as the
separate key_id field required by parse_label_metadata to reconstruct the
per-key PKCS#11 CKA_ID.
hsm::softhsm2::0::my-hsm-key :: 0 :: my-hsm-key@latest
├─ rotate_name (full base UID) gen key_id
This duplication is intentional and handled by the right-split parser.
Because rotate_name itself contains ::, the label is parsed from the right
(rsplitn(3, "::")):
hsm::softhsm2::0::my-key::1::my-key@latest
├─ rotate_name = "hsm::softhsm2::0::my-key" (everything left of the last two ::)
├─ generation = 1
└─ key_id = "my-key@latest"
This is backward-compatible: labels written before the full-UID convention
(e.g. "my-keyset::0::my-key@latest") still parse correctly.
UID scheme
hsm::<model>::<slot_id>::<base_key_id> ← gen 0 (original key)
hsm::<model>::<slot_id>::<base_key_id>@1 ← gen 1 (after first Re-Key)
hsm::<model>::<slot_id>::<base_key_id>@2 ← gen 2 (after second Re-Key)
Where <model> is the HSM model name (e.g. softhsm2, utimaco, proteccio).
The @N generation suffix is appended to the original base_key_id, using the
same convention as SQL keyset keys (my-key@1, my-key@2). Unlike
SQL keys, the base portion of the UID never changes, so the full chain can be
discovered by scanning CKA_LABEL on the HSM slot.
The older format hsm::<slot_id>::<key_id> (without model segment) is still
accepted for backward compatibility with keys created before the model segment
was introduced.
Keyset name constraint
For HSM keys the keyset name (x-rotate-name) must be the key's full base UID
(hsm::<model>::<slot>::<key_id> without any @N suffix).
| Value | Accepted? | Reason |
|---|---|---|
hsm::softhsm2::0::my-hsm-key | ✅ | Full base UID — unique across slots. |
my-hsm-keyset | ❌ | Bare name rejected — no slot disambiguation. |
hsm::softhsm2::0::my-hsm-key@1 | ❌ | Generation suffix rejected — base UID only. |
Invalid Request: SetAttribute: for HSM keys, rotate_name must be the key's base UID
('hsm::softhsm2::0::my-hsm-key'), not 'my-hsm-keyset'
Why this constraint? A bare name like
"my-hsm-key"is ambiguous when multiple HSM slots are in use — two keys on different slots could have the same local name. Embedding the slot ID in the keyset name prevents cross-slot collisions without requiring a central name registry.
Keyset resolution
When a base UID (e.g. hsm::softhsm2::0::my-hsm-key) or generation-scoped syntax
(hsm::softhsm2::0::my-hsm-key@latest, hsm::softhsm2::0::my-hsm-key@0,
hsm::softhsm2::0::my-hsm-key@N) is used, the server calls find_by_rotate_name,
which scans PKCS#11 objects in the HSM slot and parses CKA_LABEL to extract
the rotate_name and rotate_generation. Results are sorted by generation
descending:
- Encrypt / Sign → uses the key with the highest
rotate_generation(current latest). The@latestsuffix inCKA_LABELis not used for this determination — generation sorting is the authoritative source. - Decrypt / Verify → tries each generation newest-to-oldest until one succeeds, allowing old ciphertexts to continue to decrypt after rotation.
Using a direct generation UID with an explicit @N suffix
(e.g. hsm::softhsm2::0::my-hsm-key@0) bypasses keyset resolution entirely:
only that specific generation is used, with no chain walk.
Using the base UID without @N (e.g. hsm::softhsm2::0::my-hsm-key)
always resolves to the latest generation (see Second rotation and non-latest guard
below for the Re-Key-specific stable-handle behaviour).
HSM keysets do not use ReplacedObjectLink / ReplacementObjectLink
back-pointers; all state lives in PKCS#11 attributes.
Full rotation workflow
Setup
# 1. Start the KMS server with HSM backend
cosmian_kms \
--database-type sqlite \
--hsm-model softhsm2 \
--hsm-slot 0 \
--hsm-password 12345678
Create and enrol
# 2. Create an AES-256 key directly on the HSM
ckms sym keys create \
--key-id "hsm::softhsm2::0::my-hsm-key" \
--algorithm aes --length 256
# 3. Enrol the key in a keyset.
# The keyset name MUST equal the key's full base UID.
# Before: CKA_LABEL = "my-hsm-key" (plain key_id set at creation)
# After: CKA_LABEL = "hsm::softhsm2::0::my-hsm-key::0::my-hsm-key@latest"
# └─ rotate_name ──────────────────────┘ gen └─ key_id ──┘
ckms sym keys set-rotation-policy \
--key-id "hsm::softhsm2::0::my-hsm-key" \
--name "hsm::softhsm2::0::my-hsm-key"
Encrypt using the base UID as the keyset address
# 4. Encrypt — base UID resolves to the latest key (gen-0 initially)
ckms sym encrypt --key-id "hsm::softhsm2::0::my-hsm-key" plaintext.bin -o ciphertext.enc
First rotation
# 5. Rotate using the base UID as a stable keyset handle.
# No @N suffix → server redirects to the latest generation (gen-0 here).
ckms sym keys rekey --key-id "hsm::softhsm2::0::my-hsm-key"
# Response: new UID = hsm::softhsm2::0::my-hsm-key@1
#
# CKA_LABEL (gen-0): "hsm::softhsm2::0::my-hsm-key::0::my-hsm-key" (retired)
# CKA_LABEL (gen-1): "hsm::softhsm2::0::my-hsm-key::1::my-hsm-key@latest" (current)
sequenceDiagram
participant Client
participant KMS
participant HSM
Client->>KMS: Re-Key("hsm::softhsm2::0::my-hsm-key")
KMS->>HSM: C_FindObjects (CKA_ID = "my-hsm-key")
HSM-->>KMS: {gen-0 object handle}
KMS->>KMS: build new key attributes<br/>(algorithm, length, gen=1)
KMS->>HSM: C_GenerateKey → gen-1 object
KMS->>HSM: C_SetAttributeValue gen-0<br/>CKA_LABEL = "hsm::softhsm2::0::my-hsm-key::0::my-hsm-key"
KMS->>HSM: C_SetAttributeValue gen-1<br/>CKA_LABEL = "hsm::softhsm2::0::my-hsm-key::1::my-hsm-key@latest"
KMS-->>Client: Re-KeyResponse("hsm::softhsm2::0::my-hsm-key@1")
Decrypt old ciphertext after rotation
# 6. Decrypt using the base UID — server tries gen-1 then gen-0
ckms sym decrypt --key-id "hsm::softhsm2::0::my-hsm-key" ciphertext.enc -o plaintext.bin
sequenceDiagram
participant Client
participant KMS
participant HSM
Client->>KMS: Decrypt("hsm::softhsm2::0::my-hsm-key", ciphertext)
KMS->>HSM: find_by_rotate_name("hsm::softhsm2::0::my-hsm-key")<br/>scan CKA_LABEL right-split, sort by gen desc
HSM-->>KMS: [gen-1, gen-0]
KMS->>HSM: C_DecryptInit / C_Decrypt with gen-1
HSM-->>KMS: DecryptFailed (wrong key material)
KMS->>HSM: C_DecryptInit / C_Decrypt with gen-0
HSM-->>KMS: plaintext
KMS-->>Client: DecryptResponse(plaintext)
Second rotation and non-latest guard
The Re-Key operation distinguishes two addressing styles for HSM keys:
| Addressing style | Example | Behaviour when not latest |
|---|---|---|
Stable handle (base UID, no @N) | hsm::softhsm2::0::my-hsm-key | Silently redirects to the latest generation |
Explicit generation (@N) | hsm::softhsm2::0::my-hsm-key@0 | Returns an error |
# 7. Second rotation using the stable handle (always rotates the latest)
ckms sym keys rekey --key-id "hsm::softhsm2::0::my-hsm-key"
# → redirected to gen-1 (current latest)
# Response: new UID = hsm::softhsm2::0::my-hsm-key@2
# Attempting to re-key an explicit retired generation is rejected:
ckms sym keys rekey --key-id "hsm::softhsm2::0::my-hsm-key@0" # explicit @0 — REJECTED
# Error: ReKey: HSM key 'hsm::softhsm2::0::my-hsm-key@0' is not the latest in its keyset
# — only the latest generation can be rotated.
# Use 'hsm::softhsm2::0::my-hsm-key' to always rotate the current head.
Differences from SQL rotation
| Aspect | SQL-backed keys | HSM-resident keys |
|---|---|---|
| Keyset metadata storage | KMIP vendor attributes (x-rotate-*) in SQL DB | CKA_LABEL on PKCS#11 objects |
| UID scheme | Plain identifier (keyset name is a rotate_name attribute, not in the UID) | hsm::<model>::<slot>::<base_key_id>[@N] (generation suffix appended) |
| Auto-rotation scheduler | ✅ Supported | ❌ Not supported |
x-rotate-offset | ✅ Supported | ❌ Not supported |
| KMIP link back-pointers | ✅ ReplacedObjectLink / ReplacementObjectLink | ❌ Not used; chain lives in CKA_LABEL |
| Chain discovery | SQL query on x-rotate-name + x-rotate-generation | PKCS#11 C_FindObjects on CKA_LABEL prefix |
| Old key state after rotation | Deactivated (§4.57) | Retired label set in CKA_LABEL (no KMIP state) |
Auto-Rotation Policy
Cosmian KMS supports scheduled, policy-driven key rotation for SQL-backed symmetric keys and asymmetric key pairs. A per-key rotation policy is attached to a key object; a background scheduler then rotates any key whose interval has elapsed — without any operator action.
HSM keys support manual rotation only; the auto-rotation scheduler never picks up HSM UIDs. See HSM Key Rotation.
For the rotation flows and sequence diagrams for each key type, see Key Rotation.
Rotation policy attributes
All rotation-policy state is stored as vendor-extension KMIP attributes on the key object itself:
| Attribute | Type | Mutable | Description |
|---|---|---|---|
x-rotate-interval | i64 (seconds) | ✅ | How often to rotate. 0 disables auto-rotation. |
x-rotate-name | string | ✅ | Keyset name this key belongs to (see Key Rotation — Keysets). |
x-rotate-offset | i64 (seconds) | ✅ | Shift the first rotation trigger by this many seconds after Initial Date. |
x-rotate-generation | i32 | ❌ | Incremented on every rotation; 0 for never-rotated keys. Server-managed. |
x-rotate-date | datetime | ❌ | Timestamp of the last rotation. Server-managed. |
x-rotate-latest | bool | ❌ | true on the most-recent keyset member; false on all older keys. Server-managed. |
Read-only attributes
x-rotate-generation, x-rotate-date, and x-rotate-latest are set
exclusively by the server during the Re-Key operation. Any attempt to
modify them via AddAttribute, SetAttribute, ModifyAttribute, or
DeleteAttribute is rejected with Attribute_Read_Only.
These restrictions maintain two invariants relied on by the scheduler and the keyset resolution logic:
- Monotonic generation counter —
x-rotate-generationstarts at0and increments by exactly1per rotation. Within a keyset the generation is unique and strictly increasing, which lets the scheduler and client tooling identify the current key without inspecting every member. - Authoritative rotation timestamp —
x-rotate-dateis the only reliable source for "when was this key last rotated". The scheduler computes the next trigger asx-rotate-date + x-rotate-interval(previously rotated) orinitial_date + x-rotate-offset + x-rotate-interval(never rotated). External modifications tox-rotate-datewould cause missed or premature rotations.
Assigning a rotation policy
Use ckms sym keys set-rotation-policy (or SetAttribute for key pairs) to
configure the mutable attributes on an existing key:
# Rotate every hour; first rotation is 60 seconds after Initial Date
ckms sym keys set-rotation-policy \
--key-id my-keyset \
--interval 3600 \
--offset 60 \
--name my-keyset
SetAttribute initialises x-rotate-generation = 0 and
x-rotate-latest = true on the key. Every subsequent Re-Key increments
the generation, marks the new key as latest, and marks the old key as
non-latest.
For asymmetric key pairs, use SetAttribute directly:
ckms objects set-attribute \
--id <PRIVATE_KEY_UID> \
x-rotate-interval 86400
Server configuration
Enable the scheduler
The background scheduler is disabled by default. Enable it in kms.toml
or via the command-line flag:
# kms.toml
auto_rotation_check_interval_secs = 300 # check every 5 minutes
# Command-line equivalent
cosmian_kms --auto-rotation-check-interval-secs 300
Set the interval to a value smaller than the shortest x-rotate-interval
on any key — otherwise some rotations will be delayed by up to one scheduler
period.
HSM backend + KEK
The scheduler works with any database backend. If the server is started with
a --key-encryption-key, KEK-wrapped keys are rotated the same as plain keys
(the server unwraps in memory, generates fresh material, re-wraps):
cosmian_kms \
--database-type sqlite \
--hsm-model softhsm2 \
--hsm-slot 0 \
--hsm-password 12345678 \
--key-encryption-key "hsm::softhsm2::0::my-kek" \
--auto-rotation-check-interval-secs 300
How the scheduler works
On each tick, the scheduler:
- Queries all Active symmetric keys and private keys whose
x-rotate-interval > 0. - For each candidate, computes the next rotation deadline:
- Previously rotated key:
x-rotate-date + x-rotate-interval - Never-rotated key with Initial Date:
initial_date + x-rotate-offset + x-rotate-interval
- Previously rotated key:
- Rotates every key whose deadline is in the past.
- Emits an OpenTelemetry counter
kms.key.auto_rotationlabelled withuidandalgorithmfor each successful rotation.
The scheduler never returns HSM UIDs — auto-rotation is SQL-only.
Attribute changes on auto-rotation
| Attribute | Old key | New key |
|---|---|---|
Unique Identifier | unchanged | fresh UUID (or name@N for keysets) |
State | Deactivated (§4.57) | Active |
Link[ReplacementObjectLink] | → new key UID | — |
Link[ReplacedObjectLink] | — | → old key UID |
x-rotate-generation | unchanged | old value + 1 |
x-rotate-date | unchanged | timestamp of rotation |
x-rotate-interval | set to 0 (cron skips old key) | inherited from old key |
x-rotate-name | unchanged | inherited from old key |
x-rotate-offset | unchanged | inherited from old key |
x-initial-date | cleared | set to now (resets next deadline) |
Cryptographic Algorithm | unchanged | copied from old key |
Cryptographic Length | unchanged | copied from old key |
Note:
x-rotate-intervalis inherited on auto-rotation (policy continues on the new key automatically). On manualRe-Keyit is set to0on the new key — the operator must re-arm the policy explicitly.
End-to-end setup
Step 1 — Create a key in a keyset
# SQL key: UID must equal the keyset name
ckms sym keys create --key-id my-keyset --algorithm aes --length 256
Step 2 — Attach a rotation policy
ckms sym keys set-rotation-policy \
--key-id my-keyset \
--name my-keyset \
--interval 3600 \
--offset 60
Step 3 — Enable the server scheduler
In kms.toml:
auto_rotation_check_interval_secs = 300
The scheduler will rotate my-keyset for the first time roughly 60 + 3600
seconds after its Initial Date, and every 3600 seconds thereafter.
Disabling auto-rotation on a key
Set x-rotate-interval to 0:
ckms sym keys set-rotation-policy --key-id my-keyset --interval 0
This prevents the scheduler from selecting the key without removing any other keyset metadata.
Keyset chain depth warning
When a Decrypt or Verify call resolves a keyset name (e.g. my-keyset)
rather than an explicit key UID, the server walks the generation chain
newest-to-oldest until one generation succeeds. A very deep chain indicates
that many ciphertexts are still bound to old key generations — a signal that
client-side re-encryption may be overdue.
To surface this, configure keyset_warn_depth in kms.toml:
# Emit a server warning when decryption succeeds at chain depth >= this value.
# Default: 5. 0 disables the warning.
keyset_warn_depth = 5
Or via the CLI flag:
cosmian_kms --keyset-warn-depth 5
When the threshold is reached, the server emits a WARN log line:
Decrypt: keyset chain depth 5 >= warn threshold 5 for uid my-keyset@0;
consider re-encrypting with the latest key
The chain walk has no hard limit. All key generations remain reachable
(subject to KMIP state rules). keyset_warn_depth is purely a
monitoring hint — it never prevents a decryption from succeeding.
Observability
The server increments the OpenTelemetry counter kms.key.auto_rotation with
labels uid and algorithm on every successful auto-rotation. Use your
OTel-compatible backend (Prometheus + Grafana, Datadog, …) to:
- Alert on unexpected gaps in rotation activity.
- Audit which keys were rotated and when.
- Track rotation throughput across the fleet.
See Monitoring for the full OTel setup guide.
Specification
This operation requests the server to revoke a Managed Cryptographic Object or an Opaque Object.
The request contains a reason for the revocation (e.g., "key compromise", "cessation of operation", etc.).
The operation has one of two effects. If the revocation reason is "key compromise" or "CA compromise", then the object is placed into the "compromised" state; the Date is set to the current date and time; and the Compromise Occurrence Date is set to the value (if provided) in the Revoke request and if a value is not provided in the Revoke request then Compromise Occurrence Date SHOULD be set to the Initial Date for the object. If the revocation reason is neither "key compromise" nor "CA compromise", the object is placed into the "deactivated" state, and the Deactivation Date is set to the current date and time.
Implementation
The state of the object is kept as specified but the revocation reason is currently not maintained.
Once an Object is revoked, it can only be retrieved using the Export operation. The Get operation will return an
error.
A Revoked object can be destroyed using the Destroy operation.
Example - Symmetric key
Revoking key f54f14a3-5639-4054-8c23-54af891669db with reason key was compromised.
Corresponding KMS CLI command:
ckms sym keys revoke -k f54f14a3-5639-4054-8c23-54af891669db "key was compromised"
{
"tag": "Revoke",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "f54f14a3-5639-4054-8c23-54af891669db"
},
{
"tag": "RevocationReason",
"type": "TextString",
"value": "key was compromised"
}
]
}
{
"tag": "RevokeResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "f54f14a3-5639-4054-8c23-54af891669db"
}
]
}
Specification
The Sign operation requests the server to generate a digital signature for the provided data using a specified Managed Object.
The request contains the unique identifier of the signing key, data to be signed (or already digested data), and cryptographic parameters. The signature is computed using the specified signing key and cryptographic parameters.
The SignatureVerify operation validates a digital signature against provided data using a specified verification key.
Implementation
The Eviden KMS server supports signing with RSA and EC private keys. The signature algorithms supported include:
- RSA-PKCS#1 v1.5 with SHA-256, SHA-384, SHA-512
- RSA-PSS with SHA-256, SHA-384, SHA-512
- ECDSA with SHA-256, SHA-384, SHA-512
- Ed25519 (signature verification only for imported keys)
Example - Sign with RSA Private Key
Sign data using an RSA private key with SHA-256.
Note: Sign and SignatureVerify operations are available through the KMIP JSON API endpoint but not directly exposed through CLI subcommands. Use direct HTTP requests to the /kmip/2_1 endpoint.
{
"tag": "Sign",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "9382bfec-bd6c-46ed-8f00-90b467f77a15"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "DigitalSignatureAlgorithm",
"type": "Enumeration",
"value": "SHA256WithRSAEncryption"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "48656C6C6F2C207369676E61747572652074657374"
},
{
"tag": "InitIndicator",
"type": "Boolean",
"value": true
},
{
"tag": "FinalIndicator",
"type": "Boolean",
"value": true
}
]
}
{
"tag": "SignResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "9382bfec-bd6c-46ed-8f00-90b467f77a15"
},
{
"tag": "SignatureData",
"type": "ByteString",
"value": "3A4B5C6D7E8F901234567890ABCDEF1234567890ABCDEF1234567890ABCDEF12"
}
]
}
Example - Signature Verification
Verify a signature using the corresponding public key.
{
"tag": "SignatureVerify",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "9382bfec-bd6c-46ed-8f00-90b467f77a15_pk"
},
{
"tag": "CryptographicParameters",
"type": "Structure",
"value": [
{
"tag": "DigitalSignatureAlgorithm",
"type": "Enumeration",
"value": "SHA256WithRSAEncryption"
}
]
},
{
"tag": "Data",
"type": "ByteString",
"value": "48656C6C6F2C207369676E61747572652074657374"
},
{
"tag": "SignatureData",
"type": "ByteString",
"value": "3A4B5C6D7E8F901234567890ABCDEF1234567890ABCDEF1234567890ABCDEF12"
},
{
"tag": "InitIndicator",
"type": "Boolean",
"value": true
},
{
"tag": "FinalIndicator",
"type": "Boolean",
"value": true
}
]
}
{
"tag": "SignatureVerifyResponse",
"type": "Structure",
"value": [
{
"tag": "UniqueIdentifier",
"type": "TextString",
"value": "9382bfec-bd6c-46ed-8f00-90b467f77a15_pk"
},
{
"tag": "ValidityIndicator",
"type": "Enumeration",
"value": "Valid"
}
]
}
Usage via HTTP API
To use Sign and SignatureVerify operations, send HTTP POST requests to the /kmip/2_1 endpoint:
# Sign operation example
curl -X POST -H "Content-Type: application/json" \
-d '{
"tag": "RequestMessage",
"value": [
{
"tag": "RequestHeader",
"value": [
{
"tag": "ProtocolVersion",
"value": [
{"tag": "ProtocolVersionMajor", "type": "Integer", "value": 2},
{"tag": "ProtocolVersionMinor", "type": "Integer", "value": 1}
]
},
{"tag": "BatchCount", "type": "Integer", "value": 1}
]
},
{
"tag": "BatchItem",
"value": [
{"tag": "Operation", "type": "Enumeration", "value": "Sign"},
{
"tag": "RequestPayload",
"value": [
{"tag": "UniqueIdentifier", "type": "TextString", "value": "your-key-id"},
{"tag": "Data", "type": "ByteString", "value": "48656C6C6F"}
]
}
]
}
]
}' \
http://localhost:9998/kmip/2_1
Streaming Support
Both Sign and SignatureVerify operations support streaming for large data:
- Set
InitIndicator: trueto start streaming - Use
CorrelationValueto continue streaming sessions - Set
FinalIndicator: trueto complete the operation
KMS Performance Comparison
Versions: v5.24.0
Generated: 2026-07-09
Benchmark Environment
| Field | Value |
|---|---|
| Date | 2026-07-09 13:28:17 UTC |
| Build | release / non-fips |
| Database | SQLite (temporary, single benchmark run) |
| CPU | Intel(R) Core(TM) i9-14900T @ 3,302 MHz |
| CPU cores | 24 physical / 32 logical (HT) |
| RAM | 31.1 GB |
| OS | Ubuntu 24.04.4 LTS |
| Kernel | 6.8.0-134-generic |
Load test parameters
| Parameter | Value |
|---|---|
| Mode | all |
| Protocols | all |
| Measurement window | 20 s per concurrency level |
| Concurrency levels | 1,2,4,8,16 |
| Warm-up | 5 s |
| Cooldown between levels | 2 s |
CPU detail (lscpu)
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 46 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 32
On-line CPU(s) list: 0-31
Vendor ID: GenuineIntel
Model name: Intel(R) Core(TM) i9-14900T
CPU family: 6
Model: 183
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 1
Stepping: 1
CPU(s) scaling MHz: 33%
CPU max MHz: 5500,0000
CPU min MHz: 800,0000
BogoMIPS: 2227,20
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr ibt flush_l1d arch_capabilities ibpb_exit_to_user
Virtualization: VT-x
L1d cache: 896 KiB (24 instances)
L1i cache: 1,3 MiB (24 instances)
L2 cache: 32 MiB (12 instances)
L3 cache: 36 MiB (1 instance)
NUMA node(s): 1
NUMA node0 CPU(s): 0-31
Vulnerability Gather data sampling: Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Mmio stale data: Not affected
Vulnerability Reg file data sampling: Mitigation; Clear Register File
Vulnerability Retbleed: Not affected
Vulnerability Spec rstack overflow: Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S
Vulnerability Srbds: Not affected
Vulnerability Tsa: Not affected
Vulnerability Tsx async abort: Not affected
Vulnerability Vmscape: Mitigation; IBPB before exit to userspace
Protocols
The KMS server was exercised over three distinct wire protocols. Each benchmark column is labelled with the protocol name it used.
| Protocol | Transport | Encoding | Endpoint | Description |
|---|---|---|---|---|
| ttlv-json | HTTP/1.1 | KMIP 2.1 JSON-TTLV | POST /kmip/2_1 | Primary interoperability protocol — any KMIP 2.1 compliant client can use it |
| ttlv-bytes | HTTP/1.1 | KMIP 2.1 binary TTLV | POST /kmip | Binary wire format; eliminates JSON parsing overhead — typically 10–30 % faster |
| jose | HTTP/1.1 | JWE / JWS (JOSE) | POST /v1/crypto/ | REST API for OAuth2/OIDC workloads that prefer JWA algorithm identifiers over KMIP |
KMIP TTLV (Tag-Type-Length-Value) is the native encoding of the KMIP 2.1 standard (OASIS KMIP Spec v2.1, §9.1). The JSON variant wraps every field in a {"tag": …, "type": …, "value": …} JSON object and base64-encodes binary values. The binary variant uses a compact 8-byte fixed header (3-byte tag, 1-byte type, 4-byte length) per value, removing JSON tokenisation, base64, and UTF-8 overhead entirely.
JOSE (JSON Object Signing and Encryption, RFC 7516 / RFC 7515) exposes KMS key material through /v1/crypto/ REST endpoints. It is used by cloud integrations (Google CSE, Microsoft DKE, Azure EKM) and any workload that speaks JWA algorithm identifiers (A256GCM, RS256, ES384 …) rather than KMIP semantics.
Benchmark Methodology
Plaintext / payload sizes
All encrypt/decrypt benchmarks use a fixed-size random payload. Sizes represent a realistic key-wrapping or small-message encryption workload without introducing significant data-transfer overhead on a loopback connection.
| Algorithm / category | Plaintext size | Notes |
|---|---|---|
| AES-GCM (128 / 192 / 256-bit key) | 64 bytes | FIPS 140-3 |
| AES-GCM-SIV (128 / 256-bit key) | 64 bytes | Non-FIPS |
| AES-XTS (128 / 256-bit AES = 256 / 512-bit key) | 64 bytes | FIPS 140-3; requires 16-byte IV |
| ChaCha20-Poly1305 (256-bit key) | 64 bytes | Non-FIPS |
| ECIES — P-256 / P-384 / P-521 | 64 bytes | Non-FIPS; EC public-key encryption |
| Salsa Sealed Box (X25519) | 64 bytes | Non-FIPS |
| Covercrypt (attribute-based encryption) | 64 bytes | Non-FIPS |
JOSE JWE — dir + AES-GCM (A128GCM / A192GCM / A256GCM) | 64 bytes | Symmetric (direct key agreement) |
| JOSE JWE — RSA-OAEP + AES-GCM (2048 / 4096-bit) | 64 bytes | Asymmetric (RSA-OAEP CEK wrapping) |
| RSA-OAEP (2048 / 3072 / 4096-bit) | 32 bytes | Limited by RSA block size |
| RSA-PKCS#1 v1.5 (2048 / 3072 / 4096-bit) | 32 bytes | Non-FIPS |
| RSA-AES Key Wrap — KWP (2048 / 3072 / 4096-bit) | 32 bytes | FIPS 140-3 |
| Sign / Verify — all algorithms | 32 bytes | Message is hashed internally |
| JOSE JWS / MAC | 32 bytes |
Load test (ckms bench --load)
The load test sweeps a configurable list of concurrency levels. At each level N concurrent async tasks send pre-serialised requests in tight loops for a fixed measurement window (default: 20 s), preceded by a warm-up phase (default: 5 s) that is excluded from measurements. Pre-serialisation happens once at setup time and the same bytes are reused on every iteration, isolating server-side KMS latency from client-side encoding overhead. Recorded metrics per (protocol, operation, concurrency) triple:
- Throughput — requests per second (req/s)
- p50 / p95 / p99 — round-trip latency percentiles (ms)
Criterion micro-benchmarks (ckms bench)
Criterion (Rust, v0.5) measures the round-trip latency of a single request from the ckms client library through the KMS server and back over a loopback TCP connection. The server is started once and kept alive across all benchmarks in the suite.
The reported value is the mean ± 95 % confidence interval over a configurable number of samples (preset quick: 3 s warm-up + 5 s measurement per benchmark).
Infrastructure note: Both test types use a local SQLite backend (temporary, discarded after the run). This isolates pure cryptographic and KMIP serialisation overhead from database I/O. Throughput figures will differ on a production deployment backed by PostgreSQL or Redis-Findex.
Load Tests
encrypt/aes-gcm
| Concurrency | ttlv-json (req/s) | ttlv-bytes (req/s) | jose (req/s) |
|---|---|---|---|
| 1 | 1,655 | 16,036 | 35,238 |
| 2 | 8,736 | 28,303 | 62,117 |
| 4 | 15,919 | 42,097 | 90,314 |
| 8 | 24,447 | 52,235 | 105,688 |
| 16 | 32,661 | 58,492 | 89,942 |
sign-verify/ecdsa-p256
| Concurrency | ttlv-json (req/s) | ttlv-bytes (req/s) | jose (req/s) |
|---|---|---|---|
| 1 | 1,902 | 4,601 | 4,840 |
| 2 | 3,579 | 8,421 | 8,899 |
| 4 | 7,214 | 13,683 | 14,240 |
| 8 | 12,598 | 19,260 | 20,329 |
| 16 | 18,646 | 26,443 | 28,094 |
key-creation/aes-sym
| Concurrency | ttlv-json (req/s) |
|---|---|
| 1 | 2,292 |
| 2 | 3,743 |
| 4 | 3,199 |
| 8 | 3,462 |
| 16 | 3,487 |
batch/aes-gcm-10
| Concurrency | ttlv-json (req/s) |
|---|---|
| 1 | 1,631 |
| 2 | 2,924 |
| 4 | 4,767 |
| 8 | 6,072 |
| 16 | 7,932 |
Criterion Benchmarks
Symmetric Encryption
| Benchmark | ttlv-json | ttlv-bytes | jose |
|---|---|---|---|
| aes-gcm-siv/decrypt/128 | 46.3 µs | 47.1 µs | — |
| aes-gcm-siv/decrypt/256 | 45.1 µs | 38.1 µs | — |
| aes-gcm-siv/encrypt/128 | 49.8 µs | 59.8 µs | — |
| aes-gcm-siv/encrypt/256 | 42.6 µs | 45.6 µs | — |
| aes-gcm/decrypt/128 | 75.3 µs | 47.8 µs | 32.5 µs |
| aes-gcm/decrypt/192 | 41.4 µs | 53.1 µs | 31.6 µs |
| aes-gcm/decrypt/256 | 46.2 µs | 61.4 µs | 30.6 µs |
| aes-gcm/encrypt/128 | 38.5 µs | 47.4 µs | 37.3 µs |
| aes-gcm/encrypt/192 | 51.9 µs | 56.2 µs | 32.4 µs |
| aes-gcm/encrypt/256 | 58.3 µs | 49.8 µs | 32.2 µs |
| aes-xts/decrypt/128 | 47.8 µs | 47.6 µs | — |
| aes-xts/decrypt/256 | 46.2 µs | 53.8 µs | — |
| aes-xts/encrypt/128 | 44.5 µs | 44.9 µs | — |
| aes-xts/encrypt/256 | 45.9 µs | 46.5 µs | — |
| chacha20-poly1305/decrypt/256 | 45.2 µs | 42.4 µs | — |
| chacha20-poly1305/encrypt/256 | 46.5 µs | 39.1 µs | — |
| salsa-sealed-box/decrypt | 116.9 µs | 100.7 µs | — |
| salsa-sealed-box/encrypt | 167.5 µs | 458.73 ms | — |
Asymmetric Encryption
| Benchmark | ttlv-json | ttlv-bytes | jose |
|---|---|---|---|
| covercrypt/decrypt | 253.6 µs | 232.8 µs | — |
| covercrypt/encrypt | 287.7 µs | 536.10 ms | — |
| ecies/decrypt/P-256 | 126.5 µs | 109.5 µs | — |
| ecies/decrypt/P-384 | 1.03 ms | 947.9 µs | — |
| ecies/decrypt/P-521 | 2.29 ms | — | — |
| ecies/encrypt/P-256 | 194.6 µs | 467.52 ms | — |
| ecies/encrypt/P-384 | 1.09 ms | 536.21 ms | — |
| ecies/encrypt/P-521 | 2.40 ms | 477.34 ms | — |
| rsa-aes-kwp/decrypt/4096 | 174.76 ms | 168.30 ms | — |
| rsa-aes-kwp/encrypt/4096 | 177.2 µs | 531.17 ms | — |
| rsa-oaep/decrypt/2048 | — | — | 23.02 ms |
| rsa-oaep/decrypt/4096 | 178.91 ms | 167.20 ms | 167.28 ms |
| rsa-oaep/encrypt/2048 | — | — | 93.5 µs |
| rsa-oaep/encrypt/4096 | 164.6 µs | 531.28 ms | 143.7 µs |
| rsa-pkcs1v15/decrypt/4096 | 177.32 ms | 167.42 ms | — |
| rsa-pkcs1v15/encrypt/4096 | 155.7 µs | 492.94 ms | — |
Key Encapsulation (KEM)
| Benchmark | ttlv-json | ttlv-bytes |
|---|---|---|
| configurable/decapsulate/ML-KEM-512 | 69.1 µs | 57.9 µs |
| configurable/decapsulate/ML-KEM-512/P-256 | 63.4 µs | — |
| configurable/decapsulate/ML-KEM-768 | 72.4 µs | 66.4 µs |
| configurable/decapsulate/ML-KEM-768/P-256 | 77.8 µs | — |
| configurable/encapsulate/ML-KEM-512 | 147.9 µs | 469.28 ms |
| configurable/encapsulate/ML-KEM-512/P-256 | 308.0 µs | 527.73 ms |
| configurable/encapsulate/ML-KEM-768 | 167.7 µs | 462.83 ms |
| configurable/encapsulate/ML-KEM-768/P-256 | 370.7 µs | — |
| pqc/decapsulate/ML-KEM-1024 | 129.6 µs | — |
| pqc/decapsulate/ML-KEM-512 | 94.5 µs | 88.0 µs |
| pqc/decapsulate/ML-KEM-768 | 108.6 µs | 91.9 µs |
| pqc/decapsulate/X25519MLKEM768 | 182.9 µs | — |
| pqc/encapsulate/ML-KEM-1024 | 194.5 µs | 480.22 ms |
| pqc/encapsulate/ML-KEM-512 | 196.6 µs | 453.94 ms |
| pqc/encapsulate/ML-KEM-768 | 230.6 µs | 531.89 ms |
| pqc/encapsulate/X25519MLKEM768 | 244.3 µs | — |
Key Creation
| Benchmark | ttlv-json |
|---|---|
| EC/ES256 | — |
| EC/ES384 | — |
| RSA/2048 | — |
| aes-gcm/oct/128 | — |
| aes-gcm/oct/256 | — |
| covercrypt/master-keypair | 706.9 µs |
| ec/ed25519 | 368.5 µs |
| ec/ed448 | 490.0 µs |
| ec/p256 | 352.0 µs |
| ec/p384 | 822.5 µs |
| ec/p521 | 1.64 ms |
| ec/secp256k1 | 574.3 µs |
| kem/ML-KEM-512 | 371.8 µs |
| kem/ML-KEM-512/P-256 | 499.2 µs |
| kem/ML-KEM-512/X25519 | 338.1 µs |
| kem/ML-KEM-768 | 425.3 µs |
| kem/ML-KEM-768/P-256 | 465.5 µs |
| kem/ML-KEM-768/X25519 | 378.7 µs |
| pqc/ML-DSA-44 | 500.6 µs |
| pqc/ML-DSA-65 | 532.0 µs |
| pqc/ML-DSA-87 | 581.3 µs |
| pqc/ML-KEM-1024 | 418.3 µs |
| pqc/ML-KEM-512 | 385.9 µs |
| pqc/ML-KEM-768 | 410.1 µs |
| pqc/X25519MLKEM768 | 300.2 µs |
| pqc/X448MLKEM1024 | 436.4 µs |
| rsa/rsa-4096 | 515.10 ms |
| symmetric/aes-128 | 237.3 µs |
| symmetric/aes-192 | 224.6 µs |
| symmetric/aes-256 | 269.6 µs |
| symmetric/chacha20-256 | 242.2 µs |
Sign / Verify
| Benchmark | ttlv-json | ttlv-bytes | jose |
|---|---|---|---|
| ecdsa-p256/sign | 263.6 µs | 234.9 µs | 231.5 µs |
| ecdsa-p256/verify | 557.86 ms | 1.01 s | 1.18 s |
| ecdsa-p384/sign | 1.17 ms | 966.6 µs | 998.1 µs |
| ecdsa-p384/verify | 554.38 ms | 1.12 s | 1.17 s |
| ecdsa-p521/sign | 2.50 ms | 2.62 ms | — |
| ecdsa-p521/verify | 548.90 ms | 1.10 s | — |
| ecdsa-secp256k1/sign | 351.7 µs | 356.5 µs | — |
| ecdsa-secp256k1/verify | 474.97 ms | 1.02 s | — |
| eddsa-ed25519/sign | 87.0 µs | 92.0 µs | 87.3 µs |
| eddsa-ed25519/verify | 466.31 ms | 1.03 s | 1.03 s |
| eddsa-ed448/sign | 303.4 µs | 290.9 µs | — |
| eddsa-ed448/verify | 530.69 ms | 1.17 s | — |
| ml-dsa/sign/44 | 511.8 µs | 458.9 µs | — |
| ml-dsa/sign/65 | 814.0 µs | 766.5 µs | — |
| ml-dsa/sign/87 | 1.00 ms | — | — |
| ml-dsa/verify/44 | 536.02 ms | 1.16 s | — |
| ml-dsa/verify/65 | 470.30 ms | 1.03 s | — |
| ml-dsa/verify/87 | 480.09 ms | — | — |
| rsa-pkcs1v15/sign | — | — | 23.42 ms |
| rsa-pkcs1v15/verify | — | — | 1.16 s |
| rsa-pss/sign | — | — | 24.11 ms |
| rsa-pss/sign/4096 | 181.90 ms | 172.64 ms | — |
| rsa-pss/verify | — | — | 1.02 s |
| rsa-pss/verify/4096 | 532.30 ms | 1.18 s | — |
| slh-dsa/sign/SHA2-128f | 10.41 ms | 9.52 ms | — |
| slh-dsa/sign/SHA2-256f | 37.66 ms | 34.76 ms | — |
| slh-dsa/sign/SHAKE-128f | 26.75 ms | — | — |
| slh-dsa/verify/SHA2-128f | 543.67 ms | 1.02 s | — |
| slh-dsa/verify/SHA2-256f | 487.30 ms | 1.18 s | — |
| slh-dsa/verify/SHAKE-128f | 477.53 ms | — | — |
CPU Scaling & Flamegraph Analysis
This page documents the multi-CPU scaling characteristics of the Cosmian KMS and explains how to reproduce the results and generate flamegraphs yourself.
Why this matters
A KMS deployed in production must handle concurrent cryptographic requests from many clients at the same time. To justify a multi-core deployment (and to rule out serialisation bottlenecks such as global mutexes or single-threaded database queues), we measure:
- Throughput scaling – how req/s grows as the number of actix-web worker threads increases from 1 → 2 → 4 → 8.
- CPU hotspot profile – a flamegraph confirming that the dominant cost is the cryptographic operation itself, not infrastructure overhead (routing, serialisation, database, locks).
Methodology
Server worker count
The KMS exposes a --server-workers N / KMS_SERVER_WORKERS configuration option that pins
the number of actix-web OS threads. Setting it explicitly makes the bench deterministic regardless
of the host's logical CPU count.
# kms.toml – leave unset to default to one thread per logical CPU
# server_workers = 8
Benchmark design
The http_throughput Criterion bench (located at
crate/test_kms_server/benches/http_throughput.rs) exercises three representative KMIP operations:
| Operation | Why chosen |
|---|---|
| AES-256-GCM encrypt | Lightweight, high-frequency – reveals OS-thread dispatch overhead |
| RSA-2048 OAEP decrypt | CPU-heavy asymmetric – shows scaling of the OpenSSL thread pool |
| ECDSA P-256 sign | CPU-heavy, short messages – reveals lock contention on key material |
For each worker count in {1, 2, 4, 8}:
- A fresh in-process KMS is started with
server_workers = Nand SQLite on/dev/shm(tmpfs). - Cryptographic keys are pre-created (not timed).
- 16 concurrent
reqwestHTTP tasks are dispatched per Criterion iteration viaiter_custom + join_all, so the server is always saturated. - Criterion reports wall-clock throughput in elements/s (= concurrent requests per second).
Flamegraph generation
Flamegraphs are recorded with
cargo-flamegraph (Linux perf back-end) and
rendered to PNG with rsvg-convert (part of
librsvg2-bin). They are generated for all three operations above at 1, 2, 4, and 8 workers.
Why
rsvg-convertand notconvert/ImageMagick? ImageMagick delegates SVG rasterisation torsvg-convertinternally; if that binary is missing,convertsilently falls back to a blank canvas, producing fully-black PNGs. Always invokersvg-convertdirectly.
To reproduce locally (Linux only, requires perf and rsvg-convert):
# Install cargo-flamegraph and rsvg-convert once
cargo install flamegraph --locked
sudo apt-get install -y librsvg2-bin
# Allow perf for unprivileged processes (revert after benchmarking)
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
# Build and profile – SVG lands next to this file
CARGO_PROFILE_BENCH_DEBUG=true \
cargo flamegraph \
--bench http_throughput \
-p test_kms_server \
--features non-fips \
--output documentation/docs/benchmarks/flamegraph/ecdsa_sign/w8/ecdsa_sign_w8.svg \
-- \
--bench \
"ecdsa_sign/w8" \
--profile-time 15
# Render the interactive SVG to a static PNG for the docs page
rsvg-convert --output documentation/docs/benchmarks/flamegraph/ecdsa_sign/w8/ecdsa_sign_w8.png \
documentation/docs/benchmarks/flamegraph/ecdsa_sign/w8/ecdsa_sign_w8.svg
Running the throughput benchmark
# Non-FIPS mode (all three operations)
cargo bench --bench http_throughput -p test_kms_server --features non-fips
# FIPS mode
cargo bench --bench http_throughput -p test_kms_server
Criterion writes an HTML report to target/criterion/kms_bench/ (also copied to flamegraph/ here).
Interpreting the results
What near-linear scaling looks like
If the KMS scales well, throughput doubles when the worker count doubles:
| Workers | Expected throughput (relative) |
|---|---|
| 1 | 1× baseline |
| 2 | ~1.9× |
| 4 | ~3.6× |
| 8 | ~6–7× (NUMA / HT effects) |
Sub-linear but monotonically increasing throughput is normal and expected:
- HTTP keep-alive and connection pooling overhead does not scale perfectly.
- SQLite WAL mode serialises writes but allows concurrent reads.
- OpenSSL's FIPS provider has per-context locking.
Flat or decreasing throughput would indicate a bottleneck worth investigating.
Reading a flamegraph
A flamegraph shows where CPU time is spent, stacked by call depth.
- Wide frames at the top = the dominant cost; you want to see
openssl/ring/cosmian_kms_cryptohere. - Wide frames in the middle = infrastructure cost;
actix-rt,tokio,serde_json,sqlxare expected but should be narrow compared to crypto. - Wide frames at the bottom = system calls;
syscall,epoll_waitwidth grows with I/O wait (not CPU saturation).
If std::sync::Mutex or parking_lot::Mutex frames appear wide, that signals lock contention
and is a regression signal worth investigating.
CI integration
The flamegraph.yml GitHub Actions workflow runs:
- On demand via
workflow_dispatch(configurable worker counts and profile time). - Weekly (Monday 03:00 UTC) against the default branch.
- On pull requests that touch
http_config.rs,start_kms_server.rs, or the bench itself.
Artifacts uploaded per run:
| Artifact | Contents |
|---|---|
criterion-http-throughput-<run_id> | Criterion HTML report with throughput charts |
flamegraph-svgs-<run_id> | SVG flamegraphs per worker count |
http-throughput-output-<run_id> | Raw bench output (bencher format) |
Results
Generated: 2026-07-02 09:27:46 UTC KMS version: 5.24.0 (commit: a099a06e1) Variant: non-fips
Machine Info
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 46 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 32
On-line CPU(s) list: 0-31
Vendor ID: GenuineIntel
Model name: Intel(R) Core(TM) i9-14900T
CPU family: 6
Model: 183
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 1
Stepping: 1
CPU(s) scaling MHz: 32%
CPU max MHz: 5500,0000
CPU min MHz: 800,0000
BogoMIPS: 2227,20
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr ibt flush_l1d arch_capabilities ibpb_exit_to_user
Virtualization: VT-x
L1d cache: 896 KiB (24 instances)
L1i cache: 1,3 MiB (24 instances)
L2 cache: 32 MiB (12 instances)
L3 cache: 36 MiB (1 instance)
NUMA node(s): 1
NUMA node0 CPU(s): 0-31
Vulnerability Gather data sampling: Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Mmio stale data: Not affected
Vulnerability Reg file data sampling: Mitigation; Clear Register File
Vulnerability Retbleed: Not affected
Vulnerability Spec rstack overflow: Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S
Vulnerability Srbds: Not affected
Vulnerability Tsa: Not affected
Vulnerability Tsx async abort: Not affected
Vulnerability Vmscape: Mitigation; IBPB before exit to userspace
/proc/cpuinfo (first core)
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 183
model name : Intel(R) Core(TM) i9-14900T
stepping : 1
microcode : 0x133
cpu MHz : 3453.279
cache size : 36864 KB
physical id : 0
siblings : 32
core id : 0
cpu cores : 24
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr ibt flush_l1d arch_capabilities ibpb_exit_to_user
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb rfds bhi vmscape
bogomips : 2227.20
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 183
model name : Intel(R) Core(TM) i9-14900T
stepping : 1
microcode : 0x133
cpu MHz : 800.000
cache size : 36864 KB
physical id : 0
siblings : 32
core id : 0
cpu cores : 24
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr ibt flush_l1d arch_capabilities ibpb_exit_to_user
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb rfds bhi vmscape
bogomips : 2227.20
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
Throughput Results
Benchmark: http_throughput Criterion bench, 16 concurrent tasks per iteration,
worker sweep: 1 2 4 8.
| Benchmark | ~req/s |
|---|---|
| kms_bench/aes_gcm_enc/w1 | 60964 |
| kms_bench/rsa_oaep_dec/w1 | 39 |
| kms_bench/ecdsa_sign/w1 | 4962 |
| kms_bench/aes_gcm_enc/w2 | 34604 |
| kms_bench/rsa_oaep_dec/w2 | 74 |
| kms_bench/ecdsa_sign/w2 | 7575 |
| kms_bench/aes_gcm_enc/w4 | 23583 |
| kms_bench/rsa_oaep_dec/w4 | 126 |
| kms_bench/ecdsa_sign/w4 | 8273 |
| kms_bench/aes_gcm_enc/w8 | 82561 |
| kms_bench/rsa_oaep_dec/w8 | 153 |
| kms_bench/ecdsa_sign/w8 | 13805 |
How to Reproduce
# Full run (throughput + flamegraphs for the default worker sweep)
mise bench:flamegraph
# Throughput only (no perf/flamegraph)
mise bench:flamegraph --skip-flamegraph
# Flamegraph for 8 workers only (skip throughput bench)
mise bench:flamegraph --workers 8 --skip-throughput
# Choose variant
mise bench:flamegraph --variant non-fips
Flamegraphs
Generated by cargo-flamegraph / Linux perf during a 15-second profiling window,
for each operation and worker count. Click a PNG's caption link to open the interactive SVG
(zoom, search) in a browser.
aes_gcm_enc
Flamegraphs not yet regenerated. Criterion throughput data is available in the Criterion report. Run
mise bench:flamegraphto populate flamegraphs here.
rsa_oaep_dec
Flamegraphs not yet regenerated. Criterion throughput data is available in the Criterion report. Run
mise bench:flamegraphto populate flamegraphs here.
ecdsa_sign
1 worker(s)

2 worker(s)

4 worker(s)

8 worker(s)

Criterion Report
The full interactive Criterion HTML report is in flamegraph/.
It is structured in four levels:
| Path | Contents |
|---|---|
flamegraph/report/ | Group overview — all 3 operations × 4 worker counts |
flamegraph/<operation>/report/ | Per-operation summary — throughput curve across worker counts |
flamegraph/<operation>/<workers>/report/ | Individual benchmark — timing distribution, regression analysis |
flamegraph/<operation>/<workers>/ | Flamegraph SVG + PNG — CPU hotspot profile for this operation at this concurrency |
Each <operation>/<workers>/ directory contains:
base//new/— Criterion raw measurement data (JSON)report/— Criterion HTML report (timing distribution, regression analysis)*.svg/*.png— flamegraph (generated bycargo-flamegraph)
Cosmian Command Line Interface (CLI)
KMS CLI is the Command Line Interface to drive KMS.
KMS CLI provides a powerful interface to manage and secure your cryptographic keys and secrets using the Cosmian Key Management System KMS. The KMS offers a high-performance, scalable solution with unique features such as confidential execution in zero-trust environments, compliance with KMIP 2.1, and support for various cryptographic algorithms and protocols.
Beyond the CLI interface, Cosmian also provides a PKCS#11 library (libcosmian_pkcs11.so) that enables seamless integration with existing cryptographic infrastructure. This library acts as a bridge between applications requiring PKCS#11 interfaces and the Eviden KMS, providing:
- Database Encryption Support: Integration with Oracle Database Transparent Data Encryption (TDE) for automatic encryption of data at rest, either through Oracle Key Vault or direct HSM communication
- Disk Encryption Support: Compatible with popular disk encryption solutions including VeraCrypt, LUKS, and Cryhod for protecting data on storage devices
The PKCS#11 library enables organizations to leverage Cosmian's advanced cryptographic capabilities while maintaining compatibility with their existing security infrastructure and workflows.
By leveraging KMS CLI, users can seamlessly integrate advanced cryptographic functionalities and secure search capabilities into their applications, enhancing data security and privacy.
!!! info Download cosmian
Please download the latest versions for your Operating System from
the [Cosmian public packages repository](https://package.cosmian.com/kms/5.25.0/)
See below for installation instructions.
Download package and install it:
sudo apt update && sudo apt install -y wget
wget https://package.cosmian.com/kms/5.25.0/deb/amd64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_amd64.deb
sudo apt install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_amd64.deb
ckms --version
Download package and install it:
sudo apt update && sudo apt install -y wget
wget https://package.cosmian.com/kms/5.25.0/deb/arm64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_arm64.deb
sudo apt install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_arm64.deb
ckms --version
Download package and install it:
sudo dnf update && sudo dnf install -y wget
wget https://package.cosmian.com/kms/5.25.0/rpm/amd64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_x86_64.rpm
sudo dnf install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_x86_64.rpm
ckms --version
Download package and install it:
sudo dnf update && sudo dnf install -y wget
wget https://package.cosmian.com/kms/5.25.0/rpm/arm64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_aarch64.rpm
sudo dnf install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_aarch64.rpm
ckms --version
Download the DMG installer and install it:
wget https://package.cosmian.com/kms/5.25.0/dmg/arm64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl-5.25.0_arm64.dmg
sudo hdiutil attach cosmian-kms-cli-non-fips-static-openssl-5.25.0_arm64.dmg
sudo installer -pkg /Volumes/cosmian-kms-cli/cosmian-kms-cli.pkg -target /
hdiutil detach /Volumes/cosmian-kms-cli
ckms --version
On Windows, download the installer:
https://package.cosmian.com/kms/5.25.0/windows/x86_64/non-fips/static-openssl/cosmian-kms-cli-non-fips-static-openssl_5.25.0_x86_64.exe
Run the installer and add the installation directory to your PATH, then run:
ckms --version
Configuration
To communicate with the KMS, the clients ckms expect the same configuration file. Please read the configuration section.
Usage
Command Line Interface used to manage the Cosmian KMS server.
If any assistance is needed, please either visit the Cosmian technical documentation at https://docs.cosmian.com
or contact the Cosmian support team on Discord https://discord.com/invite/7kPMNtHpnz
Usage: ckms [OPTIONS] <COMMAND>
Commands:
access-rights Manage the users' access rights to the cryptographic objects
attributes Get/Set/Delete/Modify the KMIP object attributes
azure Support for Azure specific interactions
aws Support for AWS specific interactions
bench Run benchmarks using criterion for statistical analysis.
cc Manage Covercrypt keys and policies. Rotate attributes. Encrypt and decrypt data
fpe Manage FPE keys and perform FPE encryption/decryption through KMIP Encrypt/Decrypt
pqc Manage post-quantum keys (ML-KEM, ML-DSA, Hybrid KEM, SLH-DSA). Encapsulate, decapsulate, sign, and verify
tokenize Anonymization utilities: hash, noise, word masking, pattern masking, aggregation, and scaling
certificates Manage certificates. Create, import, destroy and revoke. Encrypt and decrypt data
cng Manage the Windows CNG Key Storage Provider (KSP)
derive-key Derive a new key from an existing key
ec Manage elliptic curve keys. Encrypt and decrypt data using ECIES
google Manage google elements. Handle key pairs and identities from Gmail API
locate Locate cryptographic objects inside the KMS
login Login to the Identity Provider of the KMS server using the `OAuth2` authorization code flow.
logout Logout from the Identity Provider
hash Hash arbitrary data.
mac MAC utilities: compute or verify a MAC value.
rng RNG utilities: retrieve random bytes or seed RNG
server Server-related commands
rsa Manage RSA keys. Encrypt and decrypt data using RSA keys
opaque-object Create, import, export, revoke and destroy Opaque Objects
pkcs11 Verify PKCS#11 shared library integration
secret-data Create, import, export and destroy secret data
sym Manage symmetric keys. Encrypt and decrypt data
markdown Regenerate the CLI documentation in Markdown format
configure Configure the KMS CLI (create ckms.toml)
help Print this message or the help of the given subcommand(s)
Options:
-c, --conf-path <CONF_PATH>
Configuration file location
This is an alternative to the env variable `CKMS_CONF_PATH`. Takes precedence over `CKMS_CONF_PATH` env variable.
[env: CKMS_CONF_PATH=]
--url <URL>
The URL of the KMS
[env: KMS_DEFAULT_URL=]
--print-json
Output the KMS JSON KMIP request and response. This is useful to understand JSON POST requests and responses required to programmatically call the KMS on the `/kmip/2_1` endpoint
--accept-invalid-certs
Allow to connect using a self-signed cert or untrusted cert chain
`accept_invalid_certs` is useful if the CLI needs to connect to an HTTPS KMS server running an invalid or insecure SSL certificate
-H, --header <NAME: VALUE>
Add a custom HTTP header to every request sent to the KMS server.
The header must be specified in `"Name: Value"` format, matching the
curl `-H` / `--header` convention. This option may be repeated to add
multiple headers.
The environment variable `CLI_HEADER` may also be used; separate
multiple headers with a newline character.
Example: `--header "cf-access-token: <token>"`
[env: CLI_HEADER=]
--proxy-url <PROXY_URL>
The proxy URL:
- e.g., `https://secure.example` for an HTTP proxy
- e.g., `socks5://192.168.1.1:9000` for a SOCKS proxy
[env: CLI_PROXY_URL=]
--proxy-basic-auth-username <PROXY_BASIC_AUTH_USERNAME>
Set the Proxy-Authorization header username using Basic auth.
[env: CLI_PROXY_BASIC_AUTH_USERNAME=]
--proxy-basic-auth-password <PROXY_BASIC_AUTH_PASSWORD>
Set the Proxy-Authorization header password using Basic auth.
[env: CLI_PROXY_BASIC_AUTH_PASSWORD=]
--proxy-custom-auth-header <PROXY_CUSTOM_AUTH_HEADER>
Set the Proxy-Authorization header to a specified value.
[env: CLI_PROXY_CUSTOM_AUTH_HEADER=]
--proxy-exclusion-list <PROXY_EXCLUSION_LIST>
The No Proxy exclusion list to this Proxy
[env: CLI_PROXY_NO_PROXY=]
-h, --help
Print help (see a summary with '-h')
-V, --version
Print version
Web UI
The KMS server ships with a built-in browser-based client that covers the same operations as the ckms CLI. It is available at:
https://YOUR_KMS_URL/ui
No installation is required — the UI is served directly by the KMS server.
Authentication is handled automatically: the UI detects the server's configured method and adapts its login flow accordingly:
- OIDC / JWT: a LOGIN button redirects to the identity provider.
- mTLS (client certificate): the browser negotiates the TLS handshake using a certificate installed in the system or browser store. No extra configuration is needed on the client side.
- No authentication: direct access, with a warning banner indicating that the server is unsecured.
For server-side configuration and browser certificate installation steps, see the KMS User Interface configuration guide.
Download package and install it:
sudo apt update && sudo apt install -y wget
wget https://package.cosmian.com/kms/5.25.0/deb/amd64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_amd64.deb
sudo apt install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_amd64.deb
ckms --version
Download package and install it:
sudo apt update && sudo apt install -y wget
wget https://package.cosmian.com/kms/5.25.0/deb/arm64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_arm64.deb
sudo apt install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_arm64.deb
ckms --version
Download package and install it:
sudo dnf update && sudo dnf install -y wget
wget https://package.cosmian.com/kms/5.25.0/rpm/amd64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_x86_64.rpm
sudo dnf install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_x86_64.rpm
ckms --version
Download package and install it:
sudo dnf update && sudo dnf install -y wget
wget https://package.cosmian.com/kms/5.25.0/rpm/arm64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl_5.25.0_aarch64.rpm
sudo dnf install ./cosmian-kms-cli-non-fips-static-openssl_5.25.0_aarch64.rpm
ckms --version
Download the DMG installer and install it:
wget https://package.cosmian.com/kms/5.25.0/dmg/arm64/non-fips/static/cosmian-kms-cli-non-fips-static-openssl-5.25.0_arm64.dmg
sudo hdiutil attach cosmian-kms-cli-non-fips-static-openssl-5.25.0_arm64.dmg
sudo installer -pkg /Volumes/cosmian-kms-cli/cosmian-kms-cli.pkg -target /
hdiutil detach /Volumes/cosmian-kms-cli
ckms --version
On Windows, download the installer:
https://package.cosmian.com/kms/5.25.0/windows/x86_64/non-fips/static-openssl/cosmian-kms-cli-non-fips-static-openssl_5.25.0_x86_64.exe
Run the installer and add the installation directory to your PATH, then run:
ckms --version
CLI Authentication
This guide explains how to configure authentication for the KMS CLI when connecting to the KMS.
Configuration File
The CLI reads its configuration from a TOML file:
- Default location:
~/.cosmian/ckms.toml - Alternative location: Set the
CKMS_CONFenvironment variable
A basic configuration file is created automatically on first use:
[http_config]
server_url = "http://0.0.0.0:9998"
Authentication Methods
The CLI supports multiple authentication methods for the KMS:
| Method | Configuration Elements | Use Case |
|---|---|---|
| None (Default) | Only server_url | Development environments |
| Access Token | access_token | Simple API token authentication |
| TLS Client Certificate (PEM) | tls_client_pem_cert_path, tls_client_pem_key_path | Certificate-based auth — FIPS-compatible |
| TLS Client Certificate (PKCS#12) | tls_client_pkcs12_path, tls_client_pkcs12_password | Certificate-based auth — non-FIPS only |
| OAuth2/OIDC | oauth2_conf section | SSO with identity providers |
| Database Secret | database_secret | Encrypted database access |
Authenticating Using a Bearer / Access Token
When the KMS server is configured with JWT/OIDC authentication, the CLI can authenticate using a static bearer token (e.g., a short-lived JWT obtained from your identity provider) set directly in the configuration file.
[http_config]
server_url = "https://kms.example.com:9998"
# JWT bearer token sent in the Authorization: Bearer <token> header.
# Obtain from your identity provider (Google, Azure AD, Keycloak, …) or
# from ckms login after configuring the oauth2_conf section.
access_token = "<JWT_BEARER_TOKEN>"
See
test_data/configs/ckms_jwt.tomlfor a full example combiningaccess_token,oauth2_conf, anddatabase_secret.
When the server enforces an API token (a symmetric key registered server-side via
api_token_id), set the same value as access_token in the CLI config — the CLI
sends it as a bearer token and the server validates it against the registered key ID.
Authenticating Using TLS Client Certificates
When the KMS server is configured with mutual TLS (mTLS), ckms must present a client
certificate. Two formats are supported.
PEM format (FIPS-compatible, recommended)
Provide the certificate and private key as separate PEM files (.crt/.pem and .key/.pem).
This format works in both FIPS and non-FIPS builds.
[http_config]
server_url = "https://kms.example.com:9998"
accept_invalid_certs = false
# Path to the client certificate in PEM format (.crt or .pem).
# The file may contain a single leaf certificate or a full chain (leaf + intermediates).
tls_client_pem_cert_path = "/path/to/client.crt"
# Path to the client private key in PEM format (.key or .pem).
# Supported formats: PKCS#8 (-----BEGIN PRIVATE KEY-----) and traditional RSA/EC.
tls_client_pem_key_path = "/path/to/client.key"
Full example:
test_data/configs/client/pem_cert_auth.toml
Combined with a bearer token (multi-factor authentication):
[http_config]
server_url = "https://kms.example.com:9998"
accept_invalid_certs = false
tls_client_pem_cert_path = "/path/to/client.crt"
tls_client_pem_key_path = "/path/to/client.key"
# JWT bearer token sent in the Authorization: Bearer <token> header.
# Obtain from your identity provider (Google, Azure AD, Keycloak, …).
access_token = "<JWT_BEARER_TOKEN>"
Full example:
test_data/configs/client/pem_cert_and_token_auth.toml
PKCS#12 format (non-FIPS only)
Provide the certificate and private key bundled in a single PKCS#12 file (.p12).
[http_config]
server_url = "https://kms.example.com:9998"
accept_invalid_certs = false
# Path to the PKCS#12 bundle containing the client certificate and private key.
tls_client_pkcs12_path = "/path/to/client.p12"
# Password to decrypt the PKCS#12 bundle.
# Leave absent or set to "" if the bundle has no password.
tls_client_pkcs12_password = "changeit"
Full example:
test_data/configs/client/pkcs12_cert_auth.toml
Using the ckms configure wizard
Run ckms configure and choose the certificate format from the interactive menu:
Authentication method
None
Bearer token
> Client certificate (PEM) ← FIPS-compatible, recommended
Client certificate (PKCS#12) ← non-FIPS only
Both (PEM cert + token)
Both (PKCS#12 cert + token)
The wizard prompts for the certificate and key paths (PEM) or the bundle path and password (PKCS#12) and writes the result to the active configuration profile.
The KMS server authenticates the user using the Common Name (CN) field of the client
certificate's subject (e.g. CN=john.doe@example.com becomes the username).
Converting a PKCS#12 bundle to PEM
# Extract the certificate
openssl pkcs12 -in client.p12 -clcerts -nokeys -out client.crt
# Extract the private key (enter the PKCS#12 password when prompted)
openssl pkcs12 -in client.p12 -nocerts -nodes -out client.key
Common Configuration Options
Each product has its own http_config section with these options:
| Option | Description | Required |
|---|---|---|
server_url | URL of the server | Yes |
accept_invalid_certs | Accept self-signed certificates (set to "true") | No |
verified_cert | PEM certificate for pinning | No |
For KMS, you can also configure Gmail API access for S/MIME operations - see the S/MIME Gmail service account configuration.
Quick Configuration Examples
KMS with No Authentication
[http_config]
server_url = "http://127.0.0.1:9998"
OAuth2/OIDC Authentication
Basic Configuration
To authenticate using OAuth2/OIDC:
- Configure the
oauth2_confsection in your TOML file - Run
ckms loginto initiate authentication - Use
ckms logoutto clear the token
The oauth2_conf section requires:
[http_config.oauth2_conf]
client_id = "your-client-id" # Required
authorize_url = "https://idp.example.com/authorize" # Required
token_url = "https://idp.example.com/token" # Required
scopes = ["openid", "email"] # Recommended
client_secret = "your-client-secret" # Optional with PKCE
PKCE Authentication (Recommended)
PKCE (Proof Key for Code Exchange) enhances security by eliminating the need for client secrets. To use PKCE:
- Configure OAuth2 in your TOML file but omit the
client_secretfield - Ensure your identity provider supports PKCE
[http_config.oauth2_conf]
client_id = "your-client-id"
authorize_url = "https://idp.example.com/authorize"
token_url = "https://idp.example.com/token"
scopes = ["openid", "email"]
# No client_secret needed with PKCE
PKCE is recommended for:
- CLI tools
- Desktop applications
- Mobile applications
- Any client that cannot securely store secrets
Provider-Specific Examples
Microsoft Entra ID (Azure AD) with PKCE
[http_config.oauth2_conf]
client_id = "f052524e-7518-40e7-2579-219c0b48b125"
authorize_url = "https://login.microsoftonline.com/612da4de-35c0-42de-ba56-174c4e562c96/oauth2/authorize"
token_url = "https://login.microsoftonline.com/612da4de-35c0-42de-f3c6-174b69062c96/oauth2/token"
scopes = ["email", "openid"]
# No client_secret needed with PKCE
Important: In Entra ID, configure the redirect URL (http://localhost:17899/authorization) as Native/Desktop application type.
Auth0 with PKCE
[http_config.oauth2_conf]
client_id = "OUfH4FuzDAW99Ck3R4Rb7ROziOZEalIH"
authorize_url = "https://acme.eu.auth0.com/authorize"
token_url = "https://acme.eu.auth0.com/oauth/token"
scopes = ["email", "openid"]
# No client_secret needed with PKCE
Important: In Auth0, configure the application as Native and ensure the redirect URL is allowed.
Google with Traditional OAuth2
[http_config.oauth2_conf]
client_id = "99999999-abababababababababab.apps.googleusercontent.com"
client_secret = "your-client-secret" # Optional with PKCE
authorize_url = "https://accounts.google.com/o/oauth2/v2/auth"
token_url = "https://oauth2.googleapis.com/token"
scopes = ["openid", "email"]
Authentication Flow
When running ckms login:
- The CLI generates a URL to open in your browser
- You authenticate with your identity provider
- The browser redirects to a local endpoint (http://localhost:17899/authorization)
- The CLI captures the token and saves it in your configuration file
Corporate Network / Forward Proxy
When the KMS CLI is used inside a corporate network, the system HTTP proxy may intercept
outbound connections and block non-standard ports (e.g., 9998) or internal hostnames.
This typically manifests as a TunnelUnsuccessful connection error.
Note on
--proxy-exclusion-list: this CLI flag is silently ignored unless--proxy-urlis also provided. Without--proxy-url,proxy_exclusion_listis dropped and the Windows system proxy operates unconstrained. Use theckms.tomlconfiguration or environment variables for a persistent solution.
Option 1 — Environment variable (no config change needed)
Set NO_PROXY before running the CLI:
# Linux / macOS
export NO_PROXY="kms-host"
ckms kms locate
# Windows (PowerShell)
$env:NO_PROXY = "kms-host"
cosmian.exe kms locate
Option 2 — CLI flags (one-off, requires --proxy-url)
--proxy-exclusion-list only takes effect when --proxy-url is also supplied:
cosmian.exe \
--proxy-url="http://corp-proxy.example.com:8080" \
--proxy-exclusion-list="kms-host" \
kms locate
Equivalent environment variables (persist for the shell session):
export CLI_PROXY_URL="http://corp-proxy.example.com:8080"
export CLI_PROXY_NO_PROXY="kms-host,127.0.0.1,localhost"
Option 3 — ckms.toml (persistent, recommended)
Edit ~/.cosmian/ckms.toml (Windows: %USERPROFILE%\.cosmian\ckms.toml):
[http_config]
server_url = "https://kms-host:9998"
[http_config.proxy_params]
# URL of the corporate proxy (on Windows: netsh winhttp show proxy)
url = "http://corp-proxy.example.com:8080"
# Optional: Basic auth credentials for the proxy
# basic_auth_username = "DOMAIN\\username"
# basic_auth_password = "password"
# Hosts to bypass — add your KMS hostname here
exclusion_list = ["kms-host", "kms-host:9998", "127.0.0.1", "localhost"]
For a proxy requiring a custom Proxy-Authorization header:
[http_config.proxy_params]
url = "http://corp-proxy.example.com:8080"
custom_auth_header = "Bearer <proxy-token>"
exclusion_list = ["kms-host"]
Troubleshooting
- Authentication Failures: Verify client ID and URLs are correct
- PKCE Issues: Ensure your identity provider supports PKCE and has it enabled
- Redirect Errors: Check that your identity provider allows the redirect URL
- Missing Email Claim: Verify your identity provider includes the email claim in tokens
For more details about PKCE authentication, see the PKCE Authentication Guide.
Configuration file
The CLI looks for its configuration file in the following order:
- The path in the
CKMS_CONFenvironment variable (if set). ~/.cosmian/ckms.toml(user-level default)./etc/cosmian/ckms.toml(system-wide fallback).- If none of the above exists, all options must be passed as command-line arguments.
Run ckms configure to create or update the file interactively.
Minimal example
[http_config]
server_url = "http://0.0.0.0:9998"
TLS client authentication
With a PKCS#12 bundle
[http_config]
server_url = "https://kms.example.com"
ssl_client_pkcs12_path = "/path/to/client.p12"
ssl_client_pkcs12_password = "password"
With PEM certificate and key
[http_config]
server_url = "https://kms.example.com"
ssl_client_pem_cert_path = "/path/to/client.crt"
ssl_client_pem_key_path = "/path/to/client.key"
Pinning a server certificate (instead of the system CA)
[http_config]
server_url = "https://kms.example.com"
# PEM-encoded certificate expected from the server
verified_cert = "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
Accepting invalid server certificates (testing only)
[http_config]
server_url = "https://kms.example.com"
accept_invalid_certs = true
Custom HTTP headers
Some deployments place the KMS server behind a zero-trust proxy (e.g. Cloudflare
Zero Trust) that requires an extra HTTP header on every request. Use the
custom_headers field — or the --header / -H CLI flag — to pass
arbitrary headers in "Name: Value" format.
Via the configuration file
[http_config]
server_url = "https://kms.example.com"
# One or more headers in "Name: Value" format
custom_headers = [
"cf-access-token: <your-cloudflare-access-token>",
"X-Custom-Header: my-value",
]
Via the command line or environment variable
The --header (short: -H) flag mirrors curl's convention and can be
repeated for multiple headers:
# Single header
ckms --header "cf-access-token: <token>" server-version
# Multiple headers
ckms -H "cf-access-token: <token>" -H "X-Env: production" sym keys create
Set CLI_HEADER in the environment to apply headers without repeating the flag.
Multiple headers must be newline-separated:
export CLI_HEADER=$'cf-access-token: <token>\nX-Env: production'
ckms sym keys create
CLI flags merge with any custom_headers already present in ckms.toml.
Forward proxy
Route all KMS traffic through an HTTP or SOCKS proxy using
[http_config.proxy_params] in the configuration file, or via CLI flags /
environment variables.
Via the configuration file
[http_config]
server_url = "https://kms.example.com"
[http_config.proxy_params]
url = "http://proxy.corp:3128"
# Optional: exclude hosts from the proxy
exclusion_list = ["127.0.0.1", "*.internal"]
# Optional: proxy credentials — choose one of the two forms below.
# Form 1 – HTTP Basic auth
basic_auth_username = "proxyuser"
basic_auth_password = "proxypass"
# Form 2 – arbitrary Proxy-Authorization header value
# custom_auth_header = "Bearer <token>"
Via the command line
| Flag | Environment variable | Description |
|---|---|---|
--proxy-url <URL> | CLI_PROXY_URL | Proxy URL (http://, https://, socks5://) |
--proxy-basic-auth-username | CLI_PROXY_BASIC_AUTH_USERNAME | Basic-auth username |
--proxy-basic-auth-password | CLI_PROXY_BASIC_AUTH_PASSWORD | Basic-auth password |
--proxy-custom-auth-header | CLI_PROXY_CUSTOM_AUTH_HEADER | Full Proxy-Authorization header value |
--proxy-exclusion-list <HOST> | CLI_PROXY_NO_PROXY | Hosts to bypass (repeatable) |
ckms --proxy-url http://proxy.corp:3128 \
--proxy-basic-auth-username proxyuser \
--proxy-basic-auth-password proxypass \
sym keys create
Combining a proxy with custom headers
Proxy settings and custom headers are independent and can be used together:
ckms --proxy-url http://proxy.corp:3128 \
--header "cf-access-token: <token>" \
--header "X-Tenant: acme" \
sym keys create
Or fully in ckms.toml:
[http_config]
server_url = "https://kms.example.com"
custom_headers = ["cf-access-token: <token>", "X-Tenant: acme"]
[http_config.proxy_params]
url = "http://proxy.corp:3128"
OpenID Connect / OAuth2 authentication
KMS can be configured with OpenID Connect (OIDC) authentication. In that case, KMS CLI must use the oauth2_conf field to authenticate to the server.
[http_config]
server_url = "http://0.0.0.0:9998"
access_token = "eyJhbGciOiJSUz...jsFgROjPY84GRMmvpYZfyaJbDDql3A"
[http_config.oauth2_conf]
client_id = "99999999-abababababababababab.apps.googleusercontent.com"
client_secret = "XXX"
authorize_url = "https://accounts.google.com/o/oauth2/v2/auth"
token_url = "https://oauth2.googleapis.com/token"
scopes = ["openid", "email"]
Advanced options
| Key | Type | Default | Description |
|---|---|---|---|
http_config.cipher_suites | string | (platform default) | Colon-separated list of TLS cipher suites, e.g. "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256". |
print_json | bool | false | Print the raw KMIP JSON request and response for every operation. |
# Print raw KMIP JSON (useful for debugging)
print_json = true
[http_config]
server_url = "https://kms.example.com"
cipher_suites = "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"
S/MIME Gmail service account configuration for KMS server
Google Workspace can delegate encryption/decryption of Gmail (and other services such as Drive, Meet, Calendar) to an external Key Management System (KMS). In that case, the KMS can be used to encrypt and decrypt the S/MIME elements (identities, key pairs) and store them securely.
When using S/MIME, the gmail_api_conf field should be set in the configuration file to provide the necessary information about the configured service account to interact with Gmail API, and handle identities and keypairs easily from the KMS.
[http_config]
server_url = "http://0.0.0.0:9998"
access_token = "eyJhbGciOiJSUz...jsFgROjPY84GRMmvpYZfyaJbDDql3A"
[http_config.oauth2_conf]
client_id = "99999999-abababababababababab.apps.googleusercontent.com"
client_secret = "XXX"
authorize_url = "https://accounts.google.com/o/oauth2/v2/auth"
token_url = "https://oauth2.googleapis.com/token"
scopes = ["openid", "email"]
[gmail_api_conf]
type = "service_account"
project_id = "project_id"
private_key_id = "abc123abc123abc123abc123abc123abc123"
private_key = "-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----"
client_email = "xxx@yyyy.iam.gserviceaccount.com"
client_id = "12345678901234567890"
auth_uri = "https://accounts.google.com/o/oauth2/auth"
token_uri = "https://oauth2.googleapis.com/token"
auth_provider_x509_cert_url = "https://www.googleapis.com/oauth2/v1/certs"
client_x509_cert_url = "https://www.googleapis.com/robot/v1/metadata/x509/xxx%40yyyy.iam.gserviceaccount.com"
universe_domain = "googleapis.com"
Usage
Command Line Interface used to manage the Cosmian KMS server.
If any assistance is needed, please either visit the Cosmian technical documentation at https://docs.cosmian.com
or contact the Cosmian support team on Discord https://discord.com/invite/7kPMNtHpnz
Usage: ckms [OPTIONS] <COMMAND>
Commands:
access-rights Manage the users' access rights to the cryptographic objects
attributes Get/Set/Delete/Modify the KMIP object attributes
azure Support for Azure specific interactions
aws Support for AWS specific interactions
bench Run benchmarks using criterion for statistical analysis.
cc Manage Covercrypt keys and policies. Rotate attributes. Encrypt and decrypt data
fpe Manage FPE keys and perform FPE encryption/decryption through KMIP Encrypt/Decrypt
pqc Manage post-quantum keys (ML-KEM, ML-DSA, Hybrid KEM, SLH-DSA). Encapsulate, decapsulate, sign, and verify
tokenize Anonymization utilities: hash, noise, word masking, pattern masking, aggregation, and scaling
certificates Manage certificates. Create, import, destroy and revoke. Encrypt and decrypt data
cng Manage the Windows CNG Key Storage Provider (KSP)
derive-key Derive a new key from an existing key
ec Manage elliptic curve keys. Encrypt and decrypt data using ECIES
google Manage google elements. Handle key pairs and identities from Gmail API
locate Locate cryptographic objects inside the KMS
login Login to the Identity Provider of the KMS server using the `OAuth2` authorization code flow.
logout Logout from the Identity Provider
hash Hash arbitrary data.
mac MAC utilities: compute or verify a MAC value.
rng RNG utilities: retrieve random bytes or seed RNG
server Server-related commands
rsa Manage RSA keys. Encrypt and decrypt data using RSA keys
opaque-object Create, import, export, revoke and destroy Opaque Objects
pkcs11 Verify PKCS#11 shared library integration
secret-data Create, import, export and destroy secret data
sym Manage symmetric keys. Encrypt and decrypt data
markdown Regenerate the CLI documentation in Markdown format
configure Configure the KMS CLI (create ckms.toml)
help Print this message or the help of the given subcommand(s)
Options:
-c, --conf-path <CONF_PATH>
Configuration file location
This is an alternative to the env variable `CKMS_CONF_PATH`. Takes precedence over `CKMS_CONF_PATH` env variable.
[env: CKMS_CONF_PATH=]
--url <URL>
The URL of the KMS
[env: KMS_DEFAULT_URL=]
--print-json
Output the KMS JSON KMIP request and response. This is useful to understand JSON POST requests and responses required to programmatically call the KMS on the `/kmip/2_1` endpoint
--accept-invalid-certs
Allow to connect using a self-signed cert or untrusted cert chain
`accept_invalid_certs` is useful if the CLI needs to connect to an HTTPS KMS server running an invalid or insecure SSL certificate
-H, --header <NAME: VALUE>
Add a custom HTTP header to every request sent to the KMS server.
The header must be specified in `"Name: Value"` format, matching the
curl `-H` / `--header` convention. This option may be repeated to add
multiple headers.
The environment variable `CLI_HEADER` may also be used; separate
multiple headers with a newline character.
Example: `--header "cf-access-token: <token>"`
[env: CLI_HEADER=]
--proxy-url <PROXY_URL>
The proxy URL:
- e.g., `https://secure.example` for an HTTP proxy
- e.g., `socks5://192.168.1.1:9000` for a SOCKS proxy
[env: CLI_PROXY_URL=]
--proxy-basic-auth-username <PROXY_BASIC_AUTH_USERNAME>
Set the Proxy-Authorization header username using Basic auth.
[env: CLI_PROXY_BASIC_AUTH_USERNAME=]
--proxy-basic-auth-password <PROXY_BASIC_AUTH_PASSWORD>
Set the Proxy-Authorization header password using Basic auth.
[env: CLI_PROXY_BASIC_AUTH_PASSWORD=]
--proxy-custom-auth-header <PROXY_CUSTOM_AUTH_HEADER>
Set the Proxy-Authorization header to a specified value.
[env: CLI_PROXY_CUSTOM_AUTH_HEADER=]
--proxy-exclusion-list <PROXY_EXCLUSION_LIST>
The No Proxy exclusion list to this Proxy
[env: CLI_PROXY_NO_PROXY=]
-h, --help
Print help (see a summary with '-h')
-V, --version
Print version
ckms
Command Line Interface used to manage the Cosmian KMS server.
If any assistance is needed, please either visit the Cosmian technical documentation at https://docs.cosmian.com or contact the Cosmian support team on Discord https://discord.com/invite/7kPMNtHpnz
Usage
ckms <subcommand> [options]
Arguments
--conf-path [-c] <CONF_PATH> Configuration file location
--url <URL> The URL of the KMS
--print-json <PRINT_JSON> Output the KMS JSON KMIP request and response. This is useful to understand JSON POST requests and responses required to programmatically call the KMS on the /kmip/2_1 endpoint
Possible values: "true", "false"
--accept-invalid-certs <ACCEPT_INVALID_CERTS> Allow to connect using a self-signed cert or untrusted cert chain
Possible values: "true", "false"
--header [-H] <NAME: VALUE> Add a custom HTTP header to every request sent to the KMS server.
--proxy-url <PROXY_URL> The proxy URL:
- e.g.,
https://secure.examplefor an HTTP proxy - e.g.,
socks5://192.168.1.1:9000for a SOCKS proxy
--proxy-basic-auth-username <PROXY_BASIC_AUTH_USERNAME> Set the Proxy-Authorization header username using Basic auth.
--proxy-basic-auth-password <PROXY_BASIC_AUTH_PASSWORD> Set the Proxy-Authorization header password using Basic auth.
--proxy-custom-auth-header <PROXY_CUSTOM_AUTH_HEADER> Set the Proxy-Authorization header to a specified value.
--proxy-exclusion-list <PROXY_EXCLUSION_LIST> The No Proxy exclusion list to this Proxy
Subcommands
access-rights [1] Manage the users' access rights to the cryptographic objects
attributes [2] Get/Set/Delete/Modify the KMIP object attributes
azure [3] Support for Azure specific interactions
aws [4] Support for AWS specific interactions
bench [5] Run benchmarks using criterion for statistical analysis.
cc [6] Manage Covercrypt keys and policies. Rotate attributes. Encrypt and decrypt data
fpe [7] Manage FPE keys and perform FPE encryption/decryption through KMIP Encrypt/Decrypt
pqc [8] Manage post-quantum keys (ML-KEM, ML-DSA, Hybrid KEM, SLH-DSA). Encapsulate, decapsulate, sign, and verify
tokenize [9] Anonymization utilities: hash, noise, word masking, pattern masking, aggregation, and scaling
certificates [10] Manage certificates. Create, import, destroy and revoke. Encrypt and decrypt data
cng [11] Manage the Windows CNG Key Storage Provider (KSP)
derive-key [12] Derive a new key from an existing key
ec [13] Manage elliptic curve keys. Encrypt and decrypt data using ECIES
google [14] Manage google elements. Handle key pairs and identities from Gmail API
locate [15] Locate cryptographic objects inside the KMS
login [16] Login to the Identity Provider of the KMS server using the OAuth2 authorization code flow.
logout [17] Logout from the Identity Provider
hash [18] Hash arbitrary data.
mac [19] MAC utilities: compute or verify a MAC value.
rng [20] RNG utilities: retrieve random bytes or seed RNG
server [21] Server-related commands
rsa [22] Manage RSA keys. Encrypt and decrypt data using RSA keys
opaque-object [23] Create, import, export, revoke and destroy Opaque Objects
pkcs11 [24] Verify PKCS#11 shared library integration
secret-data [25] Create, import, export and destroy secret data
sym [26] Manage symmetric keys. Encrypt and decrypt data
markdown [27] Regenerate the CLI documentation in Markdown format
configure [28] Configure the KMS CLI (create ckms.toml)
1 ckms access-rights
Manage the users' access rights to the cryptographic objects
Usage
ckms access-rights <subcommand>
Subcommands
grant [1.1] Grant another user one or multiple access rights to an object
revoke [1.2] Revoke another user one or multiple access rights to an object
list [1.3] List the access rights granted on an object to other users
owned [1.4] List the objects owned by the calling user
obtained [1.5] List the access rights obtained by the calling user
1.1 ckms access-rights grant
Grant another user one or multiple access rights to an object
Usage
ckms access-rights grant [options] <USER> <OPERATIONS>...
Arguments
<USER> The user identifier to allow
--object-uid [-i] <OBJECT_UID> The object unique identifier stored in the KMS
<OPERATIONS> The operations to grant (create, get, encrypt, decrypt, import, revoke, locate, rekey, destroy, get_attributes)
1.2 ckms access-rights revoke
Revoke another user one or multiple access rights to an object
Usage
ckms access-rights revoke [options] <USER> <OPERATIONS>...
Arguments
<USER> The user to revoke access to
--object-uid [-i] <OBJECT_UID> The object unique identifier stored in the KMS
<OPERATIONS> The operations to revoke (create, get, encrypt, decrypt, import, revoke, locate, rekey, destroy)
1.3 ckms access-rights list
List the access rights granted on an object to other users
Usage
ckms access-rights list [options] <OBJECT_UID>
Arguments
<OBJECT_UID> The object unique identifier
1.4 ckms access-rights owned
List the objects owned by the calling user
Usage
ckms access-rights owned
1.5 ckms access-rights obtained
List the access rights obtained by the calling user
Usage
ckms access-rights obtained
2 ckms attributes
Get/Set/Delete/Modify the KMIP object attributes
Usage
ckms attributes <subcommand>
Subcommands
get [2.1] Get the KMIP object attributes and tags.
set [2.2] Set the KMIP object attributes.
delete [2.3] Delete the KMIP object attributes.
modify [2.4] Modify existing KMIP object attributes.
2.1 ckms attributes get
Get the KMIP object attributes and tags.
Usage
ckms attributes get [options]
Arguments
--id [-i] <ID> The unique identifier of the cryptographic object. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--attribute [-a] <ATTRIBUTE> The KMIP attribute to retrieve.
To specify multiple attributes, use the option multiple times.
If not specified, all possible attributes are returned.
To retrieve the tags, use Tag as an attribute value.
--link-type [-l] <LINK_TYPE> Filter on retrieved links. Only if KMIP tag LinkType is used in attribute parameter.
To specify multiple attributes, use the option multiple times.
If not specified, all possible link types are returned.
Possible values: "certificate", "public-key", "private-key", "derivation-base-object", "derived-key", "replacement-object", "replaced-object", "parent", "child", "previous", "next", "pkcs12-certificate", "pkcs12-password", "wrapping-key"
--output-file [-o] <OUTPUT_FILE> An optional file where to export the attributes.
The attributes will be in JSON TTLV format.
2.2 ckms attributes set
Set the KMIP object attributes.
Usage
ckms attributes set [options]
Arguments
--id [-i] <ID> The unique identifier of the cryptographic object. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--activation-date [-d] <ACTIVATION_DATE> Set the activation date of the key. Epoch time (or Unix time) in milliseconds
--cryptographic-algorithm [-a] <CRYPTOGRAPHIC_ALGORITHM> The cryptographic algorithm used by the key
Possible values: "aes", "rsa", "ecdsa", "ecdh", "ec", "chacha20", "chacha20-poly1305", "sha3224", "sha3256", "sha3384", "sha3512", "ed25519", "ed448", "covercrypt", "covercrypt-bulk"
--cryptographic-length <CRYPTOGRAPHIC_LENGTH> The length of the cryptographic key
--key-usage [-u] <KEY_USAGE> The key usage. Add multiple times to specify multiple key usages
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--public-key-id <PUBLIC_KEY_ID> The link to the corresponding public key id if any
--private-key-id <PRIVATE_KEY_ID> The link to the corresponding private key id if any
--certificate-id <CERTIFICATE_ID> The link to the corresponding certificate id if any
--p12-id <PKCS12_CERTIFICATE_ID> The link to the corresponding PKCS12 certificate id if any
--p12-pwd <PKCS12_PASSWORD_CERTIFICATE> The link to the corresponding PKCS12 password certificate if any
--parent-id <PARENT_ID> The link to the corresponding parent id if any
--child-id <CHILD_ID> The link to the corresponding child id if any
--name <NAME> The name of the object (standard KMIP Name attribute). The name is stored as an UninterpretedTextString by default
--vendor-identification [-v] <VENDOR_IDENTIFICATION> The vendor identification
--attribute-name [-n] <ATTRIBUTE_NAME> The attribute name
--attribute-value <ATTRIBUTE_VALUE> The attribute value (in hex format)
2.3 ckms attributes delete
Delete the KMIP object attributes.
Usage
ckms attributes delete [options]
Arguments
--id [-i] <ID> The unique identifier of the cryptographic object. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--activation-date [-d] <ACTIVATION_DATE> Set the activation date of the key. Epoch time (or Unix time) in milliseconds
--cryptographic-algorithm [-a] <CRYPTOGRAPHIC_ALGORITHM> The cryptographic algorithm used by the key
Possible values: "aes", "rsa", "ecdsa", "ecdh", "ec", "chacha20", "chacha20-poly1305", "sha3224", "sha3256", "sha3384", "sha3512", "ed25519", "ed448", "covercrypt", "covercrypt-bulk"
--cryptographic-length <CRYPTOGRAPHIC_LENGTH> The length of the cryptographic key
--key-usage [-u] <KEY_USAGE> The key usage. Add multiple times to specify multiple key usages
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--public-key-id <PUBLIC_KEY_ID> The link to the corresponding public key id if any
--private-key-id <PRIVATE_KEY_ID> The link to the corresponding private key id if any
--certificate-id <CERTIFICATE_ID> The link to the corresponding certificate id if any
--p12-id <PKCS12_CERTIFICATE_ID> The link to the corresponding PKCS12 certificate id if any
--p12-pwd <PKCS12_PASSWORD_CERTIFICATE> The link to the corresponding PKCS12 password certificate if any
--parent-id <PARENT_ID> The link to the corresponding parent id if any
--child-id <CHILD_ID> The link to the corresponding child id if any
--name <NAME> The name of the object (standard KMIP Name attribute). The name is stored as an UninterpretedTextString by default
--vendor-identification [-v] <VENDOR_IDENTIFICATION> The vendor identification
--attribute-name [-n] <ATTRIBUTE_NAME> The attribute name
--attribute-value <ATTRIBUTE_VALUE> The attribute value (in hex format)
--attribute <ATTRIBUTE> The attributes or tags to retrieve.
To specify multiple attributes, use the option multiple times.
2.4 ckms attributes modify
Modify existing KMIP object attributes.
Usage
ckms attributes modify [options]
Arguments
--id [-i] <ID> The unique identifier of the cryptographic object. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--activation-date [-d] <ACTIVATION_DATE> Set the activation date of the key. Epoch time (or Unix time) in milliseconds
--cryptographic-algorithm [-a] <CRYPTOGRAPHIC_ALGORITHM> The cryptographic algorithm used by the key
Possible values: "aes", "rsa", "ecdsa", "ecdh", "ec", "chacha20", "chacha20-poly1305", "sha3224", "sha3256", "sha3384", "sha3512", "ed25519", "ed448", "covercrypt", "covercrypt-bulk"
--cryptographic-length <CRYPTOGRAPHIC_LENGTH> The length of the cryptographic key
--key-usage [-u] <KEY_USAGE> The key usage. Add multiple times to specify multiple key usages
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--public-key-id <PUBLIC_KEY_ID> The link to the corresponding public key id if any
--private-key-id <PRIVATE_KEY_ID> The link to the corresponding private key id if any
--certificate-id <CERTIFICATE_ID> The link to the corresponding certificate id if any
--p12-id <PKCS12_CERTIFICATE_ID> The link to the corresponding PKCS12 certificate id if any
--p12-pwd <PKCS12_PASSWORD_CERTIFICATE> The link to the corresponding PKCS12 password certificate if any
--parent-id <PARENT_ID> The link to the corresponding parent id if any
--child-id <CHILD_ID> The link to the corresponding child id if any
--name <NAME> The name of the object (standard KMIP Name attribute). The name is stored as an UninterpretedTextString by default
--vendor-identification [-v] <VENDOR_IDENTIFICATION> The vendor identification
--attribute-name [-n] <ATTRIBUTE_NAME> The attribute name
--attribute-value <ATTRIBUTE_VALUE> The attribute value (in hex format)
3 ckms azure
Support for Azure specific interactions
Usage
ckms azure <subcommand>
Subcommands
byok [3.1] Azure BYOK support. See: https://learn.microsoft.com/en-us/azure/key-vault/keys/byok-specification
3.1 ckms azure byok
Azure BYOK support. See: https://learn.microsoft.com/en-us/azure/key-vault/keys/byok-specification
Usage
ckms azure byok <subcommand>
Subcommands
import [3.1.1] Import into the KMS an RSA Key Encryption Key (KEK) generated on Azure Key Vault.
See: https://learn.microsoft.com/en-us/azure/key-vault/keys/byok-specification#generate-kek
export [3.1.2] Wrap a KMS key with an Azure Key Encryption Key (KEK),
previously imported using the ckms azure byok import command.
Generate the .byok file that can be used to import the KMS key into Azure Key Vault.
See: https://learn.microsoft.com/en-us/azure/key-vault/keys/byok-specification
3.1.1 ckms azure byok import
Import into the KMS an RSA Key Encryption Key (KEK) generated on Azure Key Vault. See: https://learn.microsoft.com/en-us/azure/key-vault/keys/byok-specification#generate-kek
Usage
ckms azure byok import [options] <KEK_FILE> <KID> [KEY_ID]
Arguments
<KEK_FILE> The RSA Key Encryption Key (KEK) file exported from the Azure Key Vault in PKCS#8 PEM format
<KID> The Azure Key ID (kid). It should be something like:
https://mypremiumkeyvault.vault.azure.net/keys/KEK-BYOK/664f5aa2797a4075b8e36ca4500636d8
<KEY_ID> The unique ID of the key in this KMS; a random UUID is generated if not specified
3.1.2 ckms azure byok export
Wrap a KMS key with an Azure Key Encryption Key (KEK),
previously imported using the ckms azure byok import command.
Generate the .byok file that can be used to import the KMS key into Azure Key Vault.
See: https://learn.microsoft.com/en-us/azure/key-vault/keys/byok-specification
Usage
ckms azure byok export [options] <WRAPPED_KEY_ID> <KEK_ID> [BYOK_FILE]
Arguments
<WRAPPED_KEY_ID> The unique ID of the KMS private key that will be wrapped and then exported
<KEK_ID> The Azure KEK ID in this KMS
<BYOK_FILE> The file path to export the .byok file to. If not specified, the file will be called <wrapped_key_id>.byok
4 ckms aws
Support for AWS specific interactions
Usage
ckms aws <subcommand>
Subcommands
byok [4.1] AWS BYOK support. See: https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys-conceptual.html
4.1 ckms aws byok
AWS BYOK support. See: https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys-conceptual.html
Usage
ckms aws byok <subcommand>
Subcommands
import [4.1.1] Import an AWS Key Encryption Key (KEK) into the KMS.
export [4.1.2] Wrap a KMS key with an AWS Key Encryption Key (KEK).
4.1.1 ckms aws byok import
Import an AWS Key Encryption Key (KEK) into the KMS.
Usage
ckms aws byok import [options]
Arguments
--kek-base64 [-b] <KEK_BASE64> The RSA Key Encryption public key (the KEK) as a base64-encoded string
--kek-file [-f] <KEK_FILE> In case of KEK provided as a file blob
--wrapping-algorithm [-w] <WRAPPING_ALGORITHM>
Possible values: "RSAES_OAEP_SHA_1", "RSAES_OAEP_SHA_256", "RSA_AES_KEY_WRAP_SHA_1", "RSA_AES_KEY_WRAP_SHA_256"
--key-arn [-a] <KEY_ARN> The Amazon Resource Name (key ARN) of the KMS key. It's recommended to provide it for an easier export later
--key-id [-i] <KEY_ID> The unique ID of the key in this KMS; a random UUID is generated if not specified
4.1.2 ckms aws byok export
Wrap a KMS key with an AWS Key Encryption Key (KEK).
Usage
ckms aws byok export [options] <KEY_ID> <KEK_ID> [TOKEN_FILE_PATH] [OUTPUT_FILE_PATH]
Arguments
<KEY_ID> The unique ID of the KMS private key that will be wrapped and then exported
<KEK_ID> The AWS KEK ID in this KMS
<TOKEN_FILE_PATH> The file path containing the import token previously generated when importing the KEK. This file isn't read and neither used by the KMS, it's simply for providing copy-paste ready output for aws cli users upon a successful key material wrapping
<OUTPUT_FILE_PATH> If not specified, a base64 encoded blob containing the key material will be printed to stdout. Can be piped to desired file or command
5 ckms bench
Run benchmarks using criterion for statistical analysis.
Usage
ckms bench [options]
Arguments
--mode [-m] <MODE> Benchmark category (default: all)
Possible values: "all", "encrypt", "key-creation", "sign-verify", "batch" [default: "all"]
--protocol [-p] <PROTOCOL> Protocol / transport to benchmark (default: all). - ttlv-json: KMIP over JSON TTLV (POST /kmip/2_1) - ttlv-bytes: KMIP over binary TTLV (POST /kmip) - jose: REST JOSE endpoints (POST /v1/crypto/*)
Possible values: "all", "ttlv-json", "ttlv-bytes", "jose" [default: "all"]
--format [-f] <FORMAT> Output format
Possible values: "text", "json", "markdown", "compact", "html" [default: "text"]
--speed [-s] <SPEED> Benchmark speed mode: normal (default), quick, or sanity. Sanity auto-selects --format compact when no explicit format is given
Possible values: "normal", "quick", "sanity" [default: "normal"]
--time [-t] <TIME> Maximum measurement time per benchmark in seconds (default: 10). Caps how long criterion spends on each benchmark function. Ignored in quick and sanity speed modes
--max-group-time <MAX_GROUP_TIME> Maximum wall-clock time (in seconds) to spend per benchmark group. Once a group exceeds this budget, its remaining benchmarks are skipped (benchmarks already completed in the group are kept). Unset means no cap. Applies to the KMIP (ttlv-json / ttlv-bytes) benchmark groups
--save-baseline <SAVE_BASELINE> Save results under a named baseline in target/criterion/
--load-baseline <LOAD_BASELINE> Compare results against a previously saved baseline. Prints change% in console output for each benchmark. Example: --load-baseline before-my-change
--version-label <VERSION_LABEL> When emitting --format json, insert this label as the version column so that criterion-table renders versions as columns for proper comparison. Run baseline first, compare second, then combine: cat v5.12.json v5.17.json | criterion-table > diff.md
--load <LOAD> Run concurrent load tests instead of criterion statistical benchmarks. Measures throughput (req/s) and latency percentiles (p50/p95/p99) at increasing concurrency levels. Can be combined with --mode to focus on specific operations. Use --format html to produce a gnuplot HTML report
Possible values: "true", "false" [default: "false"]
--load-concurrency <LOAD_CONCURRENCY> Comma-separated concurrency levels for load testing. Only used when --load is set
--load-plaintext-size <LOAD_PLAINTEXT_SIZE> Plaintext size in bytes for load-test encrypt ops (default 4096). Larger payloads make the op CPU-bound (crypto + serialization dominate the fixed HTTP/loopback overhead), which is what a capacity/scaling benchmark wants; the small default keeps the op network/latency-bound
--warmup-time <WARMUP_TIME> Warmup time in seconds before benchmarking starts. Sends requests for this duration to warm HTTP connection pools, TLS sessions, and server-side caches. Set to 0 to skip
--cooldown-time <COOLDOWN_TIME> Cooldown time in seconds between load-test concurrency levels. Lets the server drain TCP TIME_WAIT sockets, checkpoint SQLite WAL, and release memory before the next level starts fresh
6 ckms cc
Manage Covercrypt keys and policies. Rotate attributes. Encrypt and decrypt data
Usage
ckms cc <subcommand>
Subcommands
keys [6.1] Create, destroy, import, export, and rekey Covercrypt master and user keys
access-structure [6.2] Extract, view, or edit policies of existing keys
encrypt [6.3] Encrypt a file using Covercrypt
decrypt [6.4] Decrypt a file using Covercrypt
6.1 ckms cc keys
Create, destroy, import, export, and rekey Covercrypt master and user keys
Usage
ckms cc keys <subcommand>
Subcommands
activate [6.1.1] Activate a cryptographic object (key, certificate, etc.)
create-master-key-pair [6.1.2] Create a new master keypair for a given access structure and return the key
IDs.
create-user-key [6.1.3] Create a new user secret key for an access policy, and index it under some
(optional) tags, that can later be used to retrieve the key.
export [6.1.4] Export a key or secret data from the KMS
import [6.1.5] Import a secret data or a key in the KMS.
wrap [6.1.6] Locally wrap a secret data or key in KMIP JSON TTLV format.
unwrap [6.1.7] Locally unwrap a secret data or key in KMIP JSON TTLV format.
revoke [6.1.8] Revoke a Covercrypt master or user decryption key
destroy [6.1.9] Destroy a Covercrypt master or user decryption key
rekey [6.1.10] Rekey the given access policy.
prune [6.1.11] Prune all keys linked to an MSK w.r.t an given access policy.
6.1.1 ckms cc keys activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms cc keys activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
6.1.2 ckms cc keys create-master-key-pair
Create a new master keypair for a given access structure and return the key IDs.
Usage
ckms cc keys create-master-key-pair [options]
Arguments
--specification [-s] <SPECIFICATION> The JSON access structure specifications file to use to generate the keys. See the inline doc of the create-master-key-pair command for details
--tag [-t] <TAG> The tag to associate with the master key pair. To specify multiple tags, use the option multiple times
--sensitive <SENSITIVE> Sensitive: if set, the private key will not be exportable
Possible values: "true", "false" [default: "false"]
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap the keypair with.
If the wrapping key is:
- a symmetric key, AES-GCM will be used
- a RSA key, RSA-OAEP will be used
- a EC key, ECIES will be used (salsa20poly1305 for X25519)
6.1.3 ckms cc keys create-user-key
Create a new user secret key for an access policy, and index it under some (optional) tags, that can later be used to retrieve the key.
Usage
ckms cc keys create-user-key [options] <MASTER_SECRET_KEY_ID> <ACCESS_POLICY>
Arguments
<MASTER_SECRET_KEY_ID> The master secret key unique identifier
<ACCESS_POLICY> The access policy should be expressed as a boolean expression of attributes. For example (provided the corresponding attributes are defined in the MSK):
--tag [-t] <TAG> The tag to associate with the user decryption key. To specify multiple tags, use the option multiple times
--sensitive <SENSITIVE> Sensitive: if set, the key will not be exportable
Possible values: "true", "false" [default: "false"]
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap the keypair with.
If the wrapping key is:
- a symmetric key, AES-GCM will be used
- a RSA key, RSA-OAEP will be used
- a EC key, ECIES will be used (salsa20poly1305 for X25519)
6.1.4 ckms cc keys export
Export a key or secret data from the KMS
Usage
ckms cc keys export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
6.1.5 ckms cc keys import
Import a secret data or a key in the KMS.
Usage
ckms cc keys import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
6.1.6 ckms cc keys wrap
Locally wrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms cc keys wrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to wrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified, the input file is overwritten
--wrap-password [-p] <WRAP_PASSWORD> A password to wrap the imported key. This password will be derived into an AES-256 symmetric key. For security reasons, a fresh salt is internally generated by cosmian and handled, and this final AES symmetric key will be displayed only once
--wrap-key-b64 [-k] <WRAP_KEY_B64> A symmetric key as a base 64 string to wrap the imported key
--wrap-key-id [-i] <WRAP_KEY_ID> The ID of a wrapping key in the KMS that will be exported and used to wrap the key
--wrap-key-file [-f] <WRAP_KEY_FILE> A wrapping key in a KMIP JSON TTLV file used to wrap the key
6.1.7 ckms cc keys unwrap
Locally unwrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms cc keys unwrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to unwrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified the input file is overwritten
--unwrap-key-b64 [-k] <UNWRAP_KEY_B64> A symmetric key as a base 64 string to unwrap the imported key
--unwrap-key-id [-i] <UNWRAP_KEY_ID> The id of an unwrapping key in the KMS that will be exported and used to unwrap the key
--unwrap-key-file [-f] <UNWRAP_KEY_FILE> An unwrapping key in a KMIP JSON TTLV file used to unwrap the key
6.1.8 ckms cc keys revoke
Revoke a Covercrypt master or user decryption key
Usage
ckms cc keys revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--key-id [-k] <KEY_ID> The key unique identifier of the key to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
6.1.9 ckms cc keys destroy
Destroy a Covercrypt master or user decryption key
Usage
ckms cc keys destroy [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--remove <REMOVE> If the key should be removed from the database
If not specified, the key will be destroyed
but its metadata will still be available in the database.
Please note that the KMIP specification does not support the removal of objects.
Possible values: "true", "false" [default: "false"]
6.1.10 ckms cc keys rekey
Rekey the given access policy.
Usage
ckms cc keys rekey [options] <ACCESS_POLICY>
Arguments
<ACCESS_POLICY> The access policy should be expressed as a boolean expression of attributes. For example (provided the corresponding attributes are defined in the MSK):
--key-id [-k] <MSK_UID> The MSK UID stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the MSK when no key id is specified. To specify multiple tags, use the option multiple times
6.1.11 ckms cc keys prune
Prune all keys linked to an MSK w.r.t an given access policy.
Usage
ckms cc keys prune [options] <ACCESS_POLICY>
Arguments
<ACCESS_POLICY> The access policy should be expressed as a boolean expression of attributes. For example (provided the corresponding attributes are defined in the MSK):
--key-id [-k] <MSK_UID> The private master key unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
6.2 ckms cc access-structure
Extract, view, or edit policies of existing keys
Usage
ckms cc access-structure <subcommand>
Subcommands
view [6.2.1] View the access structure of an existing public or private master key.
add-attribute [6.2.2] Add an attribute to the access structure of an existing private master key.
remove-attribute [6.2.3] Remove an attribute from the access structure of an existing private master key.
Permanently removes the ability to use this attribute in both encryptions and decryptions.
disable-attribute [6.2.4] Disable an attribute from the access structure of an existing private master
key.
rename-attribute [6.2.5] Rename an attribute in the access structure of an existing private master key.
6.2.1 ckms cc access-structure view
View the access structure of an existing public or private master key.
Usage
ckms cc access-structure view [options]
Arguments
--key-id [-i] <KEY_ID> The public or private master key ID if the key is stored in the KMS
--key-file [-f] <KEY_FILE> If key-id is not provided, use --key-file to provide the file containing the public or private master key in TTLV format
6.2.2 ckms cc access-structure add-attribute
Add an attribute to the access structure of an existing private master key.
Usage
ckms cc access-structure add-attribute [options] <ATTRIBUTE>
Arguments
<ATTRIBUTE> The name of the attribute to create. Example: department::rnd
--hybridized <HYBRIDIZED> Hybridize this qualified attribute
Possible values: "true", "false" [default: "false"]
--key-id [-k] <SECRET_KEY_ID> The master secret key unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
6.2.3 ckms cc access-structure remove-attribute
Remove an attribute from the access structure of an existing private master key. Permanently removes the ability to use this attribute in both encryptions and decryptions.
Usage
ckms cc access-structure remove-attribute [options] <ATTRIBUTE>
Arguments
<ATTRIBUTE> The name of the attribute to remove. Example: department::marketing Note: prevents ciphertexts only targeting this qualified attribute to be decrypted
--key-id [-k] <MASTER_SECRET_KEY_ID> The master secret key unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
6.2.4 ckms cc access-structure disable-attribute
Disable an attribute from the access structure of an existing private master key.
Usage
ckms cc access-structure disable-attribute [options] <ATTRIBUTE>
Arguments
<ATTRIBUTE> The name of the attribute to disable. Example: department::marketing
--key-id [-k] <MASTER_SECRET_KEY_ID> The master secret key unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
6.2.5 ckms cc access-structure rename-attribute
Rename an attribute in the access structure of an existing private master key.
Usage
ckms cc access-structure rename-attribute [options] <ATTRIBUTE> <NEW_NAME>
Arguments
<ATTRIBUTE> The name of the attribute to rename. Example: department::mkg
<NEW_NAME> The new name for the attribute. Example: marketing
--key-id [-k] <MASTER_SECRET_KEY_ID> The master secret key unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
6.3 ckms cc encrypt
Encrypt a file using Covercrypt
Usage
ckms cc encrypt [options] <FILE>... <ENCRYPTION_POLICY>
Arguments
<FILE> The files to encrypt
<ENCRYPTION_POLICY> The encryption policy to encrypt the file with Example: "department::marketing && level::confidential"
--key-id [-k] <KEY_ID> The public key unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
--authentication-data [-a] <AUTHENTICATION_DATA> Optional authentication data. This data needs to be provided back for decryption
6.4 ckms cc decrypt
Decrypt a file using Covercrypt
Usage
ckms cc decrypt [options] <FILE>...
Arguments
<FILE> The files to decrypt
--key-id [-k] <KEY_ID> The user key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
--authentication-data [-a] <AUTHENTICATION_DATA> Optional authentication data that was supplied during encryption
7 ckms fpe
Manage FPE keys and perform FPE encryption/decryption through KMIP Encrypt/Decrypt
Usage
ckms fpe <subcommand>
Subcommands
keys [7.1] Create, destroy, import, and export FPE keys
encrypt [7.2] Encrypt data using AES-256 FF1 format-preserving encryption through KMIP
decrypt [7.3] Decrypt data using AES-256 FF1 format-preserving encryption through KMIP
7.1 ckms fpe keys
Create, destroy, import, and export FPE keys
Usage
ckms fpe keys <subcommand>
Subcommands
create [7.1.1]
export [7.1.2] Export a key or secret data from the KMS
import [7.1.3] Import a secret data or a key in the KMS.
wrap [7.1.4] Locally wrap a secret data or key in KMIP JSON TTLV format.
unwrap [7.1.5] Locally unwrap a secret data or key in KMIP JSON TTLV format.
revoke [7.1.6] Revoke an FPE key
destroy [7.1.7] Destroy an FPE key
7.1.1 ckms fpe keys create
Usage
ckms fpe keys create [options] [KEY_ID]
Arguments
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
<KEY_ID> The unique id of the key; a random uuid is generated if not specified
--sensitive <SENSITIVE> Sensitive: if set, the key will not be exportable
Possible values: "true", "false" [default: "false"]
7.1.2 ckms fpe keys export
Export a key or secret data from the KMS
Usage
ckms fpe keys export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
7.1.3 ckms fpe keys import
Import a secret data or a key in the KMS.
Usage
ckms fpe keys import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
7.1.4 ckms fpe keys wrap
Locally wrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms fpe keys wrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to wrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified, the input file is overwritten
--wrap-password [-p] <WRAP_PASSWORD> A password to wrap the imported key. This password will be derived into an AES-256 symmetric key. For security reasons, a fresh salt is internally generated by cosmian and handled, and this final AES symmetric key will be displayed only once
--wrap-key-b64 [-k] <WRAP_KEY_B64> A symmetric key as a base 64 string to wrap the imported key
--wrap-key-id [-i] <WRAP_KEY_ID> The ID of a wrapping key in the KMS that will be exported and used to wrap the key
--wrap-key-file [-f] <WRAP_KEY_FILE> A wrapping key in a KMIP JSON TTLV file used to wrap the key
7.1.5 ckms fpe keys unwrap
Locally unwrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms fpe keys unwrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to unwrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified the input file is overwritten
--unwrap-key-b64 [-k] <UNWRAP_KEY_B64> A symmetric key as a base 64 string to unwrap the imported key
--unwrap-key-id [-i] <UNWRAP_KEY_ID> The id of an unwrapping key in the KMS that will be exported and used to unwrap the key
--unwrap-key-file [-f] <UNWRAP_KEY_FILE> An unwrapping key in a KMIP JSON TTLV file used to unwrap the key
7.1.6 ckms fpe keys revoke
Revoke an FPE key
Usage
ckms fpe keys revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--key-id [-k] <KEY_ID> The key unique identifier of the key to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
7.1.7 ckms fpe keys destroy
Destroy an FPE key
Usage
ckms fpe keys destroy [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--remove <REMOVE> If the key should be removed from the database
If not specified, the key will be destroyed
but its metadata will still be available in the database.
Please note that the KMIP specification does not support the removal of objects.
Possible values: "true", "false" [default: "false"]
7.2 ckms fpe encrypt
Encrypt data using AES-256 FF1 format-preserving encryption through KMIP
Usage
ckms fpe encrypt [options] [FILE]
Arguments
--key-id [-k] <KEY_ID> The FPE key unique identifier
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--type <DATA_TYPE> The FPE data type
Possible values: "text", "integer", "float" [default: "text"]
--alphabet <ALPHABET> The alphabet to use for encryption/decryption
--tweak <TWEAK> Optional tweak bytes as a hex string
<FILE> Input file to read from. If not specified, reads from stdin
--output-file [-o] <OUTPUT_FILE> Write the output to a file instead of stdout
7.3 ckms fpe decrypt
Decrypt data using AES-256 FF1 format-preserving encryption through KMIP
Usage
ckms fpe decrypt [options] [FILE]
Arguments
--key-id [-k] <KEY_ID> The FPE key unique identifier
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--type <DATA_TYPE> The FPE data type
Possible values: "text", "integer", "float" [default: "text"]
--alphabet <ALPHABET> The alphabet to use for encryption/decryption
--tweak <TWEAK> Optional tweak bytes as a hex string
<FILE> Input file to read from. If not specified, reads from stdin
--output-file [-o] <OUTPUT_FILE> Write the output to a file instead of stdout
8 ckms pqc
Manage post-quantum keys (ML-KEM, ML-DSA, Hybrid KEM, SLH-DSA). Encapsulate, decapsulate, sign, and verify
Usage
ckms pqc <subcommand>
Subcommands
keys [8.1] Manage post-quantum keys (ML-KEM, ML-DSA)
encrypt [8.2] Encapsulate using a PQC public key (ML-KEM-512/768/1024, X25519MLKEM768, X448MLKEM1024)
decrypt [8.3] Decapsulate a KEM ciphertext using a private key (ML-KEM or Hybrid KEM)
sign [8.4] Sign data using a PQC private key (ML-DSA-44/65/87 or SLH-DSA).
sign-verify [8.5] Verify a PQC signature (ML-DSA or SLH-DSA) for a given data file.
8.1 ckms pqc keys
Manage post-quantum keys (ML-KEM, ML-DSA)
Usage
ckms pqc keys <subcommand>
Subcommands
activate [8.1.1] Activate a cryptographic object (key, certificate, etc.)
create [8.1.2] Create a new post-quantum key pair (ML-KEM or ML-DSA).
export [8.1.3] Export a key or secret data from the KMS
import [8.1.4] Import a secret data or a key in the KMS.
wrap [8.1.5] Locally wrap a secret data or key in KMIP JSON TTLV format.
unwrap [8.1.6] Locally unwrap a secret data or key in KMIP JSON TTLV format.
revoke [8.1.7] Revoke a PQC public or private key
destroy [8.1.8] Destroy a PQC public or private key
re-key [8.1.9] Rotate an existing asymmetric key pair, generating a new private/public key pair
set-rotation-policy [8.1.10] Set the automatic rotation policy on a key or key pair.
get-rotation-policy [8.1.11] Get the automatic rotation policy for a key or key pair.
8.1.1 ckms pqc keys activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms pqc keys activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
8.1.2 ckms pqc keys create
Create a new post-quantum key pair (ML-KEM or ML-DSA).
Usage
ckms pqc keys create [options]
Arguments
--algorithm [-a] <ALGORITHM> The PQC algorithm to use
Possible values: "ml-kem-512", "ml-kem-768", "ml-kem-1024", "ml-dsa-44", "ml-dsa-65", "ml-dsa-87", "x25519-ml-kem-768", "x448-ml-kem-1024", "slh-dsa-sha2-128s", "slh-dsa-sha2-128f", "slh-dsa-sha2-192s", "slh-dsa-sha2-192f", "slh-dsa-sha2-256s", "slh-dsa-sha2-256f", "slh-dsa-shake-128s", "slh-dsa-shake-128f", "slh-dsa-shake-192s", "slh-dsa-shake-192f", "slh-dsa-shake-256s", "slh-dsa-shake-256f", "ml-kem-512-p256", "ml-kem-768-p256", "ml-kem-512-curve25519", "ml-kem-768-curve25519"
--tag [-t] <TAG> Tag to associate with the key pair. To specify multiple tags, use the option multiple times
--sensitive <SENSITIVE> Sensitive: if set, the private key will not be exportable
Possible values: "true", "false" [default: "false"]
--enroll-keyset [-n] <ENROLL_KEYSET> Enroll this key in a keyset so it can be addressed via name@latest,
name@first, name@N syntax. The keyset name is set automatically to
the key's own ID returned by the server.
Possible values: "true", "false" [default: "false"]
--rotation-interval <ROTATE_INTERVAL> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--rotation-offset <ROTATE_OFFSET> Offset in seconds from the initial date before the first rotation occurs
8.1.3 ckms pqc keys export
Export a key or secret data from the KMS
Usage
ckms pqc keys export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
8.1.4 ckms pqc keys import
Import a secret data or a key in the KMS.
Usage
ckms pqc keys import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
8.1.5 ckms pqc keys wrap
Locally wrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms pqc keys wrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to wrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified, the input file is overwritten
--wrap-password [-p] <WRAP_PASSWORD> A password to wrap the imported key. This password will be derived into an AES-256 symmetric key. For security reasons, a fresh salt is internally generated by cosmian and handled, and this final AES symmetric key will be displayed only once
--wrap-key-b64 [-k] <WRAP_KEY_B64> A symmetric key as a base 64 string to wrap the imported key
--wrap-key-id [-i] <WRAP_KEY_ID> The ID of a wrapping key in the KMS that will be exported and used to wrap the key
--wrap-key-file [-f] <WRAP_KEY_FILE> A wrapping key in a KMIP JSON TTLV file used to wrap the key
8.1.6 ckms pqc keys unwrap
Locally unwrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms pqc keys unwrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to unwrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified the input file is overwritten
--unwrap-key-b64 [-k] <UNWRAP_KEY_B64> A symmetric key as a base 64 string to unwrap the imported key
--unwrap-key-id [-i] <UNWRAP_KEY_ID> The id of an unwrapping key in the KMS that will be exported and used to unwrap the key
--unwrap-key-file [-f] <UNWRAP_KEY_FILE> An unwrapping key in a KMIP JSON TTLV file used to unwrap the key
8.1.7 ckms pqc keys revoke
Revoke a PQC public or private key
Usage
ckms pqc keys revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--key-id [-k] <KEY_ID> The key unique identifier of the key to revoke
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified
8.1.8 ckms pqc keys destroy
Destroy a PQC public or private key
Usage
ckms pqc keys destroy [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to destroy
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified
--remove <REMOVE> Remove the key from the database entirely
Possible values: "true", "false" [default: "false"]
8.1.9 ckms pqc keys re-key
Rotate an existing asymmetric key pair, generating a new private/public key pair
Usage
ckms pqc keys re-key [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the private key to re-key
8.1.10 ckms pqc keys set-rotation-policy
Set the automatic rotation policy on a key or key pair.
Usage
ckms pqc keys set-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to set the rotation policy on
--interval [-i] <INTERVAL_SECS> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--offset [-o] <OFFSET_SECS> Offset in seconds from the initial date before the first rotation occurs
--rotation-name [-n] <ROTATE_NAME> A keyset name for addressing key generations via name@latest, name@first, name@N syntax. Must not contain the '@' character
8.1.11 ckms pqc keys get-rotation-policy
Get the automatic rotation policy for a key or key pair.
Usage
ckms pqc keys get-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to get the rotation policy from
8.2 ckms pqc encrypt
Encapsulate using a PQC public key (ML-KEM-512/768/1024, X25519MLKEM768, X448MLKEM1024)
Usage
ckms pqc encrypt [options]
Arguments
--key-id [-k] <KEY_ID> The public key unique identifier
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified
--output-file [-o] <OUTPUT_FILE> The output file path for the encapsulation (ciphertext)
8.3 ckms pqc decrypt
Decapsulate a KEM ciphertext using a private key (ML-KEM or Hybrid KEM)
Usage
ckms pqc decrypt [options] <FILE>
Arguments
<FILE> The encapsulation file to decapsulate
--key-id [-k] <KEY_ID> The private key unique identifier
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified
--output-file [-o] <OUTPUT_FILE> The output file path for the shared secret
8.4 ckms pqc sign
Sign data using a PQC private key (ML-DSA-44/65/87 or SLH-DSA).
Usage
ckms pqc sign [options] <FILE>
Arguments
<FILE> The file to sign
--key-id [-k] <KEY_ID> The private key unique identifier
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified
--output-file [-o] <OUTPUT_FILE> The signature output file path
8.5 ckms pqc sign-verify
Verify a PQC signature (ML-DSA or SLH-DSA) for a given data file.
Usage
ckms pqc sign-verify [options] <FILE> <SIGNATURE_FILE>
Arguments
<FILE> The data that was signed
<SIGNATURE_FILE> The signature file
--key-id [-k] <KEY_ID> The public key unique identifier
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified
9 ckms tokenize
Anonymization utilities: hash, noise, word masking, pattern masking, aggregation, and scaling
Usage
ckms tokenize <subcommand>
Subcommands
hash [9.1] Hash a string with SHA2, SHA3, or Argon2
noise [9.2] Add statistical noise to a number or date
word-mask [9.3] Replace sensitive words with "XXXX"
word-tokenize [9.4] Replace sensitive words with consistent random hex tokens
word-pattern-mask [9.5] Replace regex-matched substrings with a replacement string
aggregate-number [9.6] Round a number to the nearest power of ten
aggregate-date [9.7] Truncate a date to a specified time unit
scale-number [9.8] Normalize and scale a number using z-score transformation
9.1 ckms tokenize hash
Hash a string with SHA2, SHA3, or Argon2
Usage
ckms tokenize hash [options]
Arguments
--data [-d] <DATA> Input string to hash
--method [-m] <METHOD> Hash algorithm: sha2, sha3, or argon2
--salt <SALT> Optional hex-encoded salt bytes
9.2 ckms tokenize noise
Add statistical noise to a number or date
Usage
ckms tokenize noise [options]
Arguments
--data [-d] <DATA> Input value (float, integer, or RFC3339 date string)
--data-type [-t] <DATA_TYPE> Data type: float, integer, or date
--method [-m] <METHOD> Noise distribution: Gaussian, Laplace, or Uniform
--mean <MEAN> Distribution mean (required for Gaussian/Laplace with parameters mode)
--std-dev <STD_DEV> Standard deviation (required for Gaussian/Laplace with parameters mode)
--min-bound <MIN_BOUND> Lower bound (required for bounds mode or Uniform)
--max-bound <MAX_BOUND> Upper bound (required for bounds mode or Uniform)
9.3 ckms tokenize word-mask
Replace sensitive words with "XXXX"
Usage
ckms tokenize word-mask [options]
Arguments
--data [-d] <DATA> Input text
--word [-w] <WORDS> Words to mask. Repeat for multiple: --word foo --word bar
9.4 ckms tokenize word-tokenize
Replace sensitive words with consistent random hex tokens
Usage
ckms tokenize word-tokenize [options]
Arguments
--data [-d] <DATA> Input text
--word [-w] <WORDS> Words to tokenize. Repeat for multiple: --word foo --word bar
9.5 ckms tokenize word-pattern-mask
Replace regex-matched substrings with a replacement string
Usage
ckms tokenize word-pattern-mask [options]
Arguments
--data [-d] <DATA> Input text
--pattern [-p] <PATTERN> Regular expression pattern (max 1024 chars)
--replace [-r] <REPLACE> Replacement string
9.6 ckms tokenize aggregate-number
Round a number to the nearest power of ten
Usage
ckms tokenize aggregate-number [options]
Arguments
--data [-d] <DATA> Number to round
--data-type [-t] <DATA_TYPE> Data type: float or integer
--power-of-ten [-p] <POWER_OF_TEN> Power of ten (e.g., 2 rounds to the nearest 100)
9.7 ckms tokenize aggregate-date
Truncate a date to a specified time unit
Usage
ckms tokenize aggregate-date [options]
Arguments
--data [-d] <DATA> RFC3339 date string (e.g. "2024-07-15T13:45:00Z")
--time-unit [-u] <TIME_UNIT> Time unit precision: Second, Minute, Hour, Day, Month, or Year
9.8 ckms tokenize scale-number
Normalize and scale a number using z-score transformation
Usage
ckms tokenize scale-number [options]
Arguments
--data [-d] <DATA> Number to scale
--data-type [-t] <DATA_TYPE> Data type: float or integer
--mean <MEAN> Mean of the original data distribution
--std-deviation <STD_DEVIATION> Standard deviation of the original data distribution (must be non-zero)
--scale <SCALE> Scaling factor
--translate <TRANSLATE> Translation factor
10 ckms certificates
Manage certificates. Create, import, destroy and revoke. Encrypt and decrypt data
Usage
ckms certificates <subcommand>
Subcommands
activate [10.1] Activate a cryptographic object (key, certificate, etc.)
certify [10.2] Issue or renew a X509 certificate
decrypt [10.3] Decrypt a file using the private key of a certificate
encrypt [10.4] Encrypt a file using the certificate public key
export [10.5] Export a certificate from the KMS
import [10.6] Import one of the following:
- a certificate: formatted as a X509 PEM (pem), X509 DER (der) or JSON TTLV (json-ttlv)
- a certificate chain as a PEM-stack (chain)
- a PKCS12 file containing a certificate, a private key and possibly a chain (pkcs12)
- the Mozilla Common CA Database (CCADB - fetched by the CLI before import) (ccadb)
revoke [10.7] Revoke a certificate
destroy [10.8] Destroy a certificate
set-rotation-policy [10.9] Set the automatic rotation policy on a certificate (interval, offset, keyset name)
validate [10.10] Validate a certificate
10.1 ckms certificates activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms certificates activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
10.2 ckms certificates certify
Issue or renew a X509 certificate
Usage
ckms certificates certify [options]
Arguments
--certificate-id [-c] <CERTIFICATE_ID> The unique identifier of the certificate to issue or renew. If not provided, a random one will be generated when issuing a certificate, or the original one will be used when renewing a certificate
--certificate-signing-request [-r] <CERTIFICATE_SIGNING_REQUEST> The path to a certificate signing request
--certificate-signing-request-format [-f] <CERTIFICATE_SIGNING_REQUEST_FORMAT> The format of the certificate signing request
Possible values: "pem", "der" [default: "pem"]
--public-key-id-to-certify [-p] <PUBLIC_KEY_ID_TO_CERTIFY> The id of a public key to certify
--certificate-id-to-re-certify [-n] <CERTIFICATE_ID_TO_RE_CERTIFY> The id of a certificate to re-certify
--generate-key-pair [-g] <GENERATE_KEY_PAIR> Generate a keypair then sign the public key and generate a certificate
Possible values: "true", "false"
--subject-name [-s] <SUBJECT_NAME> When certifying a public key, or generating a keypair,
the subject name to use.
--algorithm [-a] <ALGORITHM> The algorithm to use for the keypair generation
Possible values: "nist-p192", "nist-p224", "nist-p256", "nist-p384", "nist-p521", "ed25519", "ed448", "rsa1024", "rsa2048", "rsa3072", "rsa4096", "ml-dsa-44", "ml-dsa-65", "ml-dsa-87", "slh-dsa-sha2-128s", "slh-dsa-sha2-128f", "slh-dsa-sha2-192s", "slh-dsa-sha2-192f", "slh-dsa-sha2-256s", "slh-dsa-sha2-256f", "slh-dsa-shake-128s", "slh-dsa-shake-128f", "slh-dsa-shake-192s", "slh-dsa-shake-192f", "slh-dsa-shake-256s", "slh-dsa-shake-256f", "ml-kem-512", "ml-kem-768", "ml-kem-1024", "x25519-ml-kem-768", "x448-ml-kem-1024", "ml-kem-512-p256", "ml-kem-768-p256", "ml-kem-512-curve25519", "ml-kem-768-curve25519" [default: "rsa4096"]
--issuer-private-key-id [-k] <ISSUER_PRIVATE_KEY_ID> The unique identifier of the private key of the issuer. A certificate must be linked to that private key if no issuer certificate id is provided
--issuer-certificate-id [-i] <ISSUER_CERTIFICATE_ID> The unique identifier of the certificate of the issuer. A private key must be linked to that certificate if no issuer private key id is provided
--days [-d] <NUMBER_OF_DAYS> The requested number of validity days The server may grant a different value
--certificate-extensions [-e] <CERTIFICATE_EXTENSIONS> The path to a X509 extension's file, containing a v3_ca paragraph
with the x509 extensions to use. For instance:
--tag [-t] <TAG> The tag to associate to the certificate. To specify multiple tags, use the option multiple times
10.3 ckms certificates decrypt
Decrypt a file using the private key of a certificate
Usage
ckms certificates decrypt [options] <FILE>
Arguments
<FILE> The file to decrypt
--key-id [-k] <PRIVATE_KEY_ID> The private key unique identifier related to certificate If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
--authentication-data [-a] <AUTHENTICATION_DATA> Optional authentication data that was supplied during encryption
--encryption-algorithm [-e] <ENCRYPTION_ALGORITHM> Optional encryption algorithm.
This is only available for RSA keys for now.
The default for RSA is PKCS_OAEP.
Possible values: "ckm-rsa-pkcs", "ckm-rsa-pkcs-oaep", "ckm-rsa-aes-key-wrap"
10.4 ckms certificates encrypt
Encrypt a file using the certificate public key
Usage
ckms certificates encrypt [options] <FILE>
Arguments
<FILE> The file to encrypt
--certificate-id [-c] <CERTIFICATE_ID> The certificate unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
--authentication-data [-a] <AUTHENTICATION_DATA> Optional authentication data. This data needs to be provided back for decryption
--encryption-algorithm [-e] <ENCRYPTION_ALGORITHM> Optional encryption algorithm.
This is only available for RSA keys for now.
The default for RSA is PKCS_OAEP.
Possible values: "ckm-rsa-pkcs", "ckm-rsa-pkcs-oaep", "ckm-rsa-aes-key-wrap"
10.5 ckms certificates export
Export a certificate from the KMS
Usage
ckms certificates export [options] <CERTIFICATE_FILE>
Arguments
<CERTIFICATE_FILE> The file to export the certificate to
--certificate-id [-c] <CERTIFICATE_ID> The certificate unique identifier stored in the KMS; for PKCS#12, provide the private key id
If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the certificate/private key when no unique id is specified.
To specify multiple tags, use the option multiple times.
--format [-f] <OUTPUT_FORMAT> Export the certificate in the selected format
Possible values: "json-ttlv", "pem", "pkcs12", "pkcs12-legacy", "pkcs7" [default: "json-ttlv"]
--pkcs12-password [-p] <PKCS12_PASSWORD> Password to use to protect the PKCS#12 file
--allow-revoked [-r] <ALLOW_REVOKED> Allow exporting revoked and destroyed certificates or private key (for PKCS#12).
The user must be the owner of the certificate.
Destroyed objects have their key material removed.
Possible values: "true", "false" [default: "false"]
10.6 ckms certificates import
Import one of the following:
- a certificate: formatted as a X509 PEM (pem), X509 DER (der) or JSON TTLV (json-ttlv)
- a certificate chain as a PEM-stack (chain)
- a PKCS12 file containing a certificate, a private key and possibly a chain (pkcs12)
- the Mozilla Common CA Database (CCADB - fetched by the CLI before import) (ccadb)
Usage
ckms certificates import [options] [CERTIFICATE_FILE] [CERTIFICATE_ID]
Arguments
<CERTIFICATE_FILE> The input file in PEM, KMIP-JSON-TTLV or PKCS#12 format
<CERTIFICATE_ID> The unique id of the leaf certificate; a unique id
based on the key material is generated if not specified.
When importing a PKCS12, the unique id will be that of the private key.
--format [-f] <INPUT_FORMAT> Import the certificate in the selected format
Possible values: "json-ttlv", "pem", "der", "chain", "pkcs12", "ccadb" [default: "json-ttlv"]
--private-key-id [-k] <PRIVATE_KEY_ID> The corresponding private key id if any. Ignored for PKCS12 and CCADB formats
--public-key-id [-q] <PUBLIC_KEY_ID> The corresponding public key id if any. Ignored for PKCS12 and CCADB formats
--issuer-certificate-id [-i] <ISSUER_CERTIFICATE_ID> The issuer certificate id if any. Ignored for PKCS12 and CCADB formats
--pkcs12-password [-p] <PKCS12_PASSWORD> PKCS12 password: only available for PKCS12 format
--replace [-r] <REPLACE_EXISTING> Replace an existing certificate under the same id
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the certificate. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> For what operations should the certificate be used
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
10.7 ckms certificates revoke
Revoke a certificate
Usage
ckms certificates revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--certificate-id [-c] <CERTIFICATE_ID> The certificate unique identifier of the certificate to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the certificate when no certificate id is specified. To specify multiple tags, use the option multiple times
10.8 ckms certificates destroy
Destroy a certificate
Usage
ckms certificates destroy [options]
Arguments
--certificate-id [-c] <CERTIFICATE_ID> The certificate unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the certificate when no certificate id is specified. To specify multiple tags, use the option multiple times
--remove <REMOVE> If the certificate should be removed from the database
If not specified, the certificate will be destroyed
but its metadata will still be available in the database.
Please note that the KMIP specification does not support the removal of objects.
Possible values: "true", "false" [default: "false"]
10.9 ckms certificates set-rotation-policy
Set the automatic rotation policy on a certificate (interval, offset, keyset name)
Usage
ckms certificates set-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to set the rotation policy on
--interval [-i] <INTERVAL_SECS> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--offset [-o] <OFFSET_SECS> Offset in seconds from the initial date before the first rotation occurs
--rotation-name [-n] <ROTATE_NAME> A keyset name for addressing key generations via name@latest, name@first, name@N syntax. Must not contain the '@' character
10.10 ckms certificates validate
Validate a certificate
Usage
ckms certificates validate [options]
Arguments
--certificate-id [-k] <CERTIFICATE_ID> One or more Unique Identifiers of Certificate Objects
--validity-time [-t] <VALIDITY_TIME> A Date-Time object indicating when the certificate chain needs to be valid. If omitted, the current date and time SHALL be assumed
11 ckms cng
Manage the Windows CNG Key Storage Provider (KSP)
Usage
ckms cng <subcommand>
Subcommands
register [11.1] Register the Cosmian KMS CNG Key Storage Provider DLL in the Windows Registry
unregister [11.2] Unregister the Cosmian KMS CNG Key Storage Provider from the Windows Registry
status [11.3] Show the CNG KSP registration status (is the provider registered?)
list-keys [11.4] List all private keys stored in Cosmian KMS that belong to this CNG KSP
verify [11.5] Load the CNG KSP DLL and exercise all NCrypt function-table entry points
11.1 ckms cng register
Register the Cosmian KMS CNG Key Storage Provider DLL in the Windows Registry
Usage
ckms cng register [options]
Arguments
--dll [-d] <DLL> Full path to the cosmian_cng.dll file
11.2 ckms cng unregister
Unregister the Cosmian KMS CNG Key Storage Provider from the Windows Registry
Usage
ckms cng unregister
11.3 ckms cng status
Show the CNG KSP registration status (is the provider registered?)
Usage
ckms cng status
11.4 ckms cng list-keys
List all private keys stored in Cosmian KMS that belong to this CNG KSP
Usage
ckms cng list-keys
11.5 ckms cng verify
Load the CNG KSP DLL and exercise all NCrypt function-table entry points
Usage
ckms cng verify [options]
Arguments
--dll [-d] <DLL> Full path to the cosmian_cng.dll file to verify
12 ckms derive-key
Derive a new key from an existing key
Usage
ckms derive-key [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the base key to derive from Mutually exclusive with --password
--password [-p] <PASSWORD> UTF-8 password to use as base material for key derivation Will create a SecretData of type Password internally Mutually exclusive with --key-id
--derivation-method [-m] <DERIVATION_METHOD> The derivation method to use (PBKDF2 or HKDF)
--salt [-s] <SALT> Salt for key derivation (in hex format)
--iteration-count [-i] <ITERATION_COUNT> Number of iterations for PBKDF2 derivation
--initialization-vector [-v] <INITIALIZATION_VECTOR> Initialization vector for derivation (in hex format)
--digest-algorithm [-d] <DIGEST_ALGORITHM> Digest algorithm for derivation
Possible values: "sha1", "sha224", "sha256", "sha384", "sha512", "sha3-224", "sha3-256", "sha3-384", "sha3-512" [default: "SHA256"]
--algorithm [-a] <ALGORITHM> The algorithm
Possible values: "chacha20", "aes", "sha3", "shake" [default: "aes"]
--length [-l] <CRYPTOGRAPHIC_LENGTH> Length of the derived key in bits
--derived-key-id <DERIVED_KEY_ID> Optional unique identifier for the derived key
13 ckms ec
Manage elliptic curve keys. Encrypt and decrypt data using ECIES
Usage
ckms ec <subcommand>
Subcommands
keys [13.1] Create, destroy, import, and export elliptic curve key pairs
encrypt [13.2] Encrypt a file with the given public key using ECIES
decrypt [13.3] Decrypts a file with the given private key using ECIES
sign [13.4] Sign a file using elliptic curve digital signature algorithms (ECDSA)
sign-verify [13.5] Verify an ECDSA signature for a given data file
13.1 ckms ec keys
Create, destroy, import, and export elliptic curve key pairs
Usage
ckms ec keys <subcommand>
Subcommands
activate [13.1.1] Activate a cryptographic object (key, certificate, etc.)
create [13.1.2] Create an elliptic curve key pair
export [13.1.3] Export a key or secret data from the KMS
import [13.1.4] Import a secret data or a key in the KMS.
wrap [13.1.5] Locally wrap a secret data or key in KMIP JSON TTLV format.
unwrap [13.1.6] Locally unwrap a secret data or key in KMIP JSON TTLV format.
revoke [13.1.7] Revoke a public or private key
destroy [13.1.8] Destroy a public or private key
re-key [13.1.9] Rotate an existing asymmetric key pair, generating a new private/public key pair
set-rotation-policy [13.1.10] Set the automatic rotation policy on a key or key pair.
get-rotation-policy [13.1.11] Get the automatic rotation policy for a key or key pair.
13.1.1 ckms ec keys activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms ec keys activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
13.1.2 ckms ec keys create
Create an elliptic curve key pair
Usage
ckms ec keys create [options] [PRIVATE_KEY_ID]
Arguments
--curve [-c] <CURVE> The elliptic curve
Possible values: "nist-p256", "nist-p384", "nist-p521", "x25519", "ed25519", "x448", "ed448", "secp256k1", "secp224k1" [default: "nist-p256"]
--tag [-t] <TAG> The tag to associate with the master key pair. To specify multiple tags, use the option multiple times
<PRIVATE_KEY_ID> The unique id of the private key; a random uuid is generated if not specified
--sensitive <SENSITIVE> Sensitive: if set, the key will not be exportable
Possible values: "true", "false" [default: "false"]
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap the keypair with.
If the wrapping key is:
- a symmetric key, AES-GCM will be used
- a RSA key, RSA-OAEP will be used
- a EC key, ECIES will be used (salsa20poly1305 for X25519)
--enroll-keyset [-n] <ENROLL_KEYSET> Enroll this key in a keyset so it can be addressed via name@latest,
name@first, name@N syntax. The keyset name is set automatically to
the key's own ID returned by the server.
Possible values: "true", "false" [default: "false"]
--rotation-interval <ROTATE_INTERVAL> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--rotation-offset <ROTATE_OFFSET> Offset in seconds from the initial date before the first rotation occurs
13.1.3 ckms ec keys export
Export a key or secret data from the KMS
Usage
ckms ec keys export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
13.1.4 ckms ec keys import
Import a secret data or a key in the KMS.
Usage
ckms ec keys import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
13.1.5 ckms ec keys wrap
Locally wrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms ec keys wrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to wrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified, the input file is overwritten
--wrap-password [-p] <WRAP_PASSWORD> A password to wrap the imported key. This password will be derived into an AES-256 symmetric key. For security reasons, a fresh salt is internally generated by cosmian and handled, and this final AES symmetric key will be displayed only once
--wrap-key-b64 [-k] <WRAP_KEY_B64> A symmetric key as a base 64 string to wrap the imported key
--wrap-key-id [-i] <WRAP_KEY_ID> The ID of a wrapping key in the KMS that will be exported and used to wrap the key
--wrap-key-file [-f] <WRAP_KEY_FILE> A wrapping key in a KMIP JSON TTLV file used to wrap the key
13.1.6 ckms ec keys unwrap
Locally unwrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms ec keys unwrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to unwrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified the input file is overwritten
--unwrap-key-b64 [-k] <UNWRAP_KEY_B64> A symmetric key as a base 64 string to unwrap the imported key
--unwrap-key-id [-i] <UNWRAP_KEY_ID> The id of an unwrapping key in the KMS that will be exported and used to unwrap the key
--unwrap-key-file [-f] <UNWRAP_KEY_FILE> An unwrapping key in a KMIP JSON TTLV file used to unwrap the key
13.1.7 ckms ec keys revoke
Revoke a public or private key
Usage
ckms ec keys revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--key-id [-k] <KEY_ID> The key unique identifier of the key to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
13.1.8 ckms ec keys destroy
Destroy a public or private key
Usage
ckms ec keys destroy [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to destroy If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--remove <REMOVE> If the key should be removed from the database
If not specified, the key will be destroyed
but its metadata will still be available in the database.
Please note that the KMIP specification does not support the removal of objects.
Possible values: "true", "false" [default: "false"]
13.1.9 ckms ec keys re-key
Rotate an existing asymmetric key pair, generating a new private/public key pair
Usage
ckms ec keys re-key [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the private key to re-key
13.1.10 ckms ec keys set-rotation-policy
Set the automatic rotation policy on a key or key pair.
Usage
ckms ec keys set-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to set the rotation policy on
--interval [-i] <INTERVAL_SECS> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--offset [-o] <OFFSET_SECS> Offset in seconds from the initial date before the first rotation occurs
--rotation-name [-n] <ROTATE_NAME> A keyset name for addressing key generations via name@latest, name@first, name@N syntax. Must not contain the '@' character
13.1.11 ckms ec keys get-rotation-policy
Get the automatic rotation policy for a key or key pair.
Usage
ckms ec keys get-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to get the rotation policy from
13.2 ckms ec encrypt
Encrypt a file with the given public key using ECIES
Usage
ckms ec encrypt [options] <FILE>
Arguments
<FILE> The file to encrypt
--key-id [-k] <KEY_ID> The public key unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
13.3 ckms ec decrypt
Decrypts a file with the given private key using ECIES
Usage
ckms ec decrypt [options] <FILE>
Arguments
<FILE> The file to decrypt
--key-id [-k] <KEY_ID> The private key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
13.4 ckms ec sign
Sign a file using elliptic curve digital signature algorithms (ECDSA)
Usage
ckms ec sign [options] <FILE>
Arguments
--curve [-c] <CURVE> The elliptic curve
Possible values: "nist-p256", "nist-p384", "nist-p521", "x25519", "ed25519", "x448", "ed448", "secp256k1", "secp224k1" [default: "nist-p256"]
<FILE> The file to sign
--key-id [-k] <KEY_ID> The private key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The signature output file path
--digested <DIGESTED> Treat input as already-digested data (pre-hash)
Possible values: "true", "false"
13.5 ckms ec sign-verify
Verify an ECDSA signature for a given data file
Usage
ckms ec sign-verify [options] <FILE> <SIGNATURE_FILE>
Arguments
<FILE> The data that was signed
<SIGNATURE_FILE> The signature file
--key-id [-k] <KEY_ID> The private key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> Optional output file path
--digested <DIGESTED> Treat data input as already-digested (pre-hash)
Possible values: "true", "false"
14 ckms google
Manage google elements. Handle key pairs and identities from Gmail API
Usage
ckms google <subcommand>
Subcommands
key-pairs [14.1] Insert, get, list, enable, disabled and obliterate key pairs to Gmail API
identities [14.2] Insert, get, list, patch and delete identities from Gmail API
14.1 ckms google key-pairs
Insert, get, list, enable, disabled and obliterate key pairs to Gmail API
Usage
ckms google key-pairs <subcommand>
Subcommands
get [14.1.1] Retrieves an existing client-side encryption key pair.
list [14.1.2] Lists client-side encryption key pairs for a user.
enable [14.1.3] Turns on a client-side encryption key pair that was turned off. The key pair becomes active
again for any associated client-side encryption identities.
disable [14.1.4] Turns off a client-side encryption key pair. The authenticated user can no longer use the key
pair to decrypt incoming CSE message texts or sign outgoing CSE mail. To regain access, use the
key pairs.enable to turn on the key pair. After 30 days, you can permanently delete the key pair
by using the key pairs.obliterate method.
obliterate [14.1.5] Deletes a client-side encryption key pair permanently and immediately. You can only permanently
delete key pairs that have been turned off for more than 30 days. To turn off a key pair, use
the key pairs disable method. Gmail can't restore or decrypt any messages that were encrypted by
an obliterated key. Authenticated users and Google Workspace administrators lose access to
reading the encrypted messages.
create [14.1.6] Creates and uploads a client-side encryption S/MIME public key certificate chain and private key
metadata for a user.
14.1.1 ckms google key-pairs get
Retrieves an existing client-side encryption key pair.
Usage
ckms google key-pairs get [options] <KEY_PAIRS_ID>
Arguments
<KEY_PAIRS_ID> The identifier of the key pair to retrieve
--user-id [-u] <USER_ID> The requester's primary email address
14.1.2 ckms google key-pairs list
Lists client-side encryption key pairs for a user.
Usage
ckms google key-pairs list [options] <USER_ID>
Arguments
<USER_ID> The requester's primary email address
14.1.3 ckms google key-pairs enable
Turns on a client-side encryption key pair that was turned off. The key pair becomes active again for any associated client-side encryption identities.
Usage
ckms google key-pairs enable [options] <KEY_PAIRS_ID>
Arguments
<KEY_PAIRS_ID> The identifier of the key pair to enable
--user-id [-u] <USER_ID> The requester's primary email address
14.1.4 ckms google key-pairs disable
Turns off a client-side encryption key pair. The authenticated user can no longer use the key pair to decrypt incoming CSE message texts or sign outgoing CSE mail. To regain access, use the key pairs.enable to turn on the key pair. After 30 days, you can permanently delete the key pair by using the key pairs.obliterate method.
Usage
ckms google key-pairs disable [options] <KEY_PAIRS_ID>
Arguments
<KEY_PAIRS_ID> The identifier of the key pair to disable
--user-id [-u] <USER_ID> The requester's primary email address
14.1.5 ckms google key-pairs obliterate
Deletes a client-side encryption key pair permanently and immediately. You can only permanently delete key pairs that have been turned off for more than 30 days. To turn off a key pair, use the key pairs disable method. Gmail can't restore or decrypt any messages that were encrypted by an obliterated key. Authenticated users and Google Workspace administrators lose access to reading the encrypted messages.
Usage
ckms google key-pairs obliterate [options] <KEY_PAIRS_ID>
Arguments
<KEY_PAIRS_ID> The identifier of the key pair to obliterate
--user-id [-u] <USER_ID> The requester's primary email address
14.1.6 ckms google key-pairs create
Creates and uploads a client-side encryption S/MIME public key certificate chain and private key metadata for a user.
Usage
ckms google key-pairs create [options] <USER_ID>
Arguments
<USER_ID> The requester's primary email address
--cse-key-id <CSE_KEY_ID> CSE key ID to wrap exported user private key
--subject-name [-s] <SUBJECT_NAME> When certifying a public key, or generating a keypair,
the subject name to use.
For instance: "CN=John Doe,OU=Org Unit,O=Org Name,L=City,ST=State,C=US"
--rsa-private-key-id [-k] <RSA_PRIVATE_KEY_ID> The existing private key id of an existing RSA keypair to use (optional - if no ID is provided, a RSA keypair will be created)
--sensitive <SENSITIVE> Sensitive: if set, the key will not be exportable
Possible values: "true", "false" [default: "false"]
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap the keypair with.
If the wrapping key is:
- a symmetric key, AES-GCM will be used
- a RSA key, RSA-OAEP will be used
- a EC key, ECIES will be used (salsa20poly1305 for X25519)
--issuer-private-key-id [-i] <ISSUER_PRIVATE_KEY_ID> The issuer private key id - required when generating a new leaf certificate
--leaf-certificate-extensions [-e] <LEAF_CERTIFICATE_EXTENSIONS> Path to a file containing X.509 extensions, defined under a [v3_ca] section.
These extensions will be applied to the generated leaf certificate and must
comply with Google's S/MIME certificate requirements. For example:
[ v3_ca ]
keyUsage=nonRepudiation,digitalSignature,dataEncipherment,keyEncipherment
extendedKeyUsage=emailProtection
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
This parameter is ignored when using an existing leaf certificate.
--leaf-certificate-id <LEAF_CERTIFICATE_ID> The ID of an existing leaf certificate in KMS to use instead of generating a new one.
This certificate must be compatible with the private key being used.
Cannot be used together with --leaf-certificate-file.
--leaf-certificate-pkcs12-file <LEAF_CERTIFICATE_PKCS12_FILE> Path to a local leaf PKCS12 certificate file to use instead of generating a new one.
This PKCS12 certificate also holds the private key.
Cannot be used together with --leaf-certificate-id neither --leaf-certificate-extensions.
--leaf-certificate-pkcs12-password <LEAF_CERTIFICATE_PKCS12_PASSWORD> The password for the PKCS12 file containing the leaf certificate.
--days [-d] <NUMBER_OF_DAYS> The requested number of validity days The server may grant a different value
--dry-run <DRY_RUN> Dry run mode. If set, the action will not be executed
Possible values: "true", "false" [default: "false"]
14.2 ckms google identities
Insert, get, list, patch and delete identities from Gmail API
Usage
ckms google identities <subcommand>
Subcommands
get [14.2.1] Retrieves a client-side encryption identity configuration.
list [14.2.2] Lists the client-side encrypted identities for an authenticated user.
insert [14.2.3] Creates and configures a client-side encryption identity that's authorized to send mail from the
user account. Google publishes the S/MIME certificate to a shared domain-wide directory so that
people within a Google Workspace organization can encrypt and send mail to the identity.
delete [14.2.4] Deletes a client-side encryption identity. The authenticated user can no longer use the identity
to send encrypted messages. You cannot restore the identity after you delete it. Instead, use
the identities.create method to create another identity with the same configuration.
patch [14.2.5] Associates a different key pair with an existing client-side encryption identity. The updated
key pair must validate against Google's S/MIME certificate profiles.
14.2.1 ckms google identities get
Retrieves a client-side encryption identity configuration.
Usage
ckms google identities get [options] <USER_ID>
Arguments
<USER_ID> The primary email address associated with the client-side encryption identity configuration that's retrieved
14.2.2 ckms google identities list
Lists the client-side encrypted identities for an authenticated user.
Usage
ckms google identities list [options] <USER_ID>
Arguments
<USER_ID> The requester's primary email address
14.2.3 ckms google identities insert
Creates and configures a client-side encryption identity that's authorized to send mail from the user account. Google publishes the S/MIME certificate to a shared domain-wide directory so that people within a Google Workspace organization can encrypt and send mail to the identity.
Usage
ckms google identities insert [options] <KEY_PAIRS_ID>
Arguments
<KEY_PAIRS_ID> The keypair id, associated with a given cert/key. You can get the by listing the keypairs associated with the user-id
--user-id [-u] <USER_ID> The primary email address associated with the client-side encryption identity configuration that's retrieved
14.2.4 ckms google identities delete
Deletes a client-side encryption identity. The authenticated user can no longer use the identity to send encrypted messages. You cannot restore the identity after you delete it. Instead, use the identities.create method to create another identity with the same configuration.
Usage
ckms google identities delete [options] <USER_ID>
Arguments
<USER_ID> The primary email address associated with the client-side encryption identity configuration that's retrieved
14.2.5 ckms google identities patch
Associates a different key pair with an existing client-side encryption identity. The updated key pair must validate against Google's S/MIME certificate profiles.
Usage
ckms google identities patch [options] <KEY_PAIRS_ID>
Arguments
<KEY_PAIRS_ID> The key pair id, associated with a given cert/key. You can get the by listing the key pairs associated with the user-id
--user-id [-u] <USER_ID> The primary email address associated with the client-side encryption identity configuration that's retrieved
15 ckms locate
Locate cryptographic objects inside the KMS
Usage
ckms locate [options]
Arguments
--tag [-t] <TAG> User tags or system tags to locate the object.
To specify multiple tags, use the option multiple times.
--algorithm [-a] <CRYPTOGRAPHIC_ALGORITHM> Cryptographic algorithm (case insensitive)
--cryptographic-length [-l] <CRYPTOGRAPHIC_LENGTH> Cryptographic length (e.g. key size) in bits
--key-format-type [-f] <KEY_FORMAT_TYPE> Key format type (case insensitive)
--object-type [-o] <OBJECT_TYPE> Object type (case insensitive)
--public-key-id [-p] <PUBLIC_KEY_ID> Locate an object which has a link to this public key id
--private-key-id [-k] <PRIVATE_KEY_ID> Locate an object which has a link to this private key id
--certificate-id [-c] <CERTIFICATE_ID> Locate an object which has a link to this certificate key id
16 ckms login
Login to the Identity Provider of the KMS server using the OAuth2 authorization code flow.
Usage
ckms login
17 ckms logout
Logout from the Identity Provider
Usage
ckms logout
18 ckms hash
Hash arbitrary data.
Usage
ckms hash [options]
Arguments
--algorithm [-a] <ALGORITHM> Hashing algorithm (case insensitive)
Possible values: "sha1", "sha224", "sha256", "sha384", "sha512", "sha3-224", "sha3-256", "sha3-384", "sha3-512"
--data [-d] <DATA> The data to be hashed in hexadecimal format
--correlation-value [-c] <CORRELATION_VALUE> Specifies the existing stream or by-parts cryptographic operation (as returned from a previous call to this operation)
--init-indicator [-i] <INIT_INDICATOR> Initial operation as Boolean
Possible values: "true", "false"
--final-indicator [-f] <FINAL_INDICATOR> Final operation as Boolean
Possible values: "true", "false"
19 ckms mac
MAC utilities: compute or verify a MAC value.
Usage
ckms mac <subcommand>
Subcommands
compute [19.1] Compute a MAC over data with a MAC key
verify [19.2] Verify a MAC over data with a MAC key
19.1 ckms mac compute
Compute a MAC over data with a MAC key
Usage
ckms mac compute [options]
Arguments
--mac-key-id [-k] <MAC_KEY_ID> Locate an object which has a link to this MAC key id
--algorithm [-a] <ALGORITHM> Hashing algorithm (case insensitive)
Possible values: "sha1", "sha224", "sha256", "sha384", "sha512", "sha3-224", "sha3-256", "sha3-384", "sha3-512"
--data [-d] <DATA> The data to be hashed in hexadecimal format. The data to be hashed in hexadecimal format
--correlation-value [-c] <CORRELATION_VALUE> Specifies the existing stream or by-parts cryptographic operation (as returned from a previous call to this operation). The correlation value is represented as a hexadecimal string
--init-indicator [-i] <INIT_INDICATOR> Initial operation as Boolean
Possible values: "true", "false"
--final-indicator [-f] <FINAL_INDICATOR> Final operation as Boolean
Possible values: "true", "false"
19.2 ckms mac verify
Verify a MAC over data with a MAC key
Usage
ckms mac verify [options]
Arguments
--mac-key-id [-k] <MAC_KEY_ID> Locate an object which has a link to this MAC key id
--algorithm [-a] <ALGORITHM> Hashing algorithm (case insensitive)
Possible values: "sha1", "sha224", "sha256", "sha384", "sha512", "sha3-224", "sha3-256", "sha3-384", "sha3-512"
--data [-d] <DATA> The data to verify in hexadecimal format
--mac [-m] <MAC_HEX> The MAC to verify in hexadecimal format
20 ckms rng
RNG utilities: retrieve random bytes or seed RNG
Usage
ckms rng <subcommand>
Subcommands
retrieve [20.1] Retrieve cryptographically secure random bytes from the server RNG
seed [20.2] Seed the server RNG with provided hex-encoded bytes
20.1 ckms rng retrieve
Retrieve cryptographically secure random bytes from the server RNG
Usage
ckms rng retrieve [options]
Arguments
--length [-l] <LENGTH> Number of bytes to retrieve
20.2 ckms rng seed
Seed the server RNG with provided hex-encoded bytes
Usage
ckms rng seed [options]
Arguments
--data [-d] <DATA> Seed data as hex string
21 ckms server
Server-related commands
Usage
ckms server <subcommand>
Subcommands
version [21.1] Show server version information
discover-versions [21.2] Discover KMIP protocol versions supported by the server
query [21.3] Query server capabilities and metadata (KMIP Query)
21.1 ckms server version
Show server version information
Usage
ckms server version
21.2 ckms server discover-versions
Discover KMIP protocol versions supported by the server
Usage
ckms server discover-versions
21.3 ckms server query
Query server capabilities and metadata (KMIP Query)
Usage
ckms server query
22 ckms rsa
Manage RSA keys. Encrypt and decrypt data using RSA keys
Usage
ckms rsa <subcommand>
Subcommands
keys [22.1] Create, destroy, import, and export RSA key pairs
encrypt [22.2] Encrypt a file with the given public key using either
CKM_RSA_PKCSa.k.a PKCS #1 RSA V1.5 as specified in PKCS#11 v2.40CKM_RSA_PKCS_OAEPa.k.a PKCS #1 RSA OAEP as specified in PKCS#11 v2.40CKM_RSA_AES_KEY_WRAPas specified in PKCS#11 v2.40
decrypt [22.3] Decrypt a file with the given private key using either
CKM_RSA_PKCSa.k.a PKCS #1 RSA V1.5 as specified in PKCS#11 v2.40CKM_RSA_PKCS_OAEPa.k.a PKCS #1 RSA OAEP as specified in PKCS#11 v2.40CKM_RSA_AES_KEY_WRAPas specified in PKCS#11 v2.40
sign [22.4] Digital signature supported is RSASSA-PSS
sign-verify [22.5] Verify an RSASSA-PSS signature for a given data file
22.1 ckms rsa keys
Create, destroy, import, and export RSA key pairs
Usage
ckms rsa keys <subcommand>
Subcommands
activate [22.1.1] Activate a cryptographic object (key, certificate, etc.)
create [22.1.2] Create a new RSA key pair
export [22.1.3] Export a key or secret data from the KMS
import [22.1.4] Import a secret data or a key in the KMS.
wrap [22.1.5] Locally wrap a secret data or key in KMIP JSON TTLV format.
unwrap [22.1.6] Locally unwrap a secret data or key in KMIP JSON TTLV format.
revoke [22.1.7] Revoke a public or private key
destroy [22.1.8] Destroy a public or private key
re-key [22.1.9] Rotate an existing asymmetric key pair, generating a new private/public key pair
set-rotation-policy [22.1.10] Set the automatic rotation policy on a key or key pair.
get-rotation-policy [22.1.11] Get the automatic rotation policy for a key or key pair.
22.1.1 ckms rsa keys activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms rsa keys activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
22.1.2 ckms rsa keys create
Create a new RSA key pair
Usage
ckms rsa keys create [options] [PRIVATE_KEY_ID]
Arguments
--size_in_bits [-s] <SIZE_IN_BITS> The expected size in bits
--tag [-t] <TAG> The tag to associate with the master key pair. To specify multiple tags, use the option multiple times
<PRIVATE_KEY_ID> The unique id of the private key; a random uuid is generated if not specified
--sensitive <SENSITIVE> Sensitive: if set, the private key will not be exportable
Possible values: "true", "false" [default: "false"]
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap the keypair with.
If the wrapping key is:
- a symmetric key, AES-GCM will be used
- a RSA key, RSA-OAEP will be used
- a EC key, ECIES will be used (salsa20poly1305 for X25519)
--enroll-keyset [-n] <ENROLL_KEYSET> Enroll this key in a keyset so it can be addressed via name@latest,
name@first, name@N syntax. The keyset name is set automatically to
the key's own ID returned by the server.
Possible values: "true", "false" [default: "false"]
--rotation-interval <ROTATE_INTERVAL> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--rotation-offset <ROTATE_OFFSET> Offset in seconds from the initial date before the first rotation occurs
22.1.3 ckms rsa keys export
Export a key or secret data from the KMS
Usage
ckms rsa keys export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
22.1.4 ckms rsa keys import
Import a secret data or a key in the KMS.
Usage
ckms rsa keys import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
22.1.5 ckms rsa keys wrap
Locally wrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms rsa keys wrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to wrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified, the input file is overwritten
--wrap-password [-p] <WRAP_PASSWORD> A password to wrap the imported key. This password will be derived into an AES-256 symmetric key. For security reasons, a fresh salt is internally generated by cosmian and handled, and this final AES symmetric key will be displayed only once
--wrap-key-b64 [-k] <WRAP_KEY_B64> A symmetric key as a base 64 string to wrap the imported key
--wrap-key-id [-i] <WRAP_KEY_ID> The ID of a wrapping key in the KMS that will be exported and used to wrap the key
--wrap-key-file [-f] <WRAP_KEY_FILE> A wrapping key in a KMIP JSON TTLV file used to wrap the key
22.1.6 ckms rsa keys unwrap
Locally unwrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms rsa keys unwrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to unwrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified the input file is overwritten
--unwrap-key-b64 [-k] <UNWRAP_KEY_B64> A symmetric key as a base 64 string to unwrap the imported key
--unwrap-key-id [-i] <UNWRAP_KEY_ID> The id of an unwrapping key in the KMS that will be exported and used to unwrap the key
--unwrap-key-file [-f] <UNWRAP_KEY_FILE> An unwrapping key in a KMIP JSON TTLV file used to unwrap the key
22.1.7 ckms rsa keys revoke
Revoke a public or private key
Usage
ckms rsa keys revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--key-id [-k] <KEY_ID> The key unique identifier of the key to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
22.1.8 ckms rsa keys destroy
Destroy a public or private key
Usage
ckms rsa keys destroy [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to destroy If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--remove <REMOVE> If the key should be removed from the database
If not specified, the key will be destroyed
but its metadata will still be available in the database.
Please note that the KMIP specification does not support the removal of objects.
Possible values: "true", "false" [default: "false"]
22.1.9 ckms rsa keys re-key
Rotate an existing asymmetric key pair, generating a new private/public key pair
Usage
ckms rsa keys re-key [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the private key to re-key
22.1.10 ckms rsa keys set-rotation-policy
Set the automatic rotation policy on a key or key pair.
Usage
ckms rsa keys set-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to set the rotation policy on
--interval [-i] <INTERVAL_SECS> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--offset [-o] <OFFSET_SECS> Offset in seconds from the initial date before the first rotation occurs
--rotation-name [-n] <ROTATE_NAME> A keyset name for addressing key generations via name@latest, name@first, name@N syntax. Must not contain the '@' character
22.1.11 ckms rsa keys get-rotation-policy
Get the automatic rotation policy for a key or key pair.
Usage
ckms rsa keys get-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to get the rotation policy from
22.2 ckms rsa encrypt
Encrypt a file with the given public key using either
CKM_RSA_PKCSa.k.a PKCS #1 RSA V1.5 as specified in PKCS#11 v2.40CKM_RSA_PKCS_OAEPa.k.a PKCS #1 RSA OAEP as specified in PKCS#11 v2.40CKM_RSA_AES_KEY_WRAPas specified in PKCS#11 v2.40
Usage
ckms rsa encrypt [options] <FILE>
Arguments
<FILE> The file to encrypt
--key-id [-k] <KEY_ID> The public key unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--encryption-algorithm [-e] <ENCRYPTION_ALGORITHM> The encryption algorithm
Possible values: "ckm-rsa-pkcs", "ckm-rsa-pkcs-oaep", "ckm-rsa-aes-key-wrap" [default: "ckm-rsa-pkcs-oaep"]
--hashing-algorithm [-s] <HASH_FN> The hashing algorithm
Possible values: "sha1", "sha224", "sha256", "sha384", "sha512", "sha3-224", "sha3-256", "sha3-384", "sha3-512" [default: "sha256"]
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
22.3 ckms rsa decrypt
Decrypt a file with the given private key using either
CKM_RSA_PKCSa.k.a PKCS #1 RSA V1.5 as specified in PKCS#11 v2.40CKM_RSA_PKCS_OAEPa.k.a PKCS #1 RSA OAEP as specified in PKCS#11 v2.40CKM_RSA_AES_KEY_WRAPas specified in PKCS#11 v2.40
Usage
ckms rsa decrypt [options] <FILE>
Arguments
<FILE> The file to decrypt
--key-id [-k] <KEY_ID> The private key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--encryption-algorithm [-e] <ENCRYPTION_ALGORITHM> The encryption algorithm
Possible values: "ckm-rsa-pkcs", "ckm-rsa-pkcs-oaep", "ckm-rsa-aes-key-wrap" [default: "ckm-rsa-pkcs-oaep"]
--hashing-algorithm [-s] <HASH_FN> The hashing algorithm (for OAEP and AES key wrap)
Possible values: "sha1", "sha224", "sha256", "sha384", "sha512", "sha3-224", "sha3-256", "sha3-384", "sha3-512" [default: "sha256"]
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
22.4 ckms rsa sign
Digital signature supported is RSASSA-PSS
Usage
ckms rsa sign [options] <FILE>
Arguments
<FILE> The file to sign
--key-id [-k] <KEY_ID> The private key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The signature output file path
--digested <DIGESTED> Treat input as already-digested data (pre-hash)
Possible values: "true", "false"
22.5 ckms rsa sign-verify
Verify an RSASSA-PSS signature for a given data file
Usage
ckms rsa sign-verify [options] <FILE> <SIGNATURE_FILE>
Arguments
<FILE> The data that was signed
<SIGNATURE_FILE> The signature file
--key-id [-k] <KEY_ID> The private key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> Optional output file path
--digested <DIGESTED> Treat data input as already-digested (pre-hash)
Possible values: "true", "false"
23 ckms opaque-object
Create, import, export, revoke and destroy Opaque Objects
Usage
ckms opaque-object <subcommand>
Subcommands
activate [23.1] Activate a cryptographic object (key, certificate, etc.)
create [23.2] Create (register) an OpaqueObject by importing raw bytes.
export [23.3] Export a key or secret data from the KMS
import [23.4] Import a secret data or a key in the KMS.
revoke [23.5] Revoke an OpaqueObject
destroy [23.6] Destroy an OpaqueObject
23.1 ckms opaque-object activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms opaque-object activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
23.2 ckms opaque-object create
Create (register) an OpaqueObject by importing raw bytes.
Usage
ckms opaque-object create [options]
Arguments
--file [-f] <FILE> Optional file containing the opaque bytes to import
--data [-d] <DATA> Inline opaque data as a UTF-8 string. If provided, it's used instead of --file bytes
--type <OPAQUE_TYPE> Opaque data type (defaults to Vendor)
--id <ID> Optional object unique identifier to assign; otherwise server generates one
--tag [-t] <TAG> Tags to associate with the object. Repeat to add multiple tags
23.3 ckms opaque-object export
Export a key or secret data from the KMS
Usage
ckms opaque-object export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
23.4 ckms opaque-object import
Import a secret data or a key in the KMS.
Usage
ckms opaque-object import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
23.5 ckms opaque-object revoke
Revoke an OpaqueObject
Usage
ckms opaque-object revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--key-id [-k] <OBJECT_ID> The opaque object unique identifier to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tags to locate the object if id is not provided. Repeat to specify multiple tags
23.6 ckms opaque-object destroy
Destroy an OpaqueObject
Usage
ckms opaque-object destroy [options]
Arguments
--key-id [-k] <OBJECT_ID> The opaque object unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tags to locate the object if id is not provided. Repeat to specify multiple tags
--remove <REMOVE> If the object should be removed from the database. If not specified, the object will be destroyed
but its metadata will still be available.
Possible values: "true", "false" [default: "false"]
24 ckms pkcs11
Verify PKCS#11 shared library integration
Usage
ckms pkcs11 <subcommand>
Subcommands
verify [24.1] Load the PKCS#11 shared library and exercise the standard API sequence
24.1 ckms pkcs11 verify
Load the PKCS#11 shared library and exercise the standard API sequence
Usage
ckms pkcs11 verify [options]
Arguments
--dll <PATH> Path to the PKCS#11 shared library (libcosmian_pkcs11.so / .dylib / .dll)
--conf <PATH> Explicit path to ckms.toml. When set, the CKMS_CONF environment variable is written before the library is loaded so that the provider picks up this configuration file
--token <JWT> Bearer token (OIDC/JWT) to pass to C_Login. Required when ckms.toml has pkcs11_use_pin_as_access_token = true
25 ckms secret-data
Create, import, export and destroy secret data
Usage
ckms secret-data <subcommand>
Subcommands
activate [25.1] Activate a cryptographic object (key, certificate, etc.)
create [25.2] Create a new secret data
export [25.3] Export a key or secret data from the KMS
import [25.4] Import a secret data or a key in the KMS.
wrap [25.5] Locally wrap a secret data or key in KMIP JSON TTLV format.
unwrap [25.6] Locally unwrap a secret data or key in KMIP JSON TTLV format.
revoke [25.7] Revoke a secret data
destroy [25.8] Destroy a secret data
25.1 ckms secret-data activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms secret-data activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
25.2 ckms secret-data create
Create a new secret data
Usage
ckms secret-data create [options] [SECRET_ID]
Arguments
--value [-v] <SECRET_VALUE> Optional secret data string, UTF-8 encoded. If not provided, a random 32-byte seed will be generated
--type <SECRET_TYPE> The type of secret data. Defaults to a randomly generated Seed. To use a Password type, you must provide both this and a valid secret value
Possible values: "password", "seed" [default: "seed"]
--tag [-t] <TAG> The tag to associate with the secret data. To specify multiple tags, use the option multiple times
<SECRET_ID> The unique id of the secret; a random uuid is generated if not specified
--sensitive <SENSITIVE> Sensitive: if set, the secret will not be exportable
Possible values: "true", "false" [default: "false"]
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this new secret data with.
If the wrapping key is:
- a symmetric key, AES-GCM will be used
- a RSA key, RSA-OAEP will be used
- a EC key, ECIES will be used (salsa20poly1305 for X25519)
25.3 ckms secret-data export
Export a key or secret data from the KMS
Usage
ckms secret-data export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
25.4 ckms secret-data import
Import a secret data or a key in the KMS.
Usage
ckms secret-data import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
25.5 ckms secret-data wrap
Locally wrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms secret-data wrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to wrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified, the input file is overwritten
--wrap-password [-p] <WRAP_PASSWORD> A password to wrap the imported key. This password will be derived into an AES-256 symmetric key. For security reasons, a fresh salt is internally generated by cosmian and handled, and this final AES symmetric key will be displayed only once
--wrap-key-b64 [-k] <WRAP_KEY_B64> A symmetric key as a base 64 string to wrap the imported key
--wrap-key-id [-i] <WRAP_KEY_ID> The ID of a wrapping key in the KMS that will be exported and used to wrap the key
--wrap-key-file [-f] <WRAP_KEY_FILE> A wrapping key in a KMIP JSON TTLV file used to wrap the key
25.6 ckms secret-data unwrap
Locally unwrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms secret-data unwrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to unwrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified the input file is overwritten
--unwrap-key-b64 [-k] <UNWRAP_KEY_B64> A symmetric key as a base 64 string to unwrap the imported key
--unwrap-key-id [-i] <UNWRAP_KEY_ID> The id of an unwrapping key in the KMS that will be exported and used to unwrap the key
--unwrap-key-file [-f] <UNWRAP_KEY_FILE> An unwrapping key in a KMIP JSON TTLV file used to unwrap the key
25.7 ckms secret-data revoke
Revoke a secret data
Usage
ckms secret-data revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--secret-data-id [-s] <SECRET_ID> The secret unique identifier of the secret to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the secret data when no secret data id is specified. To specify multiple tags, use the option multiple times
25.8 ckms secret-data destroy
Destroy a secret data
Usage
ckms secret-data destroy [options]
Arguments
--key-id [-s] <SECRET_ID> The secret unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the secret when no secret id is specified. To specify multiple tags, use the option multiple times
--remove <REMOVE> If the secret should be removed from the database
If not specified, the key will be destroyed
but its metadata will still be available in the database.
Please note that the KMIP specification does not support the removal of objects.
Possible values: "true", "false" [default: "false"]
26 ckms sym
Manage symmetric keys. Encrypt and decrypt data
Usage
ckms sym <subcommand>
Subcommands
keys [26.1] Create, destroy, import, and export symmetric keys
encrypt [26.2] Encrypt a file using a symmetric cipher
decrypt [26.3] Decrypt a file using a symmetric key.
26.1 ckms sym keys
Create, destroy, import, and export symmetric keys
Usage
ckms sym keys <subcommand>
Subcommands
activate [26.1.1] Activate a cryptographic object (key, certificate, etc.)
create [26.1.2] Create a new symmetric key
re-key [26.1.3] Refresh an existing symmetric key
export [26.1.4] Export a key or secret data from the KMS
import [26.1.5] Import a secret data or a key in the KMS.
wrap [26.1.6] Locally wrap a secret data or key in KMIP JSON TTLV format.
unwrap [26.1.7] Locally unwrap a secret data or key in KMIP JSON TTLV format.
revoke [26.1.8] Revoke a symmetric key
destroy [26.1.9] Destroy a symmetric key
set-rotation-policy [26.1.10] Set the automatic rotation policy on a key or key pair.
get-rotation-policy [26.1.11] Get the automatic rotation policy for a key or key pair.
26.1.1 ckms sym keys activate
Activate a cryptographic object (key, certificate, etc.)
Usage
ckms sym keys activate [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier of the key to activate. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
26.1.2 ckms sym keys create
Create a new symmetric key
Usage
ckms sym keys create [options] [KEY_ID]
Arguments
--number-of-bits [-l] <NUMBER_OF_BITS> The length of the generated random key or salt in bits
--bytes-b64 [-k] <WRAP_KEY_B64> The symmetric key bytes or salt as a base 64 string
--algorithm [-a] <ALGORITHM> The algorithm
Possible values: "chacha20", "aes", "sha3", "shake" [default: "aes"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
<KEY_ID> The unique id of the key; a random uuid is generated if not specified
--sensitive <SENSITIVE> Sensitive: if set, the key will not be exportable
Possible values: "true", "false" [default: "false"]
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this new key with.
If the wrapping key is:
- a symmetric key, AES-GCM will be used
- a RSA key, RSA-OAEP will be used
- a EC key, ECIES will be used (salsa20poly1305 for X25519)
--enroll-keyset [-n] <ENROLL_KEYSET> Enroll this key in a keyset so it can be addressed via name@latest,
name@first, name@N syntax. The keyset name is set automatically to
the key's own ID returned by the server.
Possible values: "true", "false" [default: "false"]
--rotation-interval <ROTATE_INTERVAL> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--rotation-offset <ROTATE_OFFSET> Offset in seconds from the initial date before the first rotation occurs
26.1.3 ckms sym keys re-key
Refresh an existing symmetric key
Usage
ckms sym keys re-key [options]
Arguments
--key-id [-k] <KEY_ID> The tag to associate with the key. To specify multiple tags, use the option multiple times
26.1.4 ckms sym keys export
Export a key or secret data from the KMS
Usage
ckms sym keys export [options] <KEY_FILE>
Arguments
<KEY_FILE> The file to export the key to
--key-id [-k] <KEY_ID> The key or secret data unique identifier stored in the KMS. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key or secret data id is specified. To specify multiple tags, use the option multiple times
--key-format [-f] <EXPORT_FORMAT> The format of the key
json-ttlv[default]. It should be the format to use to later re-import the keysec1-pemandsec1-deronly apply to NIST EC private keys (Not Curve25519 or X448)pkcs1-pemandpkcs1-deronly apply to RSA private and public keyspkcs8-pemandpkcs8-deronly apply to RSA and EC private keysrawreturns the raw bytes of- symmetric keys
- Covercrypt keys
- wrapped keys
- secret data
Possible values: "json-ttlv", "sec1-pem", "sec1-der", "pkcs1-pem", "pkcs1-der", "pkcs8-pem", "pkcs8-der", "base64", "raw" [default: "json-ttlv"]
--unwrap [-u] <UNWRAP> Unwrap the key if it is wrapped before export
Possible values: "true", "false" [default: "false"]
--wrap-key-id [-w] <WRAP_KEY_ID> The id of the key/certificate (a.k.a. Key Encryption Key - KEK) to use to wrap this key before export
--allow-revoked [-i] <ALLOW_REVOKED> Allow exporting revoked and destroyed keys.
The user must be the owner of the key.
Destroyed keys have their key material removed.
Possible values: "true", "false" [default: "false"]
--wrapping-algorithm [-m] <WRAPPING_ALGORITHM> Wrapping algorithm to use when exporting the key
The possible wrapping algorithms are
- using a symmetric KEK:
nist-key-wrap(default - a.k.a RFC 5649,CKM_AES_KEY_WRAP_PAD)aes-gcm
- using an RSA KEK:
rsa-oaep(default - CKM-RSA-OAEP)rsa-aes-key-wrap(CKM-RSA-AES-KEY-WRP)rsa-pkcs-v15(CKM-RSA v1.5)
Possible values: "aes-key-wrap-padding", "nist-key-wrap", "aes-gcm", "rsa-pkcs-v15-sha1", "rsa-pkcs-v15", "rsa-oaep-sha1", "rsa-oaep", "rsa-aes-key-wrap-sha1", "rsa-aes-key-wrap"
--authenticated-additional-data [-d] <AUTHENTICATED_ADDITIONAL_DATA> Authenticated encryption additional data Only available for AES GCM wrapping
26.1.5 ckms sym keys import
Import a secret data or a key in the KMS.
Usage
ckms sym keys import [options] <KEY_FILE> [KEY_ID]
Arguments
<KEY_FILE> The file holding the key or secret data to import
<KEY_ID> The unique ID of the key; a random UUID is generated if not specified
--key-format [-f] <KEY_FORMAT> The format of the key
Possible values: "json-ttlv", "pem", "sec1", "pkcs1-priv", "pkcs1-pub", "pkcs8-priv", "pkcs8-pub", "aes", "chacha20" [default: "json-ttlv"]
--public-key-id [-p] <PUBLIC_KEY_ID> For a private key: the corresponding KMS public key ID, if any
--private-key-id [-k] <PRIVATE_KEY_ID> For a public key: the corresponding KMS private key ID, if any
--certificate-id [-c] <CERTIFICATE_ID> For a public or private key: the corresponding certificate ID, if any
--unwrap [-u] <UNWRAP> In the case of a JSON TTLV key, unwrap the key if it is wrapped before storing it
Possible values: "true", "false" [default: "false"]
--replace [-r] <REPLACE_EXISTING> Replace an existing key under the same ID
Possible values: "true", "false" [default: "false"]
--tag [-t] <TAG> The tag to associate with the key. To specify multiple tags, use the option multiple times
--key-usage <KEY_USAGE> The cryptographic operations the key is allowed to perform
Possible values: "sign", "verify", "encrypt", "decrypt", "wrap-key", "unwrap-key", "mac-generate", "mac-verify", "derive-key", "key-agreement", "certificate-sign", "crl-sign", "authenticate", "unrestricted"
--wrapping-key-id [-w] <WRAPPING_KEY_ID> The key encryption key (KEK) used to wrap this imported key with.
If the wrapping key is:
- A symmetric key, AES-GCM will be used,
- An RSA key, RSA-OAEP with SHA-256 will be used,
- An EC key, ECIES will be used (salsa20poly1305 for X25519),
26.1.6 ckms sym keys wrap
Locally wrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms sym keys wrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to wrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified, the input file is overwritten
--wrap-password [-p] <WRAP_PASSWORD> A password to wrap the imported key. This password will be derived into an AES-256 symmetric key. For security reasons, a fresh salt is internally generated by cosmian and handled, and this final AES symmetric key will be displayed only once
--wrap-key-b64 [-k] <WRAP_KEY_B64> A symmetric key as a base 64 string to wrap the imported key
--wrap-key-id [-i] <WRAP_KEY_ID> The ID of a wrapping key in the KMS that will be exported and used to wrap the key
--wrap-key-file [-f] <WRAP_KEY_FILE> A wrapping key in a KMIP JSON TTLV file used to wrap the key
26.1.7 ckms sym keys unwrap
Locally unwrap a secret data or key in KMIP JSON TTLV format.
Usage
ckms sym keys unwrap [options] <KEY_FILE_IN> [KEY_FILE_OUT]
Arguments
<KEY_FILE_IN> The KMIP JSON TTLV input key file to unwrap
<KEY_FILE_OUT> The KMIP JSON output file. When not specified the input file is overwritten
--unwrap-key-b64 [-k] <UNWRAP_KEY_B64> A symmetric key as a base 64 string to unwrap the imported key
--unwrap-key-id [-i] <UNWRAP_KEY_ID> The id of an unwrapping key in the KMS that will be exported and used to unwrap the key
--unwrap-key-file [-f] <UNWRAP_KEY_FILE> An unwrapping key in a KMIP JSON TTLV file used to unwrap the key
26.1.8 ckms sym keys revoke
Revoke a symmetric key
Usage
ckms sym keys revoke [options] <REVOCATION_REASON>
Arguments
<REVOCATION_REASON> The reason for the revocation as a string
--reason-code [-r] <REASON_CODE> The revocation reason code [default: unspecified]
--key-id [-k] <KEY_ID> The key unique identifier of the key to revoke. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
26.1.9 ckms sym keys destroy
Destroy a symmetric key
Usage
ckms sym keys destroy [options]
Arguments
--key-id [-k] <KEY_ID> The key unique identifier. If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--remove <REMOVE> If the key should be removed from the database
If not specified, the key will be destroyed
but its metadata will still be available in the database.
Please note that the KMIP specification does not support the removal of objects.
Possible values: "true", "false" [default: "false"]
26.1.10 ckms sym keys set-rotation-policy
Set the automatic rotation policy on a key or key pair.
Usage
ckms sym keys set-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to set the rotation policy on
--interval [-i] <INTERVAL_SECS> Rotation interval in seconds. The key will be automatically re-keyed at this interval. Set to 0 to disable automatic rotation while preserving other policy fields
--offset [-o] <OFFSET_SECS> Offset in seconds from the initial date before the first rotation occurs
--rotation-name [-n] <ROTATE_NAME> A keyset name for addressing key generations via name@latest, name@first, name@N syntax. Must not contain the '@' character
26.1.11 ckms sym keys get-rotation-policy
Get the automatic rotation policy for a key or key pair.
Usage
ckms sym keys get-rotation-policy [options]
Arguments
--key-id [-k] <KEY_ID> The unique identifier of the key to get the rotation policy from
26.2 ckms sym encrypt
Encrypt a file using a symmetric cipher
Usage
ckms sym encrypt [options] <FILE>
Arguments
<FILE> The file to encrypt
--key-id [-k] <KEY_ID> The symmetric key unique identifier. If not specified, tags should be specified
--data-encryption-algorithm [-d] <DATA_ENCRYPTION_ALGORITHM> The data encryption algorithm. If not specified, aes-gcm is used
Possible values: "chacha20-poly1305", "aes-gcm", "aes-cbc", "aes-xts", "aes-gcm-siv" [default: "aes-gcm"]
--key-encryption-algorithm [-e] <KEY_ENCRYPTION_ALGORITHM> The optional key encryption algorithm used to encrypt the data encryption key.
Possible values: "chacha20-poly1305", "aes-gcm", "aes-xts", "aes-gcm-siv", "rfc3394", "rfc5649"
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
--nonce [-n] <NONCE> Optional nonce/IV (or tweak for XTS) as a hex string. If not provided, a random value is generated
--authentication-data [-a] <AUTHENTICATION_DATA> Optional additional authentication data as a hex string. This data needs to be provided back for decryption. This data is ignored with XTS
26.3 ckms sym decrypt
Decrypt a file using a symmetric key.
Usage
ckms sym decrypt [options] <FILE>
Arguments
<FILE> The file to decrypt
--key-id [-k] <KEY_ID> The private key unique identifier If not specified, tags should be specified
--tag [-t] <TAG> Tag to use to retrieve the key when no key id is specified. To specify multiple tags, use the option multiple times
--data-encryption-algorithm [-d] <DATA_ENCRYPTION_ALGORITHM> The data encryption algorithm.
If not specified, aes-gcm is used.
Possible values: "chacha20-poly1305", "aes-gcm", "aes-cbc", "aes-xts", "aes-gcm-siv" [default: "aes-gcm"]
--key-encryption-algorithm [-e] <KEY_ENCRYPTION_ALGORITHM> The optional key encryption algorithm used to decrypt the data encryption key.
Possible values: "chacha20-poly1305", "aes-gcm", "aes-xts", "aes-gcm-siv", "rfc3394", "rfc5649"
--output-file [-o] <OUTPUT_FILE> The encrypted output file path
--authentication-data [-a] <AUTHENTICATION_DATA> Optional authentication data that was supplied during encryption as a hex string
27 ckms markdown
Regenerate the CLI documentation in Markdown format
Usage
ckms markdown [options] <MARKDOWN_FILE>
Arguments
<MARKDOWN_FILE> The file to export the markdown to
28 ckms configure
Configure the KMS CLI (create ckms.toml)
Usage
ckms configure
KMS Authorizing users with access objects
When authentication is enabled, each KMS object requires explicit authorization from its owner to be accessed or used by others. The KMS CLI then allows to manage the access rights of users to cryptographic objects stored in the KMS.
Granting an access right
An owner of an object grants an access right to a specific user for a given operation on a given object.
The supported KMIP operations are: get, export, encrypt, decrypt, import, revoke, destroy.
➜ ckms access grant --help
Grant another user an access right to an object.
This command can only be called by the owner of the object.
The right is granted for one of the supported KMIP operations: create, get, encrypt, decrypt, import, revoke, locate, rekey, destroy
Usage: ckms access grant <USER> <OBJECT_UID> <OPERATION>
Arguments:
<USER>
The user identifier to allow
<OBJECT_UID>
The object unique identifier stored in the KMS
<OPERATION>
The KMIP operation to allow
Options:
-h, --help
Print help (see a summary with '-h')
POST to the /access/grant endpoint with the JSON object:
{
"unique_identifier": "1ae2...25df", // the object unique identifier
"user_id": "john.doe@acem.com", // the user identifier to allow
"operation_type": "get" // the KMIP operation to allow
}
The response is a JSON object:
{
"success": "a success message"
}
Revoking an access right
An owner of an object can revoke an access right to a specific user for a given operation on a given object at any time.
➜ ckms access revoke --help
Revoke another user access right to an object.
This command can only be called by the owner of the object.
Usage: ckms access revoke <USER> <OBJECT_UID> <OPERATION>
Arguments:
<USER>
The user to revoke access to
<OBJECT_UID>
The object unique identifier stored in the KMS
<OPERATION>
The operation to revoke (create, get, encrypt, decrypt, import, revoke, locate, rekey, destroy)
Options:
-h, --help
Print help (see a summary with '-h')
POST to the /access/revoke endpoint with the JSON object:
{
"unique_identifier": "1ae2...25df", // the object unique identifier
"user_id": "john.doe@acem.com", // the user identifier to allow
"operation_type": "get" // the KMIP operation to allow
}
The response is a JSON object:
{
"success": "a success message"
}
Listing an object access rights
The owner of an object can list all the access rights that have been granted to another object.
➜ ckms access list --help
List the access rights granted on an object to other users.
This command can only be called by the owner of the object. Returns a list of users and the operations they have been granted access to.
Usage: ckms access list <OBJECT_UID>
Arguments:
<OBJECT_UID>
The object unique identifier
Options:
-h, --help
Print help (see a summary with '-h')
GET to the /access/list/{object_unique_id} endpoint:
The response is a JSON array:
[
{
"user_id": "the user identifier the access rights are granted to",
"operations": [ <operation type> ]
}
]
where <operation type> is one of the following: export, get, encrypt, decrypt, import, revoke, destroy.
Listing the objects owned by a user
A user can list all the objects it owns (i.e. the objects it created using either the Create, CreateKeyPair,
or Import KMIP operations).
➜ ckms access owned --help
List the objects owned by the calling user.
Owners of objects can perform any operation on these objects and can grant access rights on any of these operations to any other user.
Usage: ckms access owned
Options:
-h, --help
Print help (see a summary with '-h')
GET to the /access/owned endpoint:
The response is a JSON array:
[
{
"object_id": "the object unique identifier",
"state": "<state>",
"attributes": "<attributes>",
"is_wrapped": "<wrapped_state>"
}
]
where:
<state>is one of the following KMIP states:PreActive,Active,Deactivated,Compromised,Destroyed_Compromised,<attributes>is the KMIP Attributes structure (see the KMIP documentation)<wrapped_state>: is a boolean indicating whether the object is wrapped or not (see key wrapping).
Listing the access rights obtained by a user
A user can list all the access rights that have been granted to it by object owners.
➜ ckms access obtained --help
List the access rights obtained by the calling user
Returns a list of objects, their state, their owner and the accesses rights granted on the object
Usage: ckms access obtained
Options:
-h, --help
Print help (see a summary with '-h')
GET to the /access/obtained endpoint:
The response is a JSON array:
[
{
"object_id": "the object unique identifier",
"owner_id": "the user identifier of the owner of the object",
"state": "<state>",
"operations": [ <operation type> ]
"attributes": "<attributes>",
"is_wrapped": "<wrapped_state>"
}
]
where:
<state>is one of the following KMIP states:PreActive,Active,Deactivated,Compromised,Destroyed_Compromised,<operation type>is one of the following:export,get,encrypt,decrypt,import,revoke,destroy,<wrapped_state>: is a boolean indicating whether the object is wrapped or not (see key wrapping).
S/MIME Gmail service account configuration
When using S/MIME, the gmail_api_conf field should be set in the configuration file to provide
the necessary information about the configured service account to interact with Gmail API, and
handle
identities and keypairs easily from the ckms.
This configuration is mandatory for ckms google subcommands.
The gmail_api_conf field is a TOML object with the following fields:
typeproject_idprivate_key_idprivate_keyclient_emailclient_idauth_uritoken_uriauth_provider_x509_cert_urlclient_x509_cert_urluniverse_domain
I can be retrieved directly from a TOML file downloaded from Google interface when creating and configuring the service account (following Google documentation).
Example:
[http_config]
server_url = "http://127.0.0.1:9998"
[gmail_api_conf]
type = "service_account"
project_id = "project_id"
private_key_id = "abc123abc123abc123abc123abc123abc123"
private_key = "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
client_email = "xxx@yyyy.iam.gserviceaccount.com"
client_id = "12345678901234567890"
auth_uri = "https://accounts.google.com/o/oauth2/auth"
token_uri = "https://oauth2.googleapis.com/token"
auth_provider_x509_cert_url = "https://www.googleapis.com/oauth2/v1/certs"
client_x509_cert_url = "https://www.googleapis.com/robot/v1/metadata/x509/xxx%40yyyy.iam.gserviceaccount.com"
universe_domain = "googleapis.com"
Eviden VM
Eviden VM offers:
- a hardened pre-configured Linux distribution (based on Ubuntu 22.04 or RHEL 9) with LUKS disk encryption designed for confidential computing machines.
- a seamless, unique experience across all confidential hardware (Intel TDX, AMD SEV-SNP, soon NVIDIA H100) and cloud providers (AWS, Azure, GCP)
- an extended verifiability of the hardware, OS, and binaries running on the VM.
Specifically, the Eviden VM provides the following features:
- Confidentiality: the whole environment runs in a Trusted Execution Environment (TEE) with encrypted memory on top of encrypted storage.
- Verifiability: the user can verify the integrity of the hardware, OS, and executables at any time and compare them against a reference snapshot
- Genericity: compatible with AMD SEV-SNP, Intel TDX, and TPM or vTPM. Works identically on all cloud providers.
- No code modification: no third-party library or any change to applications
- Simplicity: manual configuration is reduced to the bare minimum. A Linux administrator enjoys the same experience as that of a standard VM.
Use cases
Eviden VM is used in these two scenarios:
- Quickly migrate an on-premise application to the public cloud without modifications while running it with the same level of confidentiality, e.g., migrating an HR application to the cloud.
- offer confidential SaaS services to your customers/users, protecting their privacy against the cloud provider and any extra-territorial law, e.g., offering confidential AI/Gen. AI in the public cloud.
Eviden VM is designed to secure your application against passive (honest-but-curious) and active (malicious) cloud provider staff member
Extended Verifiability
Eviden VM provides memory and disk encryption on a hardened system and extends the hardware remote attestation supplied by Intel and AMD to the verifiability of the operating system, as well as the binary files or other files marked as verifiable on the system. A user can quickly check the integrity of the whole system (no hardware change, no OS change, known binaries running or having run) before sending sensitive data for processing.
To do this, Eviden VM builds on the following components:
- Trusted Execution Environment (TEE) such as AMD SEV-SNP or Intel TDX for memory encryption
- Trusted Platform Module (TPM) or vTPM (virtual TPM) to store secrets and attest the content of some memory region
- Integrity Measurement Architecture (IMA), a Linux kernel module used to maintain a measurement log of all executables
To securely tie these components together, Eviden VM image contains the following software:
cosmian_vm_agent: an agent running in the confidential VM to forward attestations, collaterals (e.g. root certificates) and measurement logcosmian_fstoolto ease the generation of LUKS container with the secret key stored in the TPM/vTPM (automount on reboot)
Our client CLI cosmian_vm can be used to interact with cosmian_vm_agent and verify the trustworthiness of a specific instance launched with Eviden VM as base image.
Eviden VM image construction process can be found in this repository: https://github.com/Cosmian/cosmian_vm/packer
Usage
Setup flow
An Eviden VM is instantiated from a cloud provider marketplace on top of a confidential computing machine. Once the system administrator has installed the application and its dependencies, a snapshot of the VM is taken. Integrity checks can then be performed on the running VM to verify the running code, OS, and hardware.
Snapshot of the system
The snapshot of the system is a crucial step performed by cosmian_vm_agent to produce a JSON file with:
- TEE policy
- TPM policy
- List of measured files and their hash digests
It's a one-time process that is done before you decide to freeze the instance and expect no more modification.
The content will be compared against TEE attestation, TPM/vTPM attestation and IMA measurement log to verify the trustworthiness of the remote instance.
Verification of the remote instance
The verification process of the Eviden VM is performed using client CLI cosmian_vm, which will check:
- IMA (Integrity Measurement Architecture) measurement log with the list of executable and configuration file's hash digest, to be compared against the snapshot
- TPM (Trusted Platform Module) attestation of the IMA measurement log
- TEE (Trusted Execution Environment) attestation to ensure the instance is running on secure hardware with encrypted memory
The verification is successful if files in IMA measurement log and snapshot have the same hash digests, TPM or vTPM correctly attested the IMA measurement log content and finally if TEE attestation is valid.
Cloud providers support
Eviden VM already supports AMD SEV-SNP and Intel TDX but it might depend on the cloud provider.
AWS images
| Official image | OS image | OS version | Kernel version | Eviden base image | |
|---|---|---|---|---|---|
| AWS - AMD SEV | ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-v20251212 | Ubuntu | 24.04 | 6.17.0-1007-aws | base-image-X-Y-Z-ubuntu-sev |
| AWS - AMD SEV | RHEL-9.4.0_HVM-20250519-x86_64-0-Hourly2-GP3 | Redhat | 9.4 | 5.14.0-427.37.1.el9_4.x86_64 | base-image-X-Y-Z-ubuntu-sev |
Azure images
| Official image | OS image | OS version | Kernel version | Eviden base image | Version | |
|---|---|---|---|---|---|---|
| Azure - Intel TDX | Canonical-ubuntu-24_04-lts-cvm | Ubuntu | 24.04 | 6.8.0-1020-azure | base-image-ubuntu-tdx | X.Y.Z |
| Azure - AMD SEV | Canonical-ubuntu-24_04-lts-cvm | Ubuntu | 24.04 | 6.17.0-1010-azure-fde | base-image-ubuntu-sev | X.Y.Z |
| Azure - Intel TDX | Redhat-rhel-cvm-9_4_cvm | Redhat | 9.4 | 5.14.0-427.37.1.el9_4.x86_64 | base-image-rhel-tdx | X.Y.Z |
| Azure - AMD SEV | Redhat-rhel-cvm-9_4_cvm | Redhat | 9.4 | 5.14.0-427.37.1.el9_4.x86_64 | base-image-rhel-sev | X.Y.Z |
GCP images
| Official image | OS image | OS version | Kernel version | Eviden base image | |
|---|---|---|---|---|---|
| GCP - Intel TDX | ubuntu-2404-noble-amd64-v20260225 | Ubuntu | 24.04 | 6.17.0-1008-gcp | base-image-X-Y-Z-ubuntu-tdx |
| GCP - AMD SEV | ubuntu-2404-noble-amd64-v20260517 | Ubuntu | 24.04 | 6.17.0-1018-gcp | base-image-X-Y-Z-ubuntu-sev |
| GCP - AMD SEV | rhel-9-v20251016 | Redhat | 9.6 | 5.14.0-570.52.1.el9_6.x86_64 | base-image-X-Y-Z-rhel-sev |
| GCP - Intel TDX | rhel-9-v20251016 | Redhat | 9.6 | 5.14.0-570.52.1.el9_6.x86_64 | base-image-X-Y-Z-rhel-tdx |
Marketplace Image content
The Eviden VM image built on the marketplaces of GCP, Azure, or AWS contains four primary executables:
-
cosmian_vm_agentis designed to be deployed on the Eviden VM. It serves on demand the collaterals used to verify the trustworthiness of the Eviden VM, such as the IMA file, the TEE quote, or the TPM quote -
cosmian_fstoolis designed to generate a LUKS container and enroll the TPM to be automatically started on reboot -
cosmian_vmis a CLI designed to be used on your host. It queries thecosmian_vm_agentto get the collaterals used to verify the integrity/trustworthiness of the Eviden VM
This image:
- contains the fully configured IMA
- contains the fully configured SELinux
- disables the auto-update (to avoid any modification of the Eviden VM after having snapshotted it)
- contains the fully configured
cosmian_vm_agent
This is an abstract of the updated file tree:
.
├── etc
│ ├── apt
│ │ └── apt.conf.d
│ │ └── 10periodic
│ ├── cosmian_vm
│ │ └── agent.toml
│ ├── default
│ │ └── grub
│ ├── ima
│ │ └── ima-policy
│ └── systemd
│ └── system
│ ├── cosmian_vm_agent.service
│ └── mount_luks.service
├── root
│ ├── mount_luks.sh
├── usr
│ └── local
| └── bin
│ ├── cosmian_fstool
│ └── cosmian_vm_agent
└── var
└── lib
└── cosmian_vm
├── container <--- LUKS container
├── tmp
└── data <--- LUKS container mounted
├── cert.pem
└── cert.key
First, read detailed information about Eviden VM or about Eviden VM Agent and related software tools functioning.
As a reminder, the Eviden VM's goal is to verify Confidential VM trustworthiness and integrity at anytime. This verification runs on the operating system where one or more applications have been installed.
First, a snapshot is generated, freezing the state of the system and all executable files.
Then, at anytime, a remote verification of the VM can be done using the Eviden VM CLI tool (cosmian_vm).
The Eviden VM can be deployed on virtual machines that supports AMD SEV-SNP or Intel TDX technologies.
The following steps help to deploy a Eviden VM instance on any supported cloud provider.
The Eviden VM contains a set of software to ensure trustworthiness of the executable environment of the VM.
Then, the deployment flow is the following:
- instantiate a Eviden Confidential VM,
- connect on this VM and install everything required for your application to run correctly,
- create for once a VM snapshot remotely using Cosmian VM CLI,
- verify at anytime the integrity of the VM
Instantiate Eviden VM on your favorite cloud provider 🚚
Go the Eviden marketplace webpage of the chosen cloud provider:
- Eviden VM/KMS/AI on AWS Marketplace
- Eviden VM/KMS/AI on Azure Marketplace
- Eviden VM/KMS/AI on GCP Marketplace
Select an OS, set an external IP and continue until the Eviden VM instance is spawned.
Here's the list of instance types by cloud provider
| Cloud provider | Azure | GCP | AWS |
|---|---|---|---|
| AMD | SNP | SNP | SNP |
| Standard_DCas_v5 | n2d-standard | M6a | |
| Standard_DCads_v5 | C6a | ||
| R6a | |||
| Intel | TDX | TDX | TDX |
| DCes_v5-series | c3-standard | Not available | |
| ECesv5-series | |||
| (preview) |
Customize your VM 👩🔧
Connect to the spawned Eviden VM using SSH and install whatever is required for application and services to run (installing software and dependencies, setting-up configurations and services etc.).
For example, deploy an app and setup it as a Linux service.
Snapshot the VM remotely
Once the VM is configured as needed, Eviden VM Agent can do a snapshot of the VM containing fingerprint of the executables and metadata related to TEE and TPM.
Install the Eviden VM CLI on your local machine
Install the Eviden VM CLI on a local machine
Download the binary and allow it to be executed:
sudo apt update && sudo apt install -y wget
wget https://package.cosmian.com/cosmian_vm/1.3.21/ubuntu-22.04/cosmian-vm_1.3.21-1_amd64.deb
sudo apt install ./cosmian-vm_1.3.21-1_amd64.deb
cosmian_vm --version
Download the binary and allow it to be executed:
sudo apt update && sudo apt install -y wget
wget https://package.cosmian.com/cosmian_vm/1.3.21/ubuntu-24.04/cosmian-vm_1.3.21-1_amd64.deb
sudo apt install ./cosmian-vm_1.3.21-1_amd64.deb
cosmian_vm --version
Download the binary and allow it to be executed:
sudo dnf update && dnf install -y wget
wget https://package.cosmian.com/cosmian_vm/1.3.21/rhel9/cosmian_vm-1.3.21-1.x86_64.rpm
sudo dnf install ./cosmian_vm-1.3.21-1.x86_64.rpm
cosmian_vm --version
Start a Ubuntu-based Docker container and enter it:
docker run -it ubuntu:22.04 /bin/bash
Download the binary and allow it to be executed:
apt update && apt install -y wget
wget https://package.cosmian.com/cosmian_vm/1.3.21/ubuntu-22.04/cosmian-vm_1.3.21-1_amd64.deb
apt install ./cosmian-vm_1.3.21-1_amd64.deb
Generate a snapshot of the Eviden VM:
cosmian_vm --url https://${COSMIAN_VM_IP_ADDR}:5555 --allow-insecure-tls snapshot
Verify the VM snapshot
Take a look at the global flow to fully understand the whole verification process of a Eviden VM.
Previous downloaded snapshot is stored as cosmian_vm.snapshot file (see the previous step).
- At anytime, the Eviden VM integrity can be verified by running:
cosmian_vm --url https://${COSMIAN_VM_IP_ADDR}:5555 --allow-insecure-tls \
verify --snapshot cosmian_vm.snapshot
When the agent starts (see step Snapshot the VM) self-signed certificate is created to enable HTTPS out of the box.
The self-signed certificate can be replaced by a certificate signed by a trusted authority such as Let's Encrypt (see certbot for certificate generation).
Deploy your application as a service
The benefit of setting the deployed app as a service is that Eviden VM Agent is able to:
- handle the lifetime cycle of the app (start, stop, restart)
- deploy safely (in encrypted folder) the config file
Setup the systemd service
Connect to the Eviden VM instance through SSH to perform this setup.
-
write a service file (here compatible with
systemctl)[Unit] Description=My App Requires=multi-user.target After=multi-user.target mount_luks.service cosmian_vm_agent.service [Service] Type=simple User=root ExecStart=/usr/local/bin/my_app Restart=on-failure RestartSec=3s Environment="MY_APP_CONF=/var/lib/cosmian_vm/data/app/app.conf" [Install] WantedBy=multi-user.target
Any provided config file will be renamed to `app.conf` and will be stored as filepath `/var/lib/cosmian_vm/data/app/app.conf`, so the app `my_app` may know the location of configuration file.
Here the env variable `MY_APP_CONF` is used to forward this information to `my_app`.
- register the new service to
systemctl
Copy the my_app.service file into /etc/systemd/system/my_app.service and enable this service (without starting it, Cosmian VM Agent that will be responsible of starting it)
sudo systemctl enable my_app
sudo systemctl daemon-reload
Note: my_app and my_app_svc are indicative naming and can be changed, but don't forget to update the Eviden VM Agent config file (/etc/cosmian_vm/agent.toml) as well.
Configure the remote app safely
On the local machine, write the config file of the app, and then use the Eviden VM CLI to remotely configure the app.
-
write the app config file
[my_cfg] key = "value" secret = "a98jfdol"The format (TOML, JSON, INI...) of this config file depends on the app but the Eviden VM CLI doesn't care, as the config file is treated as a blob of bytes.
-
send the configuration using
cosmian_vmCLIcosmian_vm --url https://app.company.com app init -c my_app.tomlThe app conf is written in the encrypted folder.
Eviden VM Agent start/restart automatically the app after writing the config file when
initis called.
Control the remote app as a service
The cosmian_vm CLI also contains two subcommands designed to drive your application running inside the Cosmian VM.
It could be relevant if the personnel in charge of the application doesn't have the rights to connect to the Cosmian VM through SSH for instance.
If your Eviden VM is reachable over Internet, be aware that anyone can control your application. Out of the box the access to the cosmian_vm_agent endpoints is not authenticated.
Before going any further, you need to add a paragraph app inside the Cosmian VM configuration file, as follow:
[agent]
host = "0.0.0.0"
port = 5555
ssl_certificate = "data/cosmianvm.cosmian.dev/cert.pem"
ssl_private_key = "data/cosmianvm.cosmian.dev/key.pem"
tpm_device = "/dev/tpmrm0"
[app]
service_type = "systemd"
service_name = "my_app"
app_storage = "data/app"
The service_type could be standalone, systemd or supervisor and defines the way to start/stop the application.
The service_name field defines the name of the service or the binary to start/stop.
The app_storage field defines the root path where the application will store its data. If it's a relative path, the root path will be located inside /var/lib/cosmian_vm/. If you put it in the subfolder data, this directory is therefore encrypted and protected from the cloud provider.
Only the data/app/ part is customizable in the Cosmian VM Agent config file (/etc/cosmian_vm/agent.toml), but it remains relative to /var/lib/cosmian_vm/.
Keep in mind that /var/lib/cosmian_vm/data is the mount point of the encrypted folder.
Anything outside this folder is NOT encrypted!
Let's imagine, the application is installed in the Cosmian VM but not configured and started. Then, you can provide a configuration file (containing secrets for instance) and start it using:
cosmian_vm --url https://app.company.com app init --conf app.json
Also, if needed, the application can be restarted using:
cosmian_vm --url https://app.company.com app restart
The configuration file can be anything the application expects. Here, a json file. It will be sent to the cosmian_vm_agent and stored in the LUKS container in /var/lib/cosmian_vm/data/app/app.conf.
If you call again init the previous configuration file is overwritten.
Advanced settings
Eviden VM logs
The logs of Cosmian VM are written in journalctl and can be accessed via journalctl -exu cosmian_vm_agent.
Temporary folder
Cosmian VM also contains an encrypted RAMFS in /var/lib/cosmian_vm/tmp.
The data stored inside is volatile and will be deleted when rebooting the VM. The size of this directory is 500MB.
Data protection on the filesystem
Out of the box, Cosmian VM filesystem is not entirely protected against the cloud provider.
However, there are two ways to store securely sensitive data:
- LUKS container
- RAMFS
Encrypted folder
At the first start of cosmian_vm_agent, a LUKS container is created at /var/lib/cosmian_vm/container (size=500MB).
This container is mounted into /var/lib/cosmian_vm/data. This directory can be used to store any sensitive data (ie: to store TLS certificate).
The password of the LUKS container is stored inside the LUKS itself, and can be used to migrate the container to another VM for example.
With Cosmian VM the LUKS is enrolled on the current TPM therefore the password won't be asked again, even at reboot.
To change the size of the container, create it again:
cosmian_fstool --size 100GB --location /data/container
Define your own container size and save the container to an additional disk for back-up (/data/container in this example).
A prompt will invite you to set the password. Save this password as it could be useful if you want to migrate the container to another VM.
If you need to manage the container (extend its size, revoke the password, etc.), you can use cryptsetup.
The fields ssl_certificate and ssl_private_key could be relative paths. In that case, this is always relative to /var/lib/cosmian_vm/.
Add measurement of scripts and configuration files
When using Cosmian VM with RHEL distribution, SELinux is enabled and configured in enforced mode.
The SELinux module named cosmiand is present in Cosmian VM with 4 custom labels measured by Integrity Measurement Architecture (IMA):
cosmiand_exec_tfor Cosmian VM related binaries which will transition tocosmiand_tcosmiand_tfor daemons when the binary file is labeled withcosmian_exec_tcosmiand_script_tfor any script file such as Python, Perl or shell scriptscosmiand_conf_tfor Cosmian VM configuration files
Because IMA only tracks binaries loaded in memory, cosmiand_script_t and cosmiand_conf_t allow to label specific files read by interpreters or applications.
It will ensure that these files are not modified after the snapshot.
To label a new file, use semanage and restorecon commands:
# change SELinux context (always use absolute path)
semanage fcontext -a -t cosmiand_script_t "$(realpath my_script.py)"
# restore default context to apply the change (always use absolute path)
restorecon -v "$(realpath my_script.py)"
then you can see the new context with:
$ ls -Z
system_u:object_r:cosmiand_script_t:s0 my_script.py
See RHEL SELinux documentation for more details and advanced usage of SELinux.
Cosmian VM Agent lifecycle
Cosmian VM Agent can be started/restarted/stopped.
Start the agent:
systemctl start cosmian_vm_agent
Restart the agent
systemctl restart cosmian_vm_agent
Stop the agent
systemctl stop cosmian_vm_agent
Configure Cosmian VM Agent
Cosmian VM Agent relies on a configuration file located at /etc/cosmian_vm/agent.toml.
A minimal configuration file is:
[agent]
host = "127.0.0.1"
port = 5555
ssl_certificate = "data/cert.pem"
ssl_private_key = "data/key.pem"
tpm_device = "/dev/tpmrm0"
By default, cosmian_vm_agent uses the port 5555 on localhost.
Configure HTTPS with your own domain
On a fresh install, cosmian_vm_agent uses a self-signed certificate generated at the start of the service and set the CommonName of the certificate to the value of the machine hostname.
Therefore when using the CLI, --allow-insecure-tls must be added to ignore SSL errors (due to self-signed cert). This is not a good practice in production.
To enable HTTPS with trusted certs:
-
Edit your DNS registry to point to that VM
-
Create a trusted certificate using the method of your choice (Let's encrypt for instance)
-
Edit the
nginxconfiguration file to point to the location of the TLS certificate and private key:server { ... ssl_certificate /var/lib/cosmian_vm/data/cert.pem; ssl_certificate_key /var/lib/cosmian_vm/data/key.pem; } -
Edit the
cosmian_vm_agentconfiguration file to point to the location of the TLS certificate and private key:[agent] ... ssl_certificate = "data/cert.pem" ssl_private_key = "data/key.pem" -
Restart both services
sudo systemctl restart nginx sudo systemctl restart cosmian_vm_agent
Configure HTTPS with another certs
This configuration example sets the certificate from another application running in Cosmian VM:
[agent]
host = "0.0.0.0"
port = 5555
ssl_certificate = "/etc/letsencrypt/live/app.company.com/fullchain.pem"
ssl_private_key = "/etc/letsencrypt/live/app.company.com/privkey.pem"
tpm_device = "/dev/tpmrm0"
Note: in this case, fullchain.pem and privkey.pem are not located in the LUKS (under /var/lib/cosmian_vm/data/) so they are stored in cleartext on the disk hence potentially accessible by the Cloud Provider.
If you want to store these certificate securely, move them into the LUKS and change the location in the agent.toml file (don't forget to do the same for Nginx if applicable) like this:
[agent]
...
ssl_certificate = "data/fullchain.pem" # equivalent to /var/lib/cosmian_vm/data/fullchain.pem
ssl_private_key = "data/privkey.pem" # equivalent to /var/lib/cosmian_vm/data/privkey.pem
By setting a relative path, the agent will complete the path using the default mounted path for the LUKS, which is /var/lib/cosmian_vm/data (read here for more information about LUKS setup).
Snapshot deep dive
Take a snapshot of the remote system
cosmian_vm --url https://app.company.com snapshot
The snapshot is performed by cosmian_vm_agent to produce a single file with the trusted state of the machine at the current time.
This file is returned to the Cosmian VM CLI when using the subcommand snapshot.
The snapshot file is a JSON file containing:
- IMA measurement log at the current time
- List of all measured files and their corresponding hash (
sha256by default) - TEE metadata
- TPM metadata
Here is a sample:
{
"tee_policy":{
"Sev":{
"measurement":"73797518025d1d20e09efdf10e383cd0115e00562109b04ec577b5bd5d2ddab12f1f9ee22758f50a121355cf5aac6507",
"report_data":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"family_id":"00000000000000000000000000000000",
"image_id":"00000000000000000000000000000000",
"guest_svn":0,
"id_key_digest":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"author_key_digest":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"policy":196608,
"report_id":"b6db1e43f868a4823f708df92942a0448750fc5c37f7a724bc49292ffd111e1a",
"report_id_ma":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
},
"tpm_policy":{
"reset_count":15,
"restart_count":0
},
"filehashes":[
["/snap/google-cloud-cli/187/platform/gsutil/third_party/mock/mock/__pycache__/__init__.cpython-39.pyc", "f708df92942a044875[...]abc"],
...
]
}
Verification with multiple domains
Typically, the verification is done using the CLI as follow:
cosmian_vm --url https://app.company.com verify \
--snapshot cosmian_vm.snapshot
When verifying a Cosmian VM you can also check that the TLS certificate of your services installed inside this VM are the one used when querying the Cosmian VM Agent during the verification.
The goal is to verify your services currently running inside this Cosmian VM.
To do so, use --application as many times as needed:
cosmian_vm --url https://app.company.com verify \
--snapshot cosmian_vm.snapshot \
--application service1.company.com:3655 \
--application service2.company.com
Verification failure after reboot
Due to the IMA design, the VM cannot be trusted after a reboot. Indeed the IMA is reset at each restart.
Cosmian VM uses the TPM to detect a VM reboot: if the reset counter differs from the one captured during the snapshot, the verification fails.
If this reboot is trusted (for instance it has been made by the system administrator), you just need to ask for a new snapshot.
If the reboot occurs without the system administrator consent, the VM should be investigated to detect any malicious modification.
Cosmian VM diff with a Ubuntu/RHEL base image
The modifications are related to the installation and the configuration of Cosmian VM software stack. All the changes are performed using Packer and can be found in Cosmian VM Github page.
Cosmian VM image:
- contains the fully configured IMA
- contains the fully configured SELinux (RHEL only)
- disables the auto-update (see Disabled auto-update)
- contains the fully configured
cosmian_vm_agent
This is an abstract of the updated file tree:
.
├── etc
│ ├── apt
│ │ └── apt.conf.d
│ │ └── 10periodic
│ ├── cosmian_vm
│ │ └── agent.toml
│ ├── default
│ │ └── grub
│ ├── ima
│ │ └── ima-policy
│ └── systemd
│ └── system
│ └── cosmian_vm_agent.service
├── usr
│ └── local
│ └── bin
│ ├── cosmian_fstool
│ └── cosmian_vm_agent
└── var
└── lib
└── cosmian_vm
├── container <--- LUKS container
├── tmp
└── data <--- LUKS container mounted
├── cert.pem
└── cert.key
Disabled auto-update
The verification performed by the Cosmian VM relies on the fact that once the snapshot has been made, the VM content shouldn't be altered. If any modification is detected, the VM is considered compromised.
An auto-update processing alters the VM and makes the comparison with the snapshot impossible.
You shall update the Eviden VM manually and create a new snapshot afterwards.
Use a proxy in front of the Cosmian VM Agent
Although it's technically possible to configure an HTTPS proxy in front of the Cosmian VM Agent, it will prevent you from proceeding the verification through the CLI if you configure the proxy as an SSL forward.
Indeed, the TLS certificate configured in the Cosmian VM Agent is a part of the exchange with the TEE. To avoid any malicious software to send fake collaterals, the TLS certificate used to get these collaterals should be the same as the one configured in the Cosmian VM Agent. This certificate should stay inside the Cosmian VM.
If you use a proxy, the TLS tunnel, from the CLI to the agent, uses the certificate of the proxy and not the certificate of the agent. The verification will therefore fail, being not able to determine if it's a malicious or healthy behavior.
However, if you use a proxy as an SSL passthrough, it will work like a charm.
Here is an example with HAProxy:
[...]
defaults
mode tcp
option tcplog
[...]
# Entrypoint of the ha_proxy listen on 443
frontend https-in
# Do not decrypt ssl yet
bind *:443
tcp-request inspect-delay 60s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend 8d14ff4ac2d452c3.cosmian.io if { req_ssl_sni -i 8d14ff4ac2d452c3.cosmian.io }
# No default backend: return an error as fallback
backend 8d14ff4ac2d452c3.cosmian.io
server haproxy-app 162.19.91.151:27283 check
Other resources:
Azure instantiation
Step by step guide







AWS instantiation
Step by step guide




GCP instantiation
Step by step guide



Eviden AI
Eviden AI aims to perform query over an AI runner (summary, translation, query, RAG) in a secured workflow.
Deploy Eviden VM AI
Follow the instructions from the deployment guide.
Hardware optimization
When running on Intel Xeon processors, the application can leverage AMX (Advanced Matrix Extensions) to significantly enhance performance, especially for matrix-intensive operations commonly found in machine learning workloads. To enable this feature, simply start the application with the "use_amx" key to true from your config file.
{
"use_amx": true, // Optional - default set to false
}
HuggingFace authentication
To use certain Hugging Face models—such as the one required by the Translation endpoint—you must provide a Hugging Face access token. This token should be configured in the application's configuration file.
{
"hf_token": "hf_token", // Mandatory (used for translation models)
}
Usage
Eviden AI Runner exposes endpoints which can be fetched:
Summarize text
Summary is made using "facebook/bart-large-cnn" model.
- Endpoint:
/summarize - Method: POST
- Description: get the summary of a given text, using the configured model
- Request:
- Headers: 'Content-Type: multipart/form-data'
- Body:
doc- text to summarize, using model configured on summary config section
- Response:
{
"summary": "summarized text..."
}
- Example:
curl 'http://0.0.0.0:5000/summarize' \
--form 'doc="Il était une fois, dans un royaume couvert de vert émeraude et voilé dans les secrets murmurants des arbres anciens, vivait une princesse nommée Elara.."'
Translate text
Translation is made using one of the "Helsinki-NLP/opus-mt" models.
- Endpoint:
/translate - Method: POST
- Description: get the translation of a given text, using model configured on translation config section
- Request:
- Headers: 'Content-Type: multipart/form-data'
- Body:
doc- text to translatesrc_lang- source languagetgt_lang- targeted language
- Response:
{ "translation": "translated text..." } - Example:
curl 'http://0.0.0.0:5000/translate' \ --form 'doc="Il était une fois, dans un royaume couvert de vert émeraude et voilé dans les secrets murmurants des arbres anciens, vivait une princesse nommée Elara.."' --form 'src_lang=fr' --form 'tgt_lang=en'
Predict using text as context
- Endpoint:
/context_predict - Method: POST
- Description: get prediction from a model using current text as a context
- Request:
- Headers: 'Content-Type: multipart/form-data'
- Body:
context- text to use as context for predictionquery- query to answer
- Example:
curl 'http://0.0.0.0:5000/context_predict' \ --form 'query="Who is Elara?"' --form 'context="Elara is a girl living in a forest..."' - Response:
The response contains the answer to the query, from given context.
{ "result": ["Elara is the sovereign of the mystical forests of Eldoria"] }
Predict using RAG
- Endpoint:
/rag_predict - Method: POST
- Description: get prediction from a model using RAG and configured documentary basis
- Request:
- Headers: 'Content-Type: multipart/form-data'
- Body:
db- documentary basis to use for predictionquery- query to answer
- Example:
curl 'http://0.0.0.0:5000/rag_predict' \ --form 'query="Who is Esmeralda?"' --form 'db="literature"' - Response:
The response contains the answer to the query, from given context.
{ "result": ["a street dancer"] }
You can list available documentary basis and their uploaded references from current configuration using:
- Endpoint:
/documentary_bases - Method: GET
- Example:
curl 'http://0.0.0.0:5000/documentary_bases' - Response:
{ "documentary_bases": { "literature": [ "NDame de Paris" ], "science": [] } }
Manage references
You can add an .epub document, .docx document or a PDF to the vector DB of the given RAG associated to a database, using:
- Endpoint:
/add_reference - Method: POST
- Request:
- File sent on multipart
- Body:
db- database to insert referencereference- reference to insert
- Example:
curl -F "file=@/data/doc.pdf" --form 'db="literature"' --form 'reference="crypto"' http://0.0.0.0:5000/add_reference - Response:
File successfully processed
So far, only epub, pdf and docx files can be handled.
You can remove a reference to the vector DB of the given RAG associated to a database, using:
- Endpoint:
/delete_reference - Method: DELETE
- Request:
- Body:
db- database to remove reference fromreference- reference to delete
- Body:
- Example:
curl --form 'db="Literature"' --form 'reference="NDame de Paris"' http://0.0.0.0:5000/delete_reference - Response:
Reference successfully removed
Authentication
If your AI Runner is configured to handle authentication, in order to make requests to Eviden VM AI, users must be authentificated using your Identity Provider application (setup previously for Client-Side encryption). It should be a Single Page or Web application type.
Deploy AI Runner
An Eviden VM with a pre-installed API to serve language models for summarization and translation tasks.
This instance can be deployed on virtual machines that supports AMD SEV-SNP or Intel TDX technologies.
Please first read the guide about how to setup an Eviden VM.
The following steps can help one to deploy its own instance on each available cloud provider.
Please first read the guide about how to setup an Eviden VM.
Deploy Eviden VM AI on a cloud provider 🚚
Go the Eviden marketplace webpage of the chosen cloud provider.
Select an OS and continue until the Eviden VM AI instance is spawned.
Here's the list of instance types by cloud provider
| Cloud provider | Azure | GCP | AWS |
|---|---|---|---|
| AMD | SNP | SNP | SNP |
| Standard_DCas_v5 | n2d-standard | M6a | |
| Standard_DCads_v5 | C6a | ||
| R6a | |||
| Intel | TDX | TDX | TDX |
| DCes_v5-series | c3-standard | Not available | |
| ECesv5-series | |||
| (preview) |
The Eviden VM AI Runner contains:
- a ready-to-go Nginx setup (listening on port
443and locally on port5001) - a AI Runner service which is ready but not started yet (needs a valid configuration to start)
- the Eviden VM software stack. As reminder, Eviden VM Agent is listening on port
5555.
At the first start of the VM, Eviden AI Runner is not configured by default. Indeed AI Runner configuration can potentially contain secrets that need to be protected. That is why the configuration MUST be sent remotely and securely to the VM using the Eviden VM CLI see app init.
Service
Systemd is used to initialize and run the AI runner and the Eviden VM agent.
See the running services with the following command:
systemctl status cosmian_ai_runner
systemctl status cosmian_vm_agent
You can read as well full logs using:
journalctl -u cosmian_ai_runner
journalctl -u cosmian_vm_agent
Configure the AI Runner 📜
As explained previously, it is safe to provide secrets (such as passwords) in the configuration file because this file is going to be stored in the encrypted folder (LUKS) of the Eviden AI Runner.
{
"use_amx": false, // Optional - default set to false
"hf_token": "hf_token", // Mandatory (used for translation models)
}
Identity Provider application can be configured as follow:
{
"auth": {
"openid_configs": [
{
"client_id": "XXXX",
"jwks_uri": "XXXX"
}
]
}
}
Exposed documentary bases can be configured as follow :
{
"documentary_bases": [
{
"name": "Literature",
"persist_path": "rag_store_literature",
"model": "google/flan-t5-large",
"task": "text2text-generation",
"kwargs": {
"max_new_tokens": 500
}
},
{
"name": "Science",
"persist_path": "rag_store_science",
"model": "google/flan-t5-large",
"task": "text2text-generation",
"kwargs": {
"max_new_tokens": 500
}
}
]
}
More details about the config file can be found here.
Use Eviden VM CLI to send securely the new AI Runner configuration
Eviden VM CLI has to be installed on the client machine (Ubuntu, RHEL or via Docker). Please follow the installation instructions.
Deploy the configuration and starts the Eviden AI Runner
cosmian_vm --url https://${COSMIAN_VM_IP_ADDR}:5555 \
--allow-insecure-tls \
app init -c config.json
This command will send via an encrypted tunnel the configuration that will be written in the remotely path /var/lib/cosmian_vm/data/app.conf which is contained in an encrypted container (LUKS).
Hardware optimization
When running on Intel Xeon processors, the application can leverage AMX (Advanced Matrix Extensions) to significantly enhance performance, especially for matrix-intensive operations commonly found in machine learning workloads. To enable this feature, simply start the application with the "use_amx" key to true from your config file.
{
"use_amx": true, // Optional - default set to false
}
Check the connection with the AI Runner
curl --insecure https://${COSMIAN_VM_IP_ADDR}/health
When the agent starts (see Snapshot the VM) self-signed certificate is created to enable HTTPS out of the box.
These certificates must be replaced by trusted ones using tools like cosmian_certtool or Linux tools (certbot with Let's Encrypt for instance).
Snapshot the VM
Once the VM is configured as needed, Eviden VM Agent can do a snapshot of the VM containing fingerprint of the executables and metadata related to TEE and TPM.
The agent creates an encrypted folder (LUKS container) to store sensitive information, creates self-signed certificate for Nginx and starts a snapshot.
Wait for the agent to initialize the LUKS and generate the certificates. This is automatically at boot.
Verify the Eviden VM AI Runner integrity ✅
Verifying trustworthiness of the Eviden VM AI Runner is exactly the same process as verifying the Eviden VM itself.
Note that when using Eviden VM AI Runner with RHEL distribution, Python files related to the AI runner are measured and checked during the verification. See SELinux in Eviden VM.
Eviden Enclave
Eviden Enclave allows to quickly deploy confidential Python web applications with the following security features:
- Code runs in a Trusted Execution Environment (TEE) and is encrypted with your key.
- Secure channel is established directly and uniquely with your code running inside the TEE.
- The integrity of the code loaded in TEE's memory is verifiable through a remote attestation process.
- Everyone interacting with your application can verify that your code runs in a TEE thanks to a Transport Layer Security (TLS) extension called Remote Attestation TLS (RA-TLS).
Use Cases
Two common use cases of Eviden Enclave are:
- Offer confidential AI/ML SaaS services to your customers while guaranteeing their data cannot be accessed by you or by the cloud provider.
- Deploy confidential code, models, and/or data in a Zero-Trust environment, where you have zero control over the infrastructure and its administration. For instance, an AI company deploying a fine-tuned model in a customer's infrastructure wants to keep the code and model secrets.
Security guarantees
Eviden Enclave protects data and metadata against system administrators with root access and the underlying cloud provider who owns the hardware infrastructure.
Then, privileged users or anyone with physical access to the host machine:
- Cannot alter the integrity of data and code in the protected area of the TEE.
- Cannot access your application's unique TLS server key generated inside the TEE or decrypt the TLS session.
- Cannot decrypt your encrypted code or access the secret key.
- Cannot access the persistent storage of your application tied to the TEE and the fingerprint of your application.
These assumptions remain valid as long as the TEE hardware, namely Intel SGX, and its software stack known as the Trusted Computing Base (TCB) are not subject to severe vulnerabilities.
Cloud provider availability
As of August 2024, Microsoft Azure, Alibaba Cloud and OVH Cloud offer Intel SGX processors with SGX2 capability. Microsoft Azure and Alibaba Cloud provide VM-based instances with the SGX driver loaded while OVH Cloud provides dedicated servers with Intel SGX processors.
Bare Metal requirements
Eviden Enclave requires Intel Xeon 4th or 5th-gen processors with SGX2. To find all the compatible Intel processors, see Intel Processors supporting Intel SGX.
Workflow
The following diagram illustrates the scenario with two roles:
- The SGX operator who is the administrator of the SGX machine and the one going to run the confidential code
- The code provider who writes the Python code and sends it encrypted to the SGX operator

- The Python code must be an ASGI application using Python web framework such as Flask or FastAPI. It can be optionally encrypted with a random key using the Eviden Enclave CLI with
--encryptargument. - Since the code is encrypted under a key you only know, the code can be transmitted through any channel, even insecure.
- Using the CLI, The SGX Operator loads the encrypted code in a new Eviden Enclave. It outputs an
evidence.jsonfile, which should be returned to the code provider. - The code provider verifies the evidence file using the CLI. It ensures that the correct code is loaded in a fresh new Eviden Enclave and has not been tampered with. This process, called the remote attestation, also verifies if the TEE is genuine and will tell you if there are known vulnerabilities on the remote server's Trusted Computing Base. The file also contains a public key whose corresponding private key is only known to your Eviden Enclave and cannot be recovered by the SGX Operator.
- Using the unique enclave's public key tied to your code, the code provider encrypts a
secrets.jsonfile that contains the code decryption key and any other secrets specific to your application. - The enclave can now decrypt the code inside Intel SGX encrypted memory and run it.
The provider can send data to the application's endpoints over a secure RA-TLS channel directly with the enclave.
Intel SGX and Gramine
Intel Software Guard eXtensions (SGX) offers hardware-based memory encryption that isolates specific application code and data in memory. Intel SGX allows user-level code to allocate private regions of memory, called enclaves, which are designed to be protected from processes running at higher privilege levels.
Because working with Intel SGX requires low-level C programming with the Intel SDK, we use Gramine, a lightweight guest OS designed to run a single Linux application with minimal host requirements and no modification. It is the foundation of Eviden Enclave which allows us to expose a Python confidential web application in the cloud.
Code encryption
Before sending the Python code of your Eviden Enclave, each file is encrypted with XSalsa20-Poly1305 using a random symmetric key. The symmetric key is provisioned when you are confident that your code is running in the enclave by checking the remote attestation.
Remote attestation
A very important aspect of Intel SGX (and more generally Trusted Execution Environments) is attestation. This is a mechanism for a remote user to verify that the application runs on a real hardware in an up-to-date hardware and software with the expected initial state. In other words, remote attestation provides the assurance to the user that the remotely executing SGX enclave is trusted and that the correct code is executed.
To process the remote attestation, an SGX quote is required as a proof of trustworthiness. It's a structure which contains, among others, interesting fields for the end user:
MRENCLAVE, SHA-256 hash digest of the memory footprint during the execution of the codeMRSIGNER, SHA-256 hash digest of Eviden's enclave signer public key- Debug flag, which must not be set in production
- Intel's certification chain and signature to attest the quote
Verification of trustworthiness is done using intel-sgx-ra.
The SGX quote is embedded in the TLS certificate generated by all Eviden Enclave in a protocol called RA-TLS.
RA-TLS
To ease the transport of the quote without modifying TLS, the quote is directly embedded in a specific X509 extension of the TLS certificate.
In addition, a SHA-256 hash digest of the certificate public key is included in the REPORTDATA field of the quote to link the quote to the certificate (i.e. the certificate has been generated in the code corresponding to MRENCLAVE).
It allows to fetch the certificate before using the API provided by the application in Eviden Enclave and check first that it runs in an up-to-date SGX enclave with the correct code (by checking MRENCLAVE).
Then you can add the certificate as CA in your HTTPS client to be sure that you will always interact with the same microservice you checked.

┌────────────────────────────────┐
│ Server │
│ │
│ ┌────────────────────────────┐ │
│ │ Intel SGX │ │
│ │ ┌────────────────────────┐ │ │
│ │ │ Code │ │ │
│ │ │ │ │ │
┌──────────┐ │ │ │ ┌────────────────────┐ │ │ │
│ │ RA-TLS Channel │ │ │ │ │ │ │ │
│ Client ├─────────────────────────┼─┼─┼─┤ TLS Private key │ │ │ │
│ │ │ │ │ │ │ │ │ │
└──────────┘ │ │ │ └────────────────────┘ │ │ │
│ │ │ ┌────────────────────┐ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ RA-TLS Certificate │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ └────────────────────┘ │ │ │
│ │ └────────────────────────┘ │ │
│ └────────────────────────────┘ │
└────────────────────────────────┘
Direct encryption to your enclave
When you can't communicate on the RA-TLS channel (proxy or third party sending data to your enclave), it is still possible to encrypt the payload for your enclave in a programmatic way.
The REPORTDATA field of the SGX quote included in the RA-TLS certificated is 64 bytes field structured as follow:
SHA-256(certificate's public key) || Curve25519 enclave's public key
The purpose of the Curve25519 enclave's public key is to encrypt data for your enclave anonymously using NaCl seal boxes.
On the enclave's code side, it's then possible to decrypt using the private key only available inside the enclave in /key/enclave.key file.
We recommend to use our cryptographic library cenclave-lib-crypto which is already available in your Eviden Enclave but any library compatible with NaCl should work.
In order to launch and use SGX enclaves, you will need to install some Intel's software: Intel Platform SoftWare (PSW), Trusted RunTime System (TRTS), Untrusted RunTime System (URTS) and a compatible Linux kernel >= 6.0 which includes the Intel SGX driver and the support of EDMM. In addition, Eviden Enclave heavily uses the library OS Gramine for isolation but also to provide the best experience for Python developers with no need for third party libraries.
Host requirements
Recommended configuration:
- Ubuntu 22.04 or Ubuntu 24.04
- Linux Kernel >= 6.0
- Docker >= 27.0
Ansible deployment
A simple Ansible script for Microsoft Azure can be found in Eviden Enclave repository. Contact us for a more complex Ansible script for On Premise infrastructure.
To launch your first Eviden Enclave, follow this tutorial in your favorite terminal. Note that you first need to setup your Intel SGX machine based on the Server Installation section.
Install the Eviden Enclave CLI
The Eviden Enclave CLI requires at least Python 3.8 and OpenSSL 1.1.1 series. It is recommended to use pyenv to manage different Python interpreters if needed.
$ pip3 install cenclave
$ cenclave --help
usage: cenclave [-h] [--version]
{encrypt,decrypt,evidence,scaffold,list,logs,package,restart,run,status,seal,unseal,spawn,stop,test,localtest,verify}
...
Cosmian Enclave CLI - 1.0.0
options:
-h, --help show this help message and exit
--version version of cenclave CLI
commands:
{encrypt,decrypt,evidence,scaffold,list,logs,package,restart,run,status,seal,unseal,spawn,stop,test,localtest,verify}
encrypt encrypt a file using Fernet symmetric encryption
decrypt decrypt a file using Fernet symmetric encryption
evidence collect the evidences to verify on offline mode the application and the enclave
scaffold create a new boilerplate web application
list list the running containers
logs print container logs
package generate a package containing the container image and the code to run with
Cosmian Enclave
restart restart a web application
run finalise the configuration of the application docker and run the application
code
status print the container status
seal seal file using NaCl's Seal Box.Recipient is either raw X25519 public key or
extracted from RA-TLS certificate with enclave's public key in REPORT_DATA field
of SGX quote
unseal unseal file using NaCl's Seal Box
spawn spawn container with specified web app
stop stop and optionally remove a running container
test Test a deployed web app
localtest test locally a web app without SGX
verify verify the trustworthiness of a running Cosmian Enclave web application and get
the RA-TLS certificate
Before deploying the app, verify that Docker service is up and your current user is part of docker group.
See Manage Docker as a non-root user.
Scaffold your app
$ cenclave scaffold example
$ tree -a example
example
├── Dockerfile
├── README.md
├── config.toml
├── secrets.json
├── secrets_to_seal.json
├── src
│ ├── .cenclaveignore
│ └── app.py
└── tests
├── conftest.py
└── test_app.py
3 directories, 9 files
The Dockerfile should be based on cenclave-image-base image and include all the dependencies required to run your application.
The file app.py is a basic Hello World Flask application.
Adapt by addind your own Python code in this boilerplate.
from http import HTTPStatus
from flask import Flask, Response
app = Flask(__name__)
@app.get("/health")
def health_check():
"""Health check of the application."""
return Response(response="OK", status=HTTPStatus.OK)
@app.route('/')
def hello():
"""Get a simple example."""
return "Hello world"
# other endpoints
# ...
The configuration to run your application is done in a TOML file config.toml which will be used by the CLI:
name = "example"
python_application = "app:app"
healthcheck_endpoint = "/health"
tests_cmd = "pytest"
tests_requirements = [
"intel-sgx-ra",
"pytest",
]
The project tree also contains a test directory to test your application locally and remotely. It might help to debug and detect runtime errors before running your code in an Eviden Enclave.
See Eviden Enclave examples for proof-of-concept of confidential web applications.
Test your app, your docker and your configuration
$ cenclave localtest --code example/src/ \
--dockerfile example/Dockerfile \
--config example/config.toml \
--test example/tests/
or more concisely with default arguments:
cenclave localtest --project example
Testing your code before sending it to the SGX operator is recommended. Note that any error will require to restart the deployment flow from scratch.
Create the application package with the code and the docker image
This command generates a tarball named package_<app_name>_<timestamp>.tar which can be send to to the SGX operator:
$ cenclave package --code example/src/ \
--dockerfile example/Dockerfile \
--config example/config.toml \
--test example/tests/ \
--output code_provider/
or more concisely with default arguments:
$ cenclave package --project example \
--output code_provider/
Add --encrypt argument if you want to encrypt your code.
Spawn the application docker image
The spawn command will run a new Eviden enclave with your code loaded but it will stay in an intermediate state called the configuration server.
Configuration server is waiting additional information such as the decryption key of the code or any other secrets needed by your application.
$ cenclave spawn --host 0.0.0.0 \
--port 9999 \
--size 4096 \
--package code_provider/package_<app_name>_<timestamp>.tar \
--output sgx_operator/ \
--san <EXTERNAL_IP_ADDR | DOMAIN_NAME | localhost>
app_name
host: usually 127.0.0.1 or 0.0.0.0port: port used by your applicationsize: memory size (in MB) of the enclave to spawn (must be a power of 2 greater than 1024)package: the application package containing the Docker images and the codeoutput: directory to write the evidence JSON filesan: Subject Alternative Name to use for routing with SSL pass-through (either domain name, external IP address or localhost)
The output file sgx_operator/evidence.json contains cryptographic proofs related to the enclave and be shared with anyone to interact with your enclave.
It will be used by the code provider to verify the running app.
Collect the evidences to verify the application
cenclave evidence --output sgx_operator/ app_name
This command collects cryptographic proofs related to the enclave and serialize them in a JSON file evidence.json.
You can choose another PCCS by specifying the --pccs parameter, by default it will determine the PCCS URL by parsing the aesmd service configuration
file: /etc/sgx_default_qcnl.conf.
The file sgx_operator/evidence.json can be shared to any user of your application to allow them to do the remote attestation of your service.
Check the trustworthiness of the application
The trustworthiness is established by using 2 inputs:
- the full code package (tarball file)
- evidences captured from the running enclave (JSON file)
$ cenclave verify --package code_provider/package_<app_name>_<timestamp>.tar \
--evidence sgx_operator/evidence.json \
--output /tmp
If the verification succeeds, the RA-TLS certificate is written as a file named ratls.pem, and you can now seal the
code's secret key to share it with the SGX operator.
Seal your secrets for your Eviden Enclave
Using the unique enclave's public key tied to your code, it's possible to seal secrets which can only be decrypted by a specific Eviden Enclave.
The output of seal command is an encrypted file which can be sent to the SGX operator to start your application.
$ cenclave seal --input example/secrets_to_seal.json \
--receiver-enclave /tmp/ratls.pem \
--output code_provider/secrets_to_seal.json.seal
Finalize the configuration and run the application
$ cenclave run --sealed-secrets code_provider/secrets_to_seal.json.seal \
--secrets example/secrets.json \
app_name
If the command is successful, your application now running normally using a RA-TLS certificate.
Test the deployed application
$ cenclave test --test sgx_operator/tests/ \
--config sgx_operator/config.toml \
app_name
This command helps to check that the application is executed properly as the code provider expects.
Example of encryption on the application side
If your are using the example from cenclave scaffold command, there are endpoints to show how to encrypt the body of an HTTP response with a key provided with sealed secrets at the start of your application.
The JSON file secrets_to_seal.json has been sent sealed to the enclave.
The JSON value corresponding to JSON key result_sk inserted in secrets_to_seal.json will be used to encrypt the response.
Remember that seal secrets can only be decrypted by the specific Eviden Enclave used as receiver.
First collect the encrypted result:
curl --cacert /tmp/ratls.pem https://<IP_ADDR>:9999/result/sealed_secrets > result.enc
and decrypt the result with key.bin which contains the raw bytes of result_sk key (not encoded in Base64 such as in secrets_to_seal.json):
$ cenclave decrypt --input result.enc
--key key.bin \
--output code_provider/result.plain
$ cat code_provider/result.plain
message using result_sk from SEALED_SECRETS
The decrypt command only supports Fernet algorithm.
This is a toy example and we advise to use proper encryption methods such as AES256-GCM or XChacha20-Poly1305.
One of the advantages of using Eviden Enclave to protect your application and data in the cloud, is that if you have already developed a Python web application then it does not need to be modified.
Just write a configuration TOML file and run the deploy subcommand.
In the following sections, we give good practices and some security considerations you need to know before deploying your application in production.
Using a third-party service with secrets
Before sending the Python code of your microservice, each file is encrypted except: requirements.txt.
This code is supposed to be sharable to any user, as your convenience, in order to check the trustworthiness of your app. As a matter of fact, do not write any secret into your code. For example: passwords or keys to connect to a third-party service like a remote storage or a database.
If you need such secrets to run your code, write them in a secrets.json file. Please see the example below.
This file will be sent to the enclave after the latter has been verified during the app deployment.
Note that this file is not encrypted and can be read by the SGX operator.
Your application will then be able to read it to retrieve the secrets it needs.
Example of a secrets.json file:
{
"login": "username",
"password": "azerty"
}
Which is used by this application code example:
import os
import json
from pathlib import Path
from flask import Flask
app = Flask(__name__)
@app.route('/whoami')
def whoami():
"""A simple example manipulating secrets."""
secrets = json.loads(Path(os.getenv("SECRETS_PATH")).read_text())
return secrets["login"]
If your application requires some secrets to be hidden from the SGX operator, write those secrets in another file, for example secrets_to_seal.json.
Then you can seal this secrets_to_seal.json file with the cenclave seal command.
This command encrypts the secrets.json file using the trusted RA-TLS certificate.
This certificate embeds the public key of the enclave, ensuring that only the enclave is able to decrypt the sealed secrets.json file.
Specific filepath available in Eviden Enclave
Find below a small example to show how to use paths in your Eviden Enclave:
import os
from http import HTTPStatus
from pathlib import Path
from datetime import datetime
from flask import Flask, Response
app = Flask(__name__)
# define a global variable from env variables
WORKFILE: Path = Path(os.getenv("HOME")) / "date.txt"
@app.post('/')
def write_date():
"""A simple example of file writing."""
# transparently encrypt the file which can't be read on the host
WORKFILE.write_text(str(datetime.now()))
return Response(status=HTTPStatus.OK)
@app.route('/')
def read_date():
"""A simple example of file reading."""
if not WORKFILE.exists():
return Response(response="You should write before read",
status=HTTPStatus.NOT_FOUND)
# transparently decrypt the file with a key specific to your Eviden Enclave
txt = WORKFILE.read_text()
WORKFILE.unlink()
return txt
Your application owns a dedicated storage up to 10GB. The following directories are all encrypted on the host and can only be decrypted by your Eviden Enclave:
| Env | Path | Encrypted (1) | Persistent (2) | Comments |
|---|---|---|---|---|
$HOME | /root | ✔️ | ✖️ | home directory to save anything such as cache or configuration files |
$SECRETS_PATH | $HOME/.cache/cenclave/secrets.json | ✔️ | ✖️ | application secrets file for infrastructure credentials (database, or network access, then known by the SGX operator) |
$SEALED_SECRETS_PATH | $HOME/.cache/cenclave/sealed_secrets.json | ✔️ | ✖️ | application secrets sealed for your specific enclave (content only readable in your enclave) |
$TMP_PATH | /tmp | ✔️ | ✖️ | temporary folder for your application (only readable in your enclave) |
$MODULE_PATH | /app | ✔️ | ✖️ | folder with the decrypted application code (only readable in your enclave) |
Note that writing operations in $HOME are about 2.5 times slower than in a $TMP_PATH.
However the max file size you can allocate in $TMP_PATH is hardware_memory / 4 and the number of files has no limit as long as the sum of
their size is lower than the size still available.
Choose wisely the file location based on your own application constraints.
(1) Only the enclave containing this version of your code can decrypt this directory. Another enclave or even another version of your application won't be able to read it
(2) The content will be removed when the application is stopped
.cenclaveignore file
You can edit .cenclaveignore file in your code directory.
This file is read by the CLI when deploying an app and avoid packaging some files if not needed.
The syntax is the same as .gitignore.
A default .cenclaveignore is generated by the cenclave scaffold command.
Memory size
When you declare the memory size through the field hardware in config.toml, note that a part of this memory is used by the system itself.
All the libraries needed to run your application will be loaded in the enclave memory.
Therefore, the effective memory size available for your application is approximately: hardware_memory - libraries_size.
When running the Docker container locally, you can use the option --memory to estimate the memory size of your application.
See GitHub repository cenclave-image-base for more details.
Limitations
Please find below limitations that you need to consider to be able to run smoothly your application in Eviden Enclave:
- Fork are not allowed for performance issues to avoid bad user experience, creating new enclaves is slow.
- Some application are using a lot of memory and when working with enclaves the memory is limited and must be used with care. Consider using a comfortable amount of EPC memory and RAM regarding your application.
List running Eviden Enclave's applications:
cenclave list
Application stdout/stderr logs:
cenclave logs [-f] <app_name>
Restart your application if needed:
cenclave restart <app_name>
Status of a specific application:
cenclave status <app_name>
The status can be in the following states:
initializing: the configuration server or the application server is startingwaiting secret keys: waiting for the secret key to decrypt the code and/or secrets for your applicationrunning: the web app is currently runningon_error: the application has stopped with an error, seecenclave logsto inspect the error
Stop a running application as follow:
cenclave stop [--remove] <app_name>
If you stop an app without the parameter --remove, you can restart it later by recovering the last app state.
However you can't spawn a new app on the same port and with the same name if you don't remove it.
Eviden Findex server
The Eviden Findex is a high-performance, open-source, server application written in Rust that provides a REST API to index and search encrypted data.
What is Findex?
Findex is a cryptographic protocol designed to make search queries on an untrusted cloud server securely. Findex is concurrent and database-independent, allowing large database indexes to be outsourced securely without compromising usability.
Findex aims to solve the following problem:
Findex has been published as a scientific paper in the IACR ePrint archive: https://eprint.iacr.org/2024/1541.
What is Findex server?
Findex server is a high-performance, open-source server application written in Rust that implements the Findex protocol and offers a REST API to store encrypted indexes and perform search queries on them. Findex Server mainly is an authentication layer and therefore all data-critical manipulations are performed by a database.
The server is designed to be used in conjunction with the Eviden CLI, a command-line interface that allows users to interact with the server.
Threat Model
The threat model for Findex assumes that the cloud server is untrusted and may attempt to infer information from the encrypted indexes and search queries. However, the server is considered honest-but-curious, meaning it will follow the protocol correctly but will try to learn as much as possible from the data it processes. Findex is designed to protect against such adversaries by ensuring that no useful information about the plaintext data and the minimum of information is leaked during search queries.
Basically, the server does not know how are encrypted the indexes nor the datasets they contain. It can only perform search queries on the encrypted indexes and return the results to the client.
Quick Start
For server side: Findex server.
For client side: Eviden CLI.
Findex server
Client-Side Encryption
Client-side encryption is a crucial aspect of the Findex protocol, ensuring that data remains secure even when stored on an untrusted server. In this model, all encryption and decryption operations are performed on the client side, meaning that the server only ever sees encrypted data and cannot infer any useful information from it.
architecture-beta
service user(disk)[Client side encryption]
group untrusted(cloud)[Cloud]
service server(server)[Findex Server] in untrusted
service db(database)[Database] in untrusted
service kms(server)[KMS] in untrusted
service db2(database)[Keys] in untrusted
user:R -- L:server
server:R <--> L:db
user:R -- L:kms
kms:R <--> L:db2
How It Works
-
Data Encryption: Before sending any data to the Findex server, the client encrypts the data using a secure encryption algorithm. This ensures that the plaintext data is never exposed to the server.
-
Index Encryption: Similarly, the indexes used for search queries are also encrypted on the client side. This prevents the server from learning anything about the content of the indexes.
-
Search Queries: When performing a search query, the client encrypts the search keyword and sends the encrypted query to the server. The server processes the query on the encrypted indexes and returns the encrypted results to the client.
-
Data Decryption: Upon receiving the encrypted results from the server, the client decrypts the data to obtain the plaintext results.
Benefits
- Data Privacy: Since the server only handles encrypted data, it cannot access the plaintext information, ensuring data privacy.
- Security: Client-side encryption protects against potential data breaches on the server, as the encrypted data would be useless to an attacker without the decryption keys.
- Control: Users retain full control over their encryption keys and can manage their own security policies.
- Database Independence: Findex server is designed to work with any database, as the encryption and decryption operations are performed independently of the underlying storage mechanism. It relies on state-of-the-art solutions like Redis and can therefore provide a strong data-persistence insurance. An identified issue in the existing SSE literature is that all schemes rely on ad-hoc server implementations, which increases the probability of bugs, crashes and data-loss. In comparison, Findex Server is "just" a glorified Redis, which is good.
By leveraging client-side encryption, Findex ensures that sensitive data remains secure and private, even when stored and processed on an untrusted server.
The Findex server, written in Rust and using the Actix-web framework, is a REST-API server used to store encrypted indexes and perform search queries on them. It is designed to be used in conjunction with the Eviden CLI, which is a command-line interface that allows users to interact with the server.
Features
The server offers a REST API with the following functionalities:
Quick start
Multiple options are available to run the Findex server, including using Docker, pre-built binaries, or building from source.
No authentication is configured for quick start. This is not recommended for production use.
The quickest way to get started with Findex server is to use the Docker image.
To run the server binary on http://localhost:6668 that stores its data
in a Redis server, run the following command:
docker compose -f docker-compose-quick-start.yml up
where docker-compose-quick-start.yml is the following:
services:
redis:
container_name: redis
image: redis:latest
ports:
- 6379:6379
findex-server:
container_name: findex-server
image: ghcr.io/cosmian/findex-server:latest
ports:
- 6668:6668
environment:
FINDEX_SERVER_DATABASE_TYPE: redis
FINDEX_SERVER_DATABASE_URL: redis://redis:6379
FINDEX_SERVER_CLEAR_DATABASE: true
An other option include running the server binary directly installing the Debian package available here.
First, run the Redis server independently:
docker run -d -p 6379:6379 redis
Then, download package and install it:
sudo apt update && sudo apt install -y wget
wget https://package.cosmian.com/findex-server/0.4.14/ubuntu-24.04/cosmian-findex-server_0.4.14-1_amd64.deb
sudo apt install ./cosmian-findex-server_0.4.14-1_amd64.deb
cosmian_findex_server --version
The server should now be running on http://localhost:6668.
An other option include running the server binary directly installing the Debian package available here.
First, run the Redis server independently:
docker run -d -p 6379:6379 redis
Then, download package and install it:
sudo dnf update && dnf install -y wget
wget https://package.cosmian.com/findex-server/0.4.14/rhel9/cosmian_findex_server-0.4.14-1.x86_64.rpm
sudo dnf install ./cosmian_findex_server-0.4.14-1.x86_64.rpm
cosmian_findex_server --version
The server should now be running on http://localhost:6668.
On ARM MacOS, download the build archive and extract it:
wget https://package.cosmian.com/findex-server/0.4.14/macos_arm-release.zip
unzip macos_arm-release.zip
cp ./macos_arm-release/cosmian_findex_server /usr/local/bin/
chmod u+x /usr/local/bin/cosmian_findex_server
cosmian_findex_server --version
On Windows, download the build archive:
https://package.cosmian.com/findex-server/0.4.14/windows-release.zip
Extract the cosmian_findex_server from:
/windows-release/cosmian_findex_server.exe
Copy it to a folder in your PATH and run it:
cosmian_findex_server --version
To build the server from source, clone the repository and run the following commands:
git clone https://github.com/Cosmian/findex-server.git
cd findex-server
cargo build
First, run the Redis server independently:
docker run -d -p 6379:6379 redis
Then, run the server:
cargo run --bin cosmian_findex_server -- --database-url redis://localhost:6379 --database-type redis
Configuration
Please refer to the configuration documentation for more information on how to configure the Findex server.
Usage
Eviden Findex server
Usage: cosmian_findex_server [OPTIONS]
Options:
--database-type <DATABASE_TYPE>
The database type of the Findex server
- redis: Redis database. The Redis url must be provided [env: FINDEX_SERVER_DATABASE_TYPE=] [default: redis] [possible values: redis]
--database-url <DATABASE_URL>
The url of the database [env: FINDEX_SERVER_DATABASE_URL=] [default: redis://localhost:6379]
--clear-database
Clear the database on start.
WARNING: This will delete ALL the data in the database [env: FINDEX_SERVER_CLEAR_DATABASE=]
--port <PORT>
The Findex server port [env: FINDEX_SERVER_PORT=] [default: 6668]
--hostname <HOSTNAME>
The Findex server hostname [env: FINDEX_SERVER_HOSTNAME=] [default: 0.0.0.0]
--https-p12-file <HTTPS_P12_FILE>
The Findex server optional PKCS#12 Certificates and Key file. If provided, this will start the server in HTTPS mode [env: FINDEX_SERVER_HTTPS_P12_FILE=]
--https-p12-password <HTTPS_P12_PASSWORD>
The password to open the PKCS#12 Certificates and Key file [env: FINDEX_SERVER_HTTPS_P12_PASSWORD=]
--authority-cert-file <AUTHORITY_CERT_FILE>
The server optional authority X509 certificate in PEM format used to validate the client certificate presented for authentication. If provided, this will require clients to present a certificate signed by this authority for authentication. The server must run in TLS mode for this to be used [env: FINDEX_SERVER_AUTHORITY_CERT_FILE=]
--jwt-issuer-uri <JWT_ISSUER_URI>...
The issuer URI of the JWT token [env: FINDEX_SERVER_JWT_ISSUER_URI=]
--jwks-uri <JWKS_URI>...
The JWKS (Json Web Key Set) URI of the JWT token [env: FINDEX_SERVER_JWKS_URI=]
--jwt-audience <JWT_AUDIENCE>...
The audience of the JWT token [env: FINDEX_SERVER_JST_AUDIENCE=]
--default-username <DEFAULT_USERNAME>
The default username to use when no authentication method is provided [env: FINDEX_SERVER_DEFAULT_USERNAME=] [default: admin]
--force-default-username
When an authentication method is provided, perform the authentication but always use the default username instead of the one provided by the authentication method [env: FINDEX_SERVER_FORCE_DEFAULT_USERNAME=]
-h, --help
Print help (see more with '--help')
-V, --version
Print version
Configuration file
By default, the server expects to find:
- a TOML configuration file in
/etc/cosmian/findex_server.toml. - or an environment variable
COSMIAN_FINDEX_SERVER_CONFthat contains the path to the configuration file. - otherwise, the server will parse the arguments passed in command line.
Example without authentication
default_username = "admin"
force_default_username = false
[db]
database_type = "Redis"
database_url = "redis://localhost:6379"
clear_database = false
[http]
port = 6668
hostname = "0.0.0.0"
Example with X509 authentication
default_username = "admin"
force_default_username = false
[db]
database_type = "Redis"
database_url = "redis://localhost:6379"
clear_database = true
[http]
port = 6660
hostname = "0.0.0.0"
https_p12_file = "/etc/cosmian/certificates/server/findex.server.acme.com.p12"
https_p12_password = "password"
authority_cert_file = "/etc/cosmian/certificates/server/ca.crt"
Example with OpenID authentication
default_username = "admin"
force_default_username = false
[db]
database_type = "Redis"
database_url = "redis://localhost:6379"
clear_database = false
[http]
port = 6668
hostname = "0.0.0.0"
[auth]
jwt_issuer_uri = "eyJhbGciOiJSUzI1NiIsInR5cCI...ydoDOsmYhWTEgf5w"
User Authentication
The application supports two methods of user authentication:
- Open ID Connect with JWT access tokens
- PKCS12 certificates with mutual authentication (client ↔ server)
OpenID with JWT Access Token
In that case, the Findex server delegates the authentication process to an external OAuth2 server. In fine, the server issues a JWT Access Token that is used to authenticate the user with the Findex server.
The Findex server must be run with the following arguments: For example with Google OAuth2:
docker run -p 6668:6668 --name findex-server ghcr.io/cosmian/findex-server:latest \
--jwt-issuer-uri=https://accounts.google.com \
--jwks-uri=https://www.googleapis.com/oauth2/v3/certs \
--jwt-audience=cosmian_findex_server
The authentication Flow can be summarized as follows:
-
Client Requests Authorization:
The client application initiates an authorization request. This is done via an OAuth 2.0 Authorization Code Flow. The client redirects the user to the Authorization Server (e.g., Google, GitHub, or a custom server) that has to be owned by the client.
-
User Authenticates:
The user authenticates with their credentials (e.g., username/password, social login). The Authorization Server verifies the user's identity.
-
Access Token Issuance (JWT)
The Authorization Server issues an Access Token in the form of a JWT. The token contains:
- Header: Token type (JWT) and signing algorithm (e.g., RS256).
- Payload (Claims): User information, permissions, expiration time (exp), issuer (iss), audience (aud), etc.
- Signature: Ensures the integrity and authenticity of the token.
-
Client Accesses Protected Resources
The client includes the JWT in the Authorization header of HTTP requests to the Resource Server:
Authorization: Bearer <JWT Access Token> -
Token Validation
The Resource Server validates the JWT by:
- Verifying the signature (using a public key if signed with RS256).
- Checking standard claims (e.g., exp, iss, aud) for validity.
- Decoding the payload to extract user information and permissions.
-
Access Granted or Denied
If the JWT is valid, the Resource Server allows access to the requested resources based on the user's claims. If invalid (e.g., expired, tampered), the request is denied with an HTTP 401 Unauthorized error.
sequenceDiagram actor User participant AuthServer as Authorization Server participant ResourceServer as Resource Server User->>AuthServer: Authorization Request AuthServer->>User: Redirect to Login User->>AuthServer: User Credentials AuthServer->>User: JWT Access Token User->>ResourceServer: Request with JWT ResourceServer->>ResourceServer: Validate JWT ResourceServer->>User: Access Granted/Denied
JWT is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure. This enables the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.
Eviden CLI Configuration
Eviden CLI is helpful to authenticate with the Findex server using OpenID Connect. The CLI has to be installed locally and configured with the Findex server URL and OAuth2 configuration.
The Eviden CLI realizes this authentication flow using this simple command:
cosmian findex-server login
By using this default configuration ~/.cosmian/cosmian.toml:
[kms_config]
print_json = false
[kms_config.http_config]
server_url = "http://127.0.0.1:9998"
[findex_config.http_config]
server_url = "https://<FINDEX-SERVER-URL>/"
[findex_config.http_config.oauth2_conf]
client_id = "99999999-abababababababababab.apps.googleusercontent.com"
client_secret = "XXX"
authorize_url = "https://accounts.google.com/o/oauth2/v2/auth"
token_url = "https://oauth2.googleapis.com/token"
scopes = ["openid", "email"]
X509 certificates authentication
In that case, the Findex server uses PKCS12 certificates to authenticate the user. The server requires the client to present a certificate signed by a trusted authority known by itself. The server also presents its own certificate to the client, which the client must verify.
The Findex server must be run with the following arguments: For example with Google OAuth2:
docker run -p 6668:6668 --name findex-server ghcr.io/cosmian/findex-server:latest \
--https-p12-file=server/certificate.p12 \
--https-p12-password=complex_password \
--authority-cert-file=server/ca.crt
User access authorization
Once authenticated, users must have an authorization to an Index ID.
What is an Index ID?
An Index ID allows the partitioning of indexed data: behind an Index ID, there are:
- encrypted indexes
- and the encrypted version of the data that has been indexed.
This Index ID can be shared between users, with a specific permission. Users can also own multiple Index IDs.
Invocation of any method exposed in the API is conditioned by the validation and compatibility of the claimed permissions.
Permissions
sequenceDiagram autonumber actor User participant F as Findex server User->>F: User authentication User->>F: User create an Index ID F->>User: Index ID with admin permission User->>F: User set/revoke permission to another user
There are 3 permissions:
readerwriteradmin
The mechanism is pretty simple:
When a user creates a new Index ID, he becomes the admin of this index. He can then set other index users the role of reader, writer or admin.
Every server endpoint is protected by this authorization mechanism: the server checks the user's role before allowing access to the endpoint.
Permission format in database
Currently, there is an entry for each user in database. In the case of a key-value database, the key is the user ID (its email) and the value is a list of tuples (permission, index_id) where permission is 1 byte and index_id is an UUID of 16 bytes.
Example
| Key | Value |
|---|---|
user@gmail.com | (0,d9eee59c-f9df-4edd-97bc-ba5952ce63af) | (1,5b044b87-bced-424c-9dac-f25550c88c20) |
Endpoints
| Endpoint | Description |
|---|---|
/create/index | Create an Index ID |
/permission/set/{user_id}/{permission}/{index_id} | Set a permission to a user for a specific index |
/permission/list/{user_id} | List permissions of a user |
/permission/revoke/{user_id}/{index_id} | Revoke a user's permission for a specific index |
Encrypted database
From the server's perspective, only encrypted data is received and stored as-is. The server does not know how the data is encrypted and cannot decrypt it.
The requirements database is a key-value store where the keys are unique identifiers (UIDs) and the values are the encrypted indexes or datasets.
In this scenario, the user is responsible for encrypting the data before sending it to the server. For example, a KEM/DEM encryption scheme can be used. KEM stands for Key Encapsulation Mechanism and DEM for Data Encapsulation Mechanism. A few words, the data is encrypted with a Data Encryption Key (DEK) and the DEK is encrypted with a Key Encryption Key (KEK) and sent along with the encrypted data.
User requires a Key Management System to encrypt the Data Encryption Key (DEK).
How to securely index new data?
An example of KEM-DEM encryption scheme is the crypto-system RFC-5649 + AES-256-GCM.
sequenceDiagram
autonumber
actor U as User
participant K as Key Management System
participant F as Findex server
U->>K: User requests a Key Encryption Key (KEK)
K->>U: Send an ID of the KEK
U->>U: Generate an ephemeral Data Encryption Key (DEK)
U->>K: Encrypt the DEK with the KEK (RFC5649)
K->>U: Send the encrypted DEK (encapsulation)
loop Read and encrypt locally the dataset
U-->U: Read line by line the dataset
U-->U: For each line, an unique identifier (UID) is generated
U-->U: Each line is encrypted with the DEK (AES-256-GCM)
end
U->>F: Send all encrypted lines (and encapsulation) and corresponding UIDs to a given Index ID
loop Index and encrypt locally the dataset
U->>U: Index plaintext line by keywords resulting encrypted indexes
end
U->>F: Send encrypted indexes
How to securely search indexed data?
sequenceDiagram
autonumber
actor U as User
participant F as Findex server
participant K as Key Management System
U->>F: User does a search query by keywords
F->>U: If data has been indexed with the given keywords, sends dataset UIDs
U->>F: User requests the values of the dataset UIDs
F->>U: Sends the encrypted values of the dataset UIDs
loop Read the encrypted values
U->>U: For each value, get the encrypted DEK (encapsulation)
U->>K: Decrypt the DEK with the KEK
K->>U: Send the decrypted DEK
U->>U: Decrypt each value with the DEK
end
Store and retrieve encrypted indexes as Findex requirements
The server presents the following endpoints:
| Endpoint | Description |
|---|---|
/indexes/{index_id}/batch_read | retrieve encrypted indexes |
/indexes/{index_id}/guarded_write | insert encrypted indexes |
And consequently, the Findex [REST client implementation] (crate/client/src/rest_client.rs) implements the client side of the communication with the server.
Furthermore, the encryption is done by the client before sending the data to the server.
Database structure
In a key-value database (like Redis), indexes are stored as follows:
| Key | Value |
|---|---|
| index_id || id | Findex encrypted index |
Concerning the format of encrypted indexes, please read the Findex github.
Store and retrieve the encrypted version of the data that has been indexed
Findex server stores as it is the encrypted version of the data that has been indexed. The server presents the following endpoints:
| Endpoint | Description |
|---|---|
/datasets/{index_id}/datasets_add_entries | insert new encrypted entries |
/datasets/{index_id}/datasets_del_entries | delete encrypted entries |
/datasets/{index_id}/datasets_get_entries | get encrypted entries |
The encryption is done by the client before sending the data to the server.
Database structure
In a key-value database (like Redis), dataset entries are stored as follows:
| Key | Value |
|---|---|
| dataset entry id | encrypted dataset entry |
Using the Eviden CLI
The Eviden CLI allows to interact both with the KMS server and Findex server. Then you can realize the following operations illustrated in encrypted database.
As prerequisites, you need to have:
- the Eviden CLI installed on your machine. You can download the latest version of the Cosmian CLI from the Cosmian package website.
- a running KMS server: follow the instructions in the quick start guide.
- a running Findex server: follow the instructions in the quick start guide.
Depending on the authentication of these 2 servers, the configuration will have to be adapted. Refer to the configuration documentation for more information.
As a summary, below are described the steps:
- to encrypt and store a dataset while indexing it.
- to search a keyword and decrypt the corresponding result.
Encrypt and store a dataset while indexing it
The following steps allow to encrypt a data using a KEM-DEM crypto-system where:
- the Data Encryption Key (DEK) is encrypted with a KMS server (with RFC-5649 wrapping key standard) using a Key Encryption Key (KEK)
- the encrypted DEK is stored with the data encrypted using AES-256-GCM.
Generate the Key Encryption Key:
cosmian kms sym keys create
The symmetric key was successfully generated.
Unique identifier: 55629c83-5184-4e54-9839-9b686a6f2850
Generate the Seed Key that will be used to encrypt locally the indexes:
cosmian kms sym keys create
The symmetric key was successfully generated.
Unique identifier: fbf2a111-ae11-4231-9985-c0e3b140caeb
Then create a dedicated index id where all data will be stored:
cosmian findex-server permissions create
[admin] New admin permission successfully created on index: 13348510-75cd-436e-a9ff-60de66cac0d0
Then encrypt and index the following small dataset:
city,region,country,population
Southborough,MA,United States,9686
Northbridge,MA,United States,14061
Westborough,MA,United States,29313
Marlborough,MA,United States,38334
Springfield,MA,United States,152227
Springfield,MO,United States,150443
Springfield,NJ,United States,14976
Springfield,OH,United States,64325
Springfield,OR,United States,56032
Concord,NH,United States,42605
Using this command:
cosmian findex-server encrypt-and-index --seed-key-id fbf2a111-ae11-4231-9985-c0e3b140caeb --index-id 13348510-75cd-436e-a9ff-60de66cac0d0 --csv test_data/datasets/smallpop.csv --kek-id 55629c83-5184-4e54-9839-9b686a6f2850
Data behind those UUIDS were encrypted and indexed: UUID: 7059592d-9cd7-46d6-9e4d-b26436430942
UUID: d9eee59c-f9df-4edd-97bc-ba5952ce63af
UUID: 5b044b87-bced-424c-9dac-f25550c88c20
UUID: 863f39c5-bd6f-4685-97a2-07de8aa67c41
UUID: 90d05319-15c7-4c39-8176-85057c915b7b
UUID: dfe699ab-493d-49fc-b19c-9918376b2aa5
UUID: 61fcac44-0e91-470c-95f5-496f1b67389a
UUID: c6ab6f96-bba5-478b-be7f-2526e5b82e41
UUID: 3329fe2a-06c5-4904-aba7-4a9faf0e0876
UUID: f556fd71-7ef1-46ca-bf0f-30d92c055b44
Search a keyword
To search a keyword, find the corresponding UUIDs, get the values of these UUIDs and decrypt them (if any match is found), just proceed as follow:
cosmian findex-server search-and-decrypt --seed-key-id fbf2a111-ae11-4231-9985-c0e3b140caeb --index-id 13348510-75cd-436e-a9ff-60de66cac0d0 --kek-id 55629c83-5184-4e54-9839-9b686a6f2850 --keyword Southborough
Decrypted record: SouthboroughMAUnited States9686
Configuration
Please refer to the configuration documentation for more information on how to configure the Eviden CLI.