bg-tutorials

HSM collegato alla rete Luna v7.x: Guida alla CSR e all’attestazione

Sectigo will issue a code signing certificate onto hardware you already own, but only if you can prove the private key was born inside that hardware and cannot leave it. On a Thales Luna Network HSM the proof is a public key confirmation, or PKC: a certificate chain the HSM itself signs, attesting that a named key pair was generated inside a genuine Luna module. You upload it alongside your CSR when you complete the order.

This guide covers the whole sequence on the command line: generating an RSA key pair with the attributes the attestation needs, reading the object handles, building the CSR, producing the PKC in the format the CA expects, and checking both files before you upload them. It assumes you already own the HSM, that the Luna HSM Client is installed and registered against a partition, and that you hold the Crypto Officer credential for that partition.

What the CA is asking for, and why

Since June 2023 every publicly trusted code signing certificate must have its private key held in hardware that meets FIPS 140-2 Level 2 or Common Criteria EAL 4+, and the storage has to support externally verifiable key attestation. That is the rule behind the whole procedure. When you buy a certificate with a shipped token, the CA generates the key on hardware it controls and no proof is needed. When you choose Install on Existing HSM, the CA has never touched your hardware, so it needs a cryptographic statement from the hardware itself.

Thales builds that statement into every Luna HSM. Each module leaves the factory with a device identity certified by a Thales authority whose root is held in HSMs in a vault. The signing key inside your module is called the Hardware Origin Key, it is created at manufacture, and it cannot be extracted or replaced. When you ask for a confirmation, the HSM signs a certificate for the key pair you name and hands back a PKCS #7 bundle containing the chain that leads back to Thales:

  • MIC, the Manufacturing Integrity Certificate, signed by the Thales root.
  • HOC, the Hardware Origin Certificate, unique to your HSM and signed by the manufacturing integrity key.
  • DAC, the Device Authentication Certificate, also unique to your HSM and signed by the hardware origin key.
  • PKC, the confirmation for the specific private key you asked about, signed by the device authentication key.

A valid confirmation proves two things at once: that the key is inside the identified HSM, and that the HSM is a real Luna module. Thales only issues confirmations for private keys that were created inside a Luna cryptographic module and that can never exist outside it, which is exactly the property the CA needs to see.

The file itself is a DER-encoded PKCS #7 store. If you want background on what that container is and how it differs from PEM, see our explainer on SSL certificate formats.

Chrysalis-ITS versus TC-Trust Center

The cmu utility can build the confirmation against more than one chain of trust, and this is the step people get wrong. Thales’ archived Luna 7.4 documentation lists the two values the -pkctype option accepts:

  • 1, documented by Thales as “not used”. This is the older TC-Trust Center layout, a short chain that does not terminate at the SafeNet root, so a validator that expects that root cannot complete the path.
  • 2, Chrysalis-ITS. This is the chain that is built into the cmu utility by default and that originates from Thales’ SafeNet root certificate authority, walking MIC to HOC to DAC to PKC.

Chrysalis-ITS is the one the CA validates against, so it is the one you want. The name is a survivor from the Ottawa hardware security module company of the same name, acquired by Rainbow Technologies in 2003, which merged with SafeNet the following year, with SafeNet in turn becoming part of Thales. It is also, incidentally, why the sample commands you will find on CA knowledge bases set the locality to Ottawa. The term is still used in the current Luna Network HSM 7 documentation, so it is not a legacy label you can ignore.

One currency note worth knowing before you copy a command from an older knowledge base. -pkctype is documented in the Luna 7.4-era cmu getpkc reference but it is absent from the syntax block in the current Luna Network HSM 7 documentation, which lists only -handle, -ouid, -outputfile and -verify. Since the only other value was already marked “not used”, nothing is lost: Chrysalis-ITS is what a current client produces anyway. Include the option if your client accepts it, and drop it if the client rejects it as unknown.

Before you start

  • A Luna Network HSM and a working client link. The Luna HSM Client must be installed on the machine you will run the commands from, the client must be registered with the appliance, and a partition must be assigned to it and visible as a slot.
  • The Crypto Officer credential for that partition. Every cmu command below authenticates. On a password-authenticated HSM you will be prompted for the password unless you pass it on the command line; on a multifactor quorum (PED) HSM you present the PED key, and for a Remote PED you also add -ped with the PED ID. If you do not pass -slot, cmu prompts you to pick the slot.
  • An HSM without Functionality Modules enabled. Thales states plainly that the confirmation procedure is not supported on FM-enabled HSMs. Modules ship FM-ready, but the moment FMs are actually enabled the original hardware origin key and certificate are deleted and the chain proceeds through the FM equivalents instead. If you have enabled FMs, raise it with the CA before you order, because the standard attestation route is closed to you.
  • A decision on the certificate itself. If you do not own an HSM and do not want to run one, the pre-configured token option is the simpler purchase. Our guide to code signing certificate delivery methods compares the two.

The commands are the same on both platforms, since cmu is the same utility. Only the directory it lives in changes. Note also that this procedure is Sectigo’s, published for its own HSM-installed products. For anything specific to the hardware itself, Thales support is the right escalation, not the CA.

Step 1: open a shell in the Luna HSM Client directory

The cmu binary is not on the system path by default, so start by changing into the client directory. On Windows, open Command Prompt or PowerShell and run:

cd "C:\Program Files\SafeNet\LunaClient"

On Linux:

cd /usr/safenet/lunaclient/bin

Those are the default installation locations for Luna HSM Client 10.x and they have not changed from the 7.x client. The SafeNet in the Windows path is not stale branding to correct: Thales is the vendor, SafeNet is the product line, and Thales’ own current installation documentation still writes the directory that way.

On Linux the client directory is not on the path, so prefix both utilities with ./, as in ./lunacm and ./cmu list. On Windows you can call them by name once you are in the directory. Confirm the partition is visible before you go further by starting the interactive shell:

lunacm

At the lunacm:> prompt, list the slots and then leave:

slot list
exit

That is the only thing lunacm is needed for here. It is an interactive shell for managing slots and partitions, and cmu is a separate command-line utility that happens to live in the same directory. You do not type cmu commands at the lunacm prompt: leave lunacm first, then run each cmu command from your normal shell.

Step 2: generate the RSA key pair

Generate the pair inside the partition. Thales documents the function as generatekeypair; older CA knowledge bases abbreviate it to cmu gen, so use the full documented name if the short form is not recognized.

cmu generatekeypair -modulusBits=3072 -publicExponent=65537 -sign=1 -verify=1 -extractable=0 -label=codesigning-2026

Every option in that line is doing work:

  • -modulusBits=3072 sets the RSA key length. 3072 bits is the minimum for a publicly trusted code signing certificate under the CA/Browser Forum Code Signing Baseline Requirements, in force since June 1, 2021, so 2048 will be rejected. Thales accepts any multiple of 64 between 1024 and 4096, with one catch: if HSM policy 12, “Allow non-FIPS algorithms”, is set to No, the key size is restricted to 2048 or 3072 bits. On a FIPS-configured HSM, which is the configuration the CA wants to see, 3072 is therefore the only compliant choice and 4096 is unavailable.
  • -publicExponent=65537 is the standard exponent. Thales accepts 3, 17 and 65537, but only 65537 is allowed in a FIPS 140 configuration.
  • -sign=1 gives the private key signing capability. Its default is False. Without it the CSR step fails, because cmu requestCertificate uses the private key to sign the request structure, and cmu verifypkc fails too, since it performs an internal sign-verify on test data.
  • -verify=1 gives the public key the matching verify capability.
  • -extractable=0 marks the private key as non-extractable. This is the attribute the whole exercise depends on. cmu getpkc works with non-extractable keys only, so an extractable key produces no attestation at all, and an extractable code signing key would fail the CA’s requirements regardless. False is already the default, but state it explicitly so nobody has to guess.
  • -label names both keys. Use something you will recognize a year from now, and quote it if it contains spaces.

Booleans can be written as 1 and 0 or as True and False; older instructions write T and F. Do not add -encrypt or -decrypt to this command. Many partitions run with policy 10, “Allow multipurpose keys”, turned off, and on such a partition a key that signs cannot also decrypt or unwrap, so the extra attributes will make the generation fail.

Step 3: read the object handles

The next two commands take handles rather than labels, so list the objects and note the numbers. Adding -display makes the output explicit:

cmu list -class public -display=handle,label
cmu list -class private -display=handle,label

Handle and label are what cmu list prints by default, so the bare cmu list -class public form works too. If the partition holds several key pairs, match on the label you set in step 2 rather than assuming the newest pair is at the top. Write down both numbers; the rest of the guide calls them the public handle and the private handle.

One platform difference: on a Luna Cloud HSM service slot there are no handles, and you use object unified identifiers instead, through -publicouid, -privateouid and -ouid. That requires Luna HSM Client 10.2.0 or newer. On a physical Luna Network HSM, handles are correct.

Step 4: create the CSR

This is the step that most often sinks an order, so read the field notes before you run anything. Substitute your own handles and your own company details everywhere:

cmu requestCertificate -publichandle=11 -privatehandle=12 -sha256withrsa -C=US -S=California "-L=San Francisco" "-O=Example Software Inc" "-CN=Example Software Inc" -outputFile=codesigning.csr

Replace 11 and 12 with the handles from step 3, and replace every value after them with your own. Example Software Inc is a placeholder, not a setting.

What each subject field must contain

  • -O, the Organization, must be your own legal entity name, spelled exactly as it appears in the official registration the CA validates against. It is not the name of the Certificate Authority. Some published examples set this to the CA’s name, which would be asking Sectigo to certify that your key belongs to Sectigo. Vetting will not pass, and at best the order comes back for correction.
  • -CN, the Common Name, is the same legal entity name for an organization-validated code signing certificate. A code signing certificate does not carry a domain name, so there is no hostname to put here, and a placeholder such as “PKC Test Cert” is exactly the sort of value that gets copied verbatim and then has to be reissued.
  • -C is the two-letter ISO country code of the registered address, for example US, GB or DE. It is not the CA’s country.
  • -S and -L are the state or province and the locality of that same registered address. Spell them out; do not abbreviate the state.
  • -OU, the Organizational Unit, is optional and is safest left out. Several CAs no longer include it.

The certificate is issued from the details the CA validated for your organization, so the CSR needs to agree with them. A request naming another company, or carrying a test string in the Common Name, is the fastest way to have the order queried by the validation team. If you are unsure what Sectigo has on file for you, our walkthrough of Sectigo code signing validation covers what gets checked.

Always set the signature algorithm

-sha256withrsa is the option most sample commands omit, and it matters. Thales documents the default signature algorithm for cmu requestCertificate as sha1withrsa, so a command without it produces a CSR self-signed with SHA-1. That is a retired algorithm, and a CA has every reason to refuse the request rather than process it. Setting it costs one option and removes an avoidable rejection.

A note on quoting

Notice the quotation marks in the command above, and keep them. Thales documents every cmu parameter as -name=value with no spaces between the dash and the end of the value, so a value that contains one, a locality such as San Francisco or a two-word company name, has to reach the utility as a single argument. Without quotes the shell splits it, cmu sees Francisco as a parameter of its own, and you get either a truncated field or a rejected command. Wrapping the whole argument works on Command Prompt, PowerShell and a Linux shell alike. The same applies to -label in step 2: Thales requires a multi-word label to be quoted.

If you would rather not fight the shell at all, run cmu requestCertificate with only the handles and the output file. When the subject components are absent from the command line and the private key has no subject attribute set, cmu prompts for each field in turn, which sidesteps quoting entirely.

The result is a PEM certificate request, which is the default encoding. Open it and check it before you go on:

openssl req -in codesigning.csr -noout -text

Read the Subject line and the signature algorithm. The subject should be your company, the public key should be 3072-bit RSA, and the signature algorithm should be sha256WithRSAEncryption. Fixing a wrong subject now costs one command; fixing it after issuance costs a reissue.

Step 5: generate the attestation package

Now produce the confirmation for the key pair you just certified:

cmu getpkc -handle=12 -outputfile=attestation.p7b -pkctype=2 -verify=1

Points to get right:

  • -outputfile needs a real file name. A widely copied version of this command reads -outputfile=.p7b, which writes a file whose entire name is the extension, and on Linux a leading dot also makes it hidden. Give it a name you can find and upload, such as attestation.p7b, and use that same name for the rest of the procedure.
  • -handle is documented by Thales, in both the current and the archived references, as the handle of the private key the confirmation is about, which is 12 in the running example. Several CA knowledge bases print the public key handle here instead. The two are listed side by side by cmu list, so if the command returns an object error, try the other one before you assume anything is broken.
  • -verify=1 asks cmu to check the confirmation against the certificate that signed it before writing the file. It defaults to False, and it takes a boolean, so give it a value rather than passing it bare.
  • -pkctype=2 selects the Chrysalis-ITS chain. Drop the option if your client reports it as unknown, since current clients build that chain by default.

Keep the resulting attestation.p7b next to your CSR. It is not secret, it contains only public certificates, but it is specific to this key pair: generate a new key pair and the old attestation is worthless.

Step 6: check the attestation before you upload it

Three checks, in increasing order of thoroughness. The first is the utility’s own:

cmu verifypkc -inputFile=attestation.p7b

This runs an internal sign-verify against the key, which is the reason the private key had to be created with -sign=1. The second check reads the chain itself. The Luna client writes DER, so tell OpenSSL that:

openssl pkcs7 -inform DER -in attestation.p7b -print_certs -noout

You should see the confirmation certificate for your key, then the device authentication, hardware origin and manufacturing integrity certificates above it. On Windows you can also double-click the file to open it in the Certificates snap-in. Third-party tools sometimes flag certificate errors on these files because they do not recognize Thales-specific key usage attributes; that on its own is not a failure, it is a display artifact.

The most thorough check is Thales’ own Luna PKC Validator, a Java tool that validates the chain against the SafeNet root for RSA keys, or against the Thales ECC Manufacturing Integrity Certificate for ECC keys. Both root certificates are published on Thales’ key attestation page, which is also where you download the SafeNet root used in the next check. If the validator is happy, the CA’s validator has no reason not to be.

You can also test the module independently of any key, which is a useful sanity check if the attestation is being rejected and you suspect the hardware link rather than the key:

cmu verifyhsm -challenge="1234567890" -rootcert=safenet-root.pem

Save the SafeNet root certificate from Thales’ documentation into the client directory first. The command generates a temporary key pair, builds and verifies the whole chain up to the root, has the HSM sign your challenge string, and prints a pass or fail for each stage. Note that the published root has an expiry date and Thales may replace it, so take the copy from the current documentation rather than one you saved a few years ago.

Step 7: submit the CSR and the attestation

Go back to your code signing order and complete the form with the Install on Existing HSM method. Paste the contents of codesigning.csr into the CSR field, including the BEGIN and END lines, and upload attestation.p7b as the attestation file.

If the upload is rejected for encoding, the fix is one command. The attestation is binary DER, and some attestation intake services expect base64. Convert it and upload the result:

openssl pkcs7 -inform DER -in attestation.p7b -out attestation.pem

The output is the same chain wrapped in BEGIN PKCS7 and END PKCS7 lines. Keep both files until the certificate has been issued and installed.

Validation then runs as it does for any code signing order. Once the certificate is issued you import it back into the partition with cmu import -inputFile=codesigning.cer, after which you can sign with it. Our guide on how to sign an EXE file covers the signing side, and if you are working with an EV product, setting up an EV code signing certificate covers the differences.

What about ECC keys?

This guide documents an RSA key pair, because that is what the CA instructions for Luna HSMs are written around and what most code signing orders use. The hardware is not the constraint. Thales states that cmu getpkc supports both RSA and ECC key pair types, and it publishes a separate Thales ECC Manufacturing Integrity Certificate specifically for validating attestation of ECC keys. Post-quantum key attestation exists too, though it needs Luna HSM Firmware 7.9.1 or newer and the cmu shipped with Luna HSM Client 10.9.1 or newer.

The constraint is on the CA side, and it is worth a short email rather than a guess. Confirm with the CA that it will issue your code signing product against an ECDSA key and that its attestation check accepts a chain rooted in the ECC manufacturing certificate rather than the SafeNet root. Do that before you generate keys, not after: the key pair cannot be converted, so an unsupported algorithm means starting over with a new pair, a new CSR and a new attestation. If you go ahead, generate with -keyType=ECDSA and -curvetype=3 for NIST P-256 or -curvetype=4 for P-384, keeping -sign=1, -verify=1 and -extractable=0 exactly as above, and add -sha256withecdsa to the CSR command instead of -sha256withrsa.

When something fails

  • The CSR command fails to sign. The private key almost certainly lacks signing capability. -sign defaults to False, and the attribute cannot usually be changed after generation because HSMs are typically configured to reject changes to functional key attributes. Generate a fresh pair with -sign=1.
  • getpkc returns nothing or errors on the key. Check that the key is non-extractable, since the confirmation only works on non-extractable keys, and check that you passed a key handle rather than a certificate or data object handle. Extractability is a search filter rather than a displayable attribute, so list the non-extractable private keys with cmu list -class private -extractable=0 -display=handle,label: a handle that does not appear in that list belongs to an extractable key, and no confirmation can be produced for it.
  • The attestation validates locally but the CA rejects it. Two usual causes: the wrong chain, meaning a TC-Trust Center package that does not reach the SafeNet root, or the wrong key, meaning an attestation generated for a different key pair than the one in the CSR. Regenerate both files from the same handles in one sitting.
  • Key generation is refused at 4096 bits. That is HSM policy 12 restricting you to FIPS-approved sizes. Use 3072, which satisfies the code signing requirements anyway.
  • cmu prompts for a slot every time. Pass -slot with the slot number from slot list, and -password or -pin if you want to avoid the credential prompt as well. Be aware that a password on a command line lands in your shell history.
  • Nothing works because the confirmation is unsupported. Check whether Functionality Modules are enabled on the HSM. If they are, the standard attestation route is not available and the CA needs to know before validation starts.

Frequently asked questions

What is a public key confirmation on a Luna HSM?

It is a certificate the HSM itself signs, attesting to the life cycle of one specific private key. The HSM issues confirmations only for private keys that were created inside a Luna cryptographic module and that can never leave it, so a valid confirmation proves both that the key is in that module and that the module is genuine. The file is a PKCS #7 bundle holding the confirmation certificate plus the device authentication, hardware origin and manufacturing integrity certificates that chain it back to Thales.

Why does the CA need attestation at all?

Since June 2023 every publicly trusted code signing private key must live in hardware meeting FIPS 140-2 Level 2 or Common Criteria EAL 4+, with externally verifiable key attestation. When you supply your own HSM the CA has no other way to confirm that the key in your CSR was generated in qualifying hardware and cannot be exported from it.

What does -pkctype=2 do, and what happens if I get it wrong?

It selects the Chrysalis-ITS chain of trust, which is built into the cmu utility by default and terminates at Thales’ SafeNet root certificate authority. The alternative value, 1, is the older TC-Trust Center layout, which Thales’ own documentation marks as not used and which does not end at that root, so a validator expecting the SafeNet root cannot complete the path and the attestation is rejected. The option appears in Luna 7.4-era documentation and is no longer listed in the current cmu getpkc syntax; on a current client the default chain is already the right one.

Can I put any organization name in the CSR?

No. The Organization and Common Name must be your own validated legal entity, matching the registration details the CA verified. Never enter the Certificate Authority’s name, which some published example commands do, and never leave a placeholder such as a test common name in place. The certificate is issued from validated data, so a mismatch means the order comes back to you instead of going forward.

Why do -extractable=0 and -sign=1 matter so much?

They govern two different steps, which is why both are needed. -extractable=0 is what makes the attestation possible, because cmu getpkc works with non-extractable keys only, and it is also what makes the key acceptable for code signing in the first place. -sign=1 is what makes the CSR possible, because cmu requestCertificate uses the private key to sign the request, and it is also required by cmu verifypkc, which does an internal sign-verify on test data.

What key size should I use?

3072-bit RSA. That has been the minimum for code signing and timestamping certificates under the CA/Browser Forum Code Signing Baseline Requirements since June 1, 2021, so 2048 will not be accepted. Going higher is usually not an option either: on an HSM with policy 12 set to disallow non-FIPS algorithms, RSA sizes are limited to 2048 or 3072 bits.

Do I run cmu commands inside lunacm?

No. lunacm is an interactive shell for slot and partition management, and cmu is a separate command-line utility that happens to sit in the same directory. Use lunacm to confirm your partition is visible, exit it, then run each cmu command from your ordinary Command Prompt, PowerShell or Linux shell.

Which handle does cmu getpkc want?

Thales documents -handle as the handle of the private key the confirmation corresponds to, in both the current Luna Network HSM 7 reference and the archived 7.4 one. A number of CA knowledge bases print the public key handle in the same position. cmu list shows both, so if one returns an object error, try the other rather than regenerating the key pair.

Does this work on a Luna HSM with Functionality Modules enabled?

No. Thales states that the confirmation procedure is not currently supported on FM-enabled HSMs. Modules ship FM-ready, holding both the standard hardware origin key and an FM equivalent, but enabling FMs deletes the original hardware origin key and certificate and moves the chain of trust onto the FM certificate. If FMs are enabled on your appliance, raise it with the CA before starting the order.

Where do I find the Luna HSM Client on my machine?

The default locations are C:\Program Files\SafeNet\LunaClient on Windows and /usr/safenet/lunaclient/bin on Linux, and they are unchanged in the current Luna HSM Client 10.x releases. The SafeNet name in the path is correct, not stale: Thales is the vendor and SafeNet is the product line the Luna HSMs belong to.

Can I reuse an attestation file for a renewal?

Only if you reuse the same key pair, since the confirmation is bound to one specific private key. If you generate a fresh key pair for the renewal, which is generally the better practice, you must generate a fresh CSR and a fresh attestation from the new handles and submit both together.

For the other hardware routes and the rest of the ordering path, see our code signing tutorials, including CSR generation and attestation on a YubiKey 5 FIPS.

Risparmia il 10% sui certificati SSL ordinando oggi stesso da SSL Dragon!

Emissione rapida, crittografia avanzata, affidabilità del browser al 99,99%, assistenza dedicata e garanzia di rimborso entro 25 giorni. Codice coupon: SAVE10

Un'immagine dettagliata di un drago in volo
Scritto da

Scrittore di contenuti con esperienza, specializzato in certificati SSL. Trasforma intricati argomenti di cybersicurezza in contenuti chiari e coinvolgenti. Contribuisci a migliorare la sicurezza digitale attraverso narrazioni d'impatto.