Client-Side Hashing

The following describes various options for performing the hashing on the client-side instead of making all the steps in the signing on the server-side. Client-side hashing is also sometimes referred to as "hash signing" and the main advantage is that the original file does not need to be sent to the server.

CMS Detached Signatures

Detached signatures allow the signature to be placed in a separate file next to the original file, and thus the original file does not have to be updated. With CMS signatures, what is covered by the signature is a set of attributes (unless it is a direct signature) where one of the attributes is called messageDigest, which is the hash of the original file. This means that in order to create a CMS detached signature, it is sufficient to get the hash of the original file as input.

The CMS Signer is for instance 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

where SHA-256 should be replaced with the name of the hash algorithm used to digest the data. The algorithm must be one of those configured in signer with the ACCEPTED_HASH_DIGEST_ALGORITHM property.

The following commands can be used to create a detached CMS signature using this mode with a CMSSigner 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

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 involves a hash operation, it is be possible to perform that on the client side.

For the Plain Signer, this can be achieved by configuring the signer with a signature algorithm with the word NONE instead of the name of the hash. For example: "NONEwithRSA" or "NONEwithECDSA". Note that the input to the signer has to be in a particular format when using the "NONEwithRSA" algorithm for the final signature to be correct. See RFC#3447 for details.

Sample Usage (with NONEwithECDSA algorithm)

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 -infile pre-computed-hash.bin -outfile sample.sig
openssl dgst -signature sample.sig -verify plainsigner-pubkey.pem -SHA256 sample.txt

Embedded Signature Formats

ENTERPRISE  This is a SignServer Enterprise feature.

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, typically, first prepare the document for signing, compute the digest and send it to the server, and then finally embed the signature within the file.

On the client-side, support has been implemented for "client-side hashing and construction" for Authenticode signing of Portable Executable (PE) files (i.e. EXE, .DLL,..), Windows Installer files (.MSI), and for Java Archives (.JAR,.APK,..) in the SignClient signdocument command. 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 Authenticode, there is the MS Authenticode CMS Signer, and for JAR signing the JArchive CMS Signer.

ParameterDescription
-clientsideRequired in order to use client-side hashing otherwise a normal request is sent.
-digestalgorithmThe digest algorithm to use for the hash (or for the hashes within the hash file depending on file type).
-extraoptionFlag to provide extra options for signing supported by a particular file type:
-extraoption KEEPSIGNATURE=Only for signing JAR files. For more information on the property KEEPSIGNATURE, see JArchive Signer.
-extraoption REPLACESIGNATURE=Only for signing JAR files. For more information on the property REPLACESIGNATURE, see JArchive Signer.
-extraoption SIGNATURE_NAME_VALUE=Only for signing JAR files. For more information on the property SIGNATURE_NAME_VALUE, see JArchive Signer.
-extraoption ZIPALIGN=Only for signing JAR files. For more information on the property ZIPALIGN, see JArchive Signer.

Sample Usages

$ signclient signdocument -clientside -workername MSAuthCodeCMSSigner -infile unsigned.exe
-outfile signed.exe -digestalgorithm SHA-256

$ signclient signdocument -clientside -workername MSAuthCodeCMSSigner -infile unsigned.msi
-outfile signed.msi -digestalgorithm SHA-512

$ 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

OpenPGP

When using the client-side hashing and construction with OpenPGP using the OpenPGPPlainSigner, the parameters key ID and key algorithm (when using a key with an algorithm other than RSA) need to be specified with the request using the -extraoption options.

ParameterDescription
-filetype PGPSpecify that a OpenPGP signature is wanted.
-extraoption KEY_ID=Key ID (in hex format) for the PGP public key. Default: "3" (RSA)
-extraoption KEY_ALGORITHM=Key algorithm, either in text format (RSA, DSA, or ECDSA) or numeric decimal format.
-extraoption RESPONSE_FORMAT=

Format of the output. Either binary or ASCII armored. Examples: "BINARY", "ARMORED". Optional. Default: "ARMORED".

RESPONSE_FORMAT can be only be provided as "ARMORED" when DETACHED_SIGNATURE extra option is provided as "FALSE"

-extraoption DETACHED_SIGNATURE=

Property specifying if a detached signature should be used or otherwise a clear-text signature. Examples: "true", "false". Required.

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

Debian Dpkg-sig

When using the client-side hashing and construction with Dpkg-sig using the OpenPGPPlainSigner, the key ID, key fingerprint, and key algorithm (when using a key with an algorithm other than RSA) need to be specified with the request using the -extraoption options.

-filetype DPKG_SIGSpecify that a Debian Dpkg-sig signature is wanted.
-extraoption KEY_ID=Key ID (in hex format) for the PGP public key.
-extraoption KEY_ALGORITHM=Key algorithm, either in text format (RSA, DSA, or ECDSA) or numeric decimal format.
-extraoption KEY_FINGERPRINT=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.

Algorithm Support

Note that specifically for DSA signatures in client-side mode, other algorithms than SHA1 may not be supported due to the underlying implementation.

Sample Usages

The key ID is the hex-encoded representation, and the key algorithm can be specified as either a name (RSA, DSA, or ECDSA) or using one of the PGP constant values (for example 19 for ECDSA).

$ 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