Client-side hashing is the practice of hashing sensitive data on the client before sending it to a server, so the server processes only the hash rather than the original data. Client-side hashing is also sometimes referred to as "hash signing".
For a overview of client-side hashing, see Client-side Hashing.
SignClient provides support for the embedded signature formats. The following shows the general format for sending a hashing request using SignClient:
$ ./bin/signclient signdocument -clientside
-workername SIGNER_NAME
-infile UNSIGNED_FILE
-outfile SIGNED_FILE
-digestalgorithm ALGORITHM_NAME
Additional parameters are available based on the signature type.
The following provides examples for performing the hashing on the client-side with various formats:
Signing CMS Detached Signatures
Detached signatures can be stored in a separate file, so the original file remains unchanged. The CMS signature structure covers a set of attributes (unless it is a direct signature). One key attribute is messageDigest, which is the hash of the original file. To create a detached CMS signature, you only need the hash of the original file.
The CMS Signer is configured to accept a hash as input by setting CLIENTSIDEHASHING=TRUE, or by allowing the client to specify if the input is the original file or a hash of it, by configuring ALLOW_CLIENTSIDEHASHING_OVERRIDE=TRUE.
When the client sends the request, the following properties need to be provided as request metadata:
-
USING_CLIENTSUPPLIED_HASH=true -
CLIENTSIDE_HASHDIGESTALGORITHM=SHA-256(or the name of the hash algorithm used to digest the data)
The algorithm must be one of those configured in the signer with the ACCEPTED_HASH_DIGEST_ALGORITHMS property.
The following commands can be used to create a detached CMS signature using this mode with a CMS Signer set up to default to consider requests as client-side computed hash (using the CLIENTSIDEHASHING property) assuming a GNU/Linux, or Unix-like system is used:
$ echo "data-to-be-signed" | openssl sha256 -binary > pre-computed-hash.bin
$ ./bin/signclient signdocument
-workername CMSSigner
-metadata USING_CLIENTSUPPLIED_HASH=true
-metadata CLIENTSIDE_HASHDIGESTALGORITHM=SHA-256
-infile pre-computed-hash.bin
-outfile signed.p7s
Signing Plain Signatures
For plain signatures, as produced by the Plain Signer, generally the whole file is sent to the signer and returned is the small signature. However, as the plain signature schemes involve a hash operation, it is possible to perform that on the client-side.
SignServer supports the following two options of using plain signatures with client-side hashing:
-
Explicitly specifying client-side hashing using request metadata properties: Works with algorithms RSASSA-PKCS1_v1.5, RSASSA-PSS, and ECDSA, for known hash algorithms and is the recommended option as of SignServer version 5.9. See Explicitly using Request Metadata Properties.
-
Implicitly using client-side hashing without request metadata properties: Supported for RSASSA-PKCS1_v1.5 and ECDSA but not for RSASSA-PSS. The input may also need special encoding, see Implicitly and With Encoding Depending on Algorithm.
For client-side hashing with ML-DSA keys, you can use External μ to sign plain signatures. See Signing with ML DSA External μ.
Explicitly using Request Metadata Properties
Recommended
We recommend explicitly specifying client-side hashing using request metadata properties. This configuration works with algorithms NONEwithRSA (RSASSA-PKCS1_v1.5), NONEwithRSAandMGF1 (RSASSA-PSS), NONEwithECDSA, and for known hash algorithms.
To explicitly specify client-side hashing, configure the Plain Signer:
-
Set
CLIENTSIDEHASHINGto true. -
Set the
SIGNATUREALGORITHMto one of the NONEwith... signature algorithms. -
Set the
ACCEPTED_HASH_DIGEST_ALGORITHMS.
For descriptions of available properties, see Plain Signer. For algorithm support, see Plain Signer Algorithm Support.
In SignClient, use the signdocument command to send the hashing request:
-
Provide the
-workername. -
Set the metadata value
USING_CLIENTSUPPLIED_HASHto true. -
Set the metadata value
CLIENTSIDE_HASHDIGESTALGORITHMto the name of the hash algorithm used to digest the data. The algorithm must be one of those configured in the Signer with theACCEPTED_HASH_DIGEST_ALGORITHMSproperty.
Example for RSASSA-PKCS1_v1.5
openssl x509 -in PlainSigner-certificate.pem -noout -pubkey > plainsigner-pubkey.pem
openssl dgst -sha256 -out pre-computed-hash.bin -binary sample.txt
bin/signclient signdocument -workername PlainSigner -metadata USING_CLIENTSUPPLIED_HASH=true -metadata CLIENTSIDE_HASHDIGESTALGORITHM=SHA-256 -infile pre-computed-hash.bin -outfile sample.sig
openssl dgst -signature sample.sig -verify plainsigner-pubkey.pem -SHA256 sample.txt
Example for RSASSA-PSS
openssl x509 -in PlainSigner-certificate.pem -noout -pubkey > plainsigner-pubkey.pem
openssl dgst -sha256 -out pre-computed-hash.bin -binary sample.txt
bin/signclient signdocument -workername PlainSigner -metadata USING_CLIENTSUPPLIED_HASH=true -metadata CLIENTSIDE_HASHDIGESTALGORITHM=SHA-256 -infile pre-computed-hash.bin -outfile sample.sig
openssl dgst -signature sample.sig -verify plainsigner-pubkey.pem -SHA256 -sigopt rsa_padding_mode:pss sample.txt
Signing Embedded Signature Formats
For signature formats where the signature is to be placed within the original document, additional logic has to be implemented on the client-side in order to:
-
Prepare the document for signing.
-
Compute the digest.
-
Send it to the server.
-
Embed the signature within the file.
On the client-side, support has been implemented for "client-side hashing and construction" for various signature formats:
-
Authenticode signing of Portable Executable (PE) files (EXE, DLL,..)
-
Authenticode signing of Windows Installer files (MSI)
Support for other file types such as PDF may also be implemented.
On the server-side, typically a CMS Signer is needed but since Authenticode and JAR signing are producing slightly different variants of the CMS signatures, different implementations are available for use. For instance for Authenticode, there is the MS Authenticode CMS Signer, and for JAR signing the JArchive CMS Signer.
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
The digest algorithm to use for the hash (or for the hashes within the hash file depending on file type). This option may be ignored if the algorithm to be used is determined in other way by the implementation. |
|
|
(Optional) One of the supported file type identifiers (see below). If not provided the implementation tries to guess the file type base on the file extension or content of the file. |
|
|
Flag to provide extra options for signing supported by a particular file type. |
Signing Authenticode Files
Enterprise
The MS Authenticode Signer supports the following formats:
-
PE: Portable Executable files (.exe, .dll, ...)
-
MSI: Windows Installer files (.msi)
-
PS1: PowerShell (.ps1, .psd, .psm)
-
CAB: Cabinet archives (.cab)
For signing of APPX/MSIX, see the APPX Signing section.
When using the client-side hashing and construction for Authenticode file signing using the MS Authenticode CMS Signer, the following formats are available:
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
Provide the digest algorithm to use for the hash. |
|
|
(Optional) Specifies a particular file type. If not provided, SignClient tries to guess the type. |
|
|
For more information on the property |
|
|
For more information on the property |
|
|
Set to true to use the legacy MS Authenticode implementation. By default, SignClient uses Jsign to embed signatures into a file. For embedding signatures into MSI installer packages, SignClient must use the legacy implementation. The |
Sample Usage
$ signclient signdocument -clientside -workername MSAuthCodeCMSSigner -infile unsigned.exe
-outfile signed.exe -digestalgorithm SHA-512
$ signclient signdocument -clientside -workername MSAuthCodeCMSSigner -infile unsigned.msi
-outfile signed.msi -digestalgorithm SHA-256
$ signclient signdocument -clientside -workername MSAuthCodeCMSSigner -infile unsigned.ps1
-outfile signed.ps1 -digestalgorithm SHA-256
Signing JAR Files
Enterprise
When using the client-side hashing and construction for JAR file signing using the JArchive CMS Signer, the following options are available:
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
The digest algorithm to use for the hashes in the manifest / signature file. |
|
|
Specify that a ZIP/JAR signature is wanted. |
|
|
For more information on the property |
|
|
For more information on the property |
|
|
For more information on the property |
|
|
For more information on the property |
Sample Usage
$ signclient signdocument -clientside -workername JArchiveCMSSigner -infile unsigned.jar
-outfile signed.jar -digestalgorithm SHA-256
$ signclient signdocument -clientside -workername JArchiveCMSSigner -infile unsigned.apk
-outfile signed.apk -digestalgorithm SHA-256 -extraoption ZIPALIGN=TRUE -extraoption SIGNATURE_NAME_VALUE=SIGNER02
Signing APK Files
Enterprise
When using the client-side hashing and construction for Android Package Kit (APK) file signing using the APK Hash Signer, the following -extraoptions can be used:
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
Any valid digest algorithm value (such as SHA-256) needs to be supplied but is ignored as the algorithm to be used is determined based on key size and API level. |
|
|
Specify that an APK file is provided for signing. |
|
|
Enable (true) to Include APK version 1 signature. Valid values: true or false. If not set, will use default behavior depending on SDK version. |
|
|
Enable (true) to Include APK version 2 signature. Valid values: true or false. If not set, will use default behavior depending on SDK version. |
|
|
Enable (true) to Include APK version 3 signature. Valid values: true or false. If not set, will use default behavior depending on SDK version. |
|
|
Minimum SDK version of APK supported to be signed. Valid values: a positive integer. |
|
|
Minimum SDK version of APK supported to be signed. Valid values: a positive integer. |
|
|
Maximum SDK version of APK supported to be signed. Valid values: a positive integer. This parameter is not currently enforced, but reserved for future use. |
|
|
True if debuggable APK should be allowed to be signed. Valid values: true or false. If not set, debuggable APKs will not be permitted. |
Algorithm Support
SignClient assumes the server-side signer is configured with either NONEwithECDSA or NONEwithRSA as signature algorithm. SignClient currently supports SHA1, SHA-256, SHA-384, and SHA-512 with RSA and SHA1, SHA-224, SHA-256, SHA-384, and SHA-512 with ECDSA.
Sample Usage
$ signclient signdocument -workername ApkHashSigner -infile unsigned.apk -outfile signed.apk -clientside -digestalgorithm SHA-256 -filetype APK
$ signclient signdocument -workername ApkHashSigner -infile unsigned.apk -outfile signed.apk -clientside -digestalgorithm SHA-256 -filetype APK -extraoption V3_SIGNATURE=false
$ signclient signdocument -workername ApkHashSigner -infile unsigned.apk -outfile signed.apk -clientside -digestalgorithm SHA-256 -filetype APK -extraoption V1_SIGNATURE=true
Signing OpenPGP Files
Enterprise
When using the client-side hashing and construction with OpenPGP using the OpenPGP Plain Signer, in the request you need to specify:
-
The
-filetypeas PGP. -
The
-extraoption KEY_ID=for the PGP public key, in hex format. -
The
-extraoption KEY_ALGORITHM=in text or numeric decimal format. -
The
-extraoption DETACHED_SIGNATURE=based on if a detatched signature should be used.
Available Parameters
|
Parameter |
Description |
|---|---|
|
|
Specify that an OpenPGP signature is wanted. |
|
|
Key ID (in hex format) for the PGP public key. Default: 3 (RSA) |
|
|
Key algorithm, either in text format (RSA or ECDSA) or numeric decimal format, using one of the PGP constant values (for example, 19 for ECDSA) |
|
|
(Optional) Format of the output. Either binary or ASCII armored. Examples: BINARY, ARMORED Default: ARMORED
|
|
|
Required. Property specifying if a detached signature should be used or otherwise a clear-text signature. Examples: true, false |
Sample Usage
$ signclient signdocument -workername OpenPGPPlainSigner -clientside -digestalgorithm SHA-256 -filetype PGP\
-infile file-to-be-signed -outfile signed-file -extraoption KEY_ID=1234567890ABC -extraoption KEY_ALGORITHM=ECDSA\
-extraoption RESPONSE_FORMAT=ARMORED -extraoption DETACHED_SIGNATURE=TRUE
$ signclient signdocument -workername OpenPGPPlainSigner -clientside -digestalgorithm SHA-256 -filetype PGP\
-infile file-to-be-signed -outfile signed-file -extraoption KEY_ID=1234567890ABC -extraoption KEY_ALGORITHM=ECDSA\
-extraoption RESPONSE_FORMAT=ARMORED -extraoption DETACHED_SIGNATURE=FALSE
Signing Debian Dpkg-sig Files
Enterprise
When using the client-side hashing and construction with Dpkg-sig using the OpenPGP Plain Signer, in the request you need to specify:
-
The
-filetypeas DPKG_SIG. -
The
-extraoption KEY_ID=for the PGP public key, in hex format. -
The
-extraoption KEY_ALGORITHM=in text or numeric decimal format. -
The
-extraoption KEY_FINGERPRINT=for the PGP public key.
|
Parameter |
Description |
|---|---|
|
|
Specify that a Debian Dpkg-sig signature is wanted. |
|
|
Key ID (in hex format) for the PGP public key. |
|
|
Key algorithm, either in text format (RSA or ECDSA) or numeric decimal format, using one of the PGP constant values (for example, 19 for ECDSA). |
|
|
Key fingerprint (in hex format) for the PGP public key. This is included in the signed manifest. |
You can run without the required KEY_ options and the server will give an error message that includes the values that can be used.
Sample Usages
$ signclient signdocument -workername OpenPGPPlainSigner -clientside -digestalgorithm SHA-256 -filetype DPKG_SIG\
-infile hello.deb -outfile hello-signed.deb -extraoption KEY_ID=4B821662F54A5923 -extraoption KEY_ALGORITHM=ECDSA\
-extraoption KEY_FINGERPRINT=23C0B776EEE6A30D6530ACD44B821662F54A5923
$ signclient signdocument -workername OpenPGPPlainSigner -clientside -digestalgorithm SHA-256 -filetype DPKG_SIG\
-infile hello.deb -outfile hello-signed.deb -extraoption KEY_ID=4B821662F54A5923 -extraoption KEY_ALGORITHM=19\
-extraoption KEY_FINGERPRINT=23C0B776EEE6A30D6530ACD44B821662F54A5923
Signing DNSSEC Files
Enterprise
When using the client-side hashing and construction for DNSSEC zone file signing using the ZoneHash Signer, in the request you need to specify:
-
The
-filetypeas ZONE_ZIP. -
The
-extraoption ZONE_NAME=as the absolute domain name. -
The
-extraoption MIN_REMAINING_VALIDITY=to minimum remaining validity time in seconds.
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
The digest algorithm to use for the hash. |
|
|
Specify that a DNS zone file is provided in the ZIP file. The first file in the archive must be the new (unsigned) zone file. Optionally, the previously signed zone file can be provided after it and in which case valid signatures from it may be re-used. |
|
|
Sequence number of the ZSK key to use. The key with this sequence number will be used to sign the record and the next key in sequence will be included (or pre-published). |
|
|
Required. Absolute domain name. Example: example.com |
|
|
Minimum remaining time in seconds required to be able to re-use a previously signed record instead of resigning it. Required unless |
|
|
If set to true, do not consider the minimum remaining validity and instead re-sign all records even if they are not expired. This should be done when a new key should be used for signing, such as when the Default: false |
Sample Usage
$ signclient signdocument -workername ZoneHashSigner -clientside -digestalgorithm SHA-256 -filetype ZONE_ZIP\
-infile example.com.zone.zip -outfile example.com-signed.zone -metadata ZSK_SEQUENCE_NUMBER=1 -extraoption ZONE_NAME=example.com. -extraoption MIN_REMAINING_VALIDITY=86400
Signing APPX Files
Enterprise
When using the client-side hashing and construction for .appx file signing using the APPX CMS Signer, the following options are available:
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
The digest algorithm to use for the hash. |
|
|
Specify that an APPX file is provided for signing. |
Sample Usage
$ signclient signdocument -workername AppxCMSSigner -infile HelloAppx.appx -outfile HelloAppx-signed.appx -clientside -digestalgorithm SHA-256 -filetype APPX
Signing RPM Packages using SignWrapper
Enterprise
When using the client-side hashing and construction for the .rpm file using the OpenPGP Plain Signer, the following parameters are required:
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
The digest algorithm to use for the hash. |
|
|
Specify that a PGP signature is wanted. |
|
|
Key ID (in hex format) for the PGP public key. |
|
|
Key algorithm, either in text format (RSA or ECDSA) or numeric decimal format. |
|
|
A detached signature is required as the RPM command expects a PGP signature to be returned. |
|
|
Expected encoding format for RPM. |
You must use the environment variable called SIGNCLIENT_PARAMS with these parameters, so that the SignWrapper can pass the parameters to SignClient.
For example:
SIGNCLIENT_PARAMS="-clientside -digestalgorithm SHA-256 -extraoption KEY_ID=<Key ID> -extraoption KEY_ALGORITHM=1 -extraoption RESPONSE_FORMAT=BINARY -extraoption DETACHED_SIGNATURE=true -filetype PGP"
Some prerequisites are required to get RPM signing to work. For a setup guide, see Code Signing with RPM Signatures.
Signing with ML-DSA External μ
Enterprise
Client-side hashing with ML-DSA keys uses a signature structure called External μ creates data to be signed based on the file or data specified in the request, alongside the public key of an ML-DSA key pair. Currently, the structure is only supported for Plain Signatures.
The following parameters are required:
|
Parameter |
Description |
|---|---|
|
|
Required in order to use client-side hashing. Otherwise, a normal request is sent. |
|
|
Specify that an External μ formatted representation of the data is to be produced and signed. |
|
|
A base64 encoded public key of ML-DSA key pair used by the signer. |
When signing with ML-DSA External μ, the digest algorithm flag is not needed as SHAKE256 is used when μ is created. The Plain Signer performing the signature will need to have the property ACCEPTED_HASH_DIGEST_ALGORITHMS configured with a valid digest algorithm, such as SHA-512 or SHAKE256.
However, SHAKE256 will be the digest hash algorithm used when constructing the μ regardless of the configured accepted digest algorithms of the Plain Signer.
Sample Usage
$ signclient signdocument -workername PlainSigner -infile sample.pdf -outfile signed.p7s -clientside -filetype MLDSAExtMu -publickey <Base64 encoded public key>