Jsign is a versatile code signing tool that allows you to sign and timestamp Windows executable files, installer packages and scripts. Jsign is platform independent and provides an alternative to native tools like signtool on Windows or the Mono development tools on Unix systems. It's particularly well-suited for signing executable wrappers and installers generated by tools such as NSIS, msitools, install4j, exe4j or launch4j. It emphasizes on seamless integration with cloud key management systems and hardware tokens.
Jsign is available as a command line tool for Linux, macOS and Windows, as a task/plugin for various build systems (Maven, Gradle, Ant, GitHub Actions), and as a Java library.
Jsign is free to use and licensed under the Apache License version 2.0.
Features
- Platform independent signing of Windows executables, DLLs, Microsoft Installers (MSI), Cabinet files (CAB), Catalog files (CAT), Windows packages (APPX/MSIX), Microsoft Dynamics 365 extension packages, NuGet packages and scripts (PowerShell, VBScript, JScript, WSF)
- Timestamping with retries and fallback on alternative servers (RFC 3161 and Authenticode protocols supported)
- Supports multiple signatures per file, for all file types
- Extracts and embeds detached signatures to support reproducible builds
- Certificate chain completion
- Hashing algorithms: MD5, SHA-1, SHA-256, SHA-384 and SHA-512
- Keystores supported:
- PKCS#12, JKS and JCEKS files
- PKCS#11 hardware tokens (YubiKey, Nitrokey, SafeNet eToken, etc)
- Cloud key management systems:
- Private key formats: PVK and PEM (PKCS#1 and PKCS#8), encrypted or not
- Certificates: PKCS#7 in PEM and DER format
- Automatic download of the intermediate certificates
- Build tools integration (Maven, Gradle, Ant, GitHub Actions)
- Command line signing tool
- Authenticode signing API (Javadoc)
- JCA security provider to use the keystores supported by Jsign with other tools such as jarsigner or apksigner
Downloads
- DEB package (Debian/Ubuntu)
- RPM package (RedHat/Fedora)
- Chocolatey package (Windows)
- Homebrew package (macOS/Linux)
- All-in-one JAR (Other systems, Ant task, JCA provider)
Ant Task
Here is an example showing how the signing works with Ant, using a Java keystore:
<taskdef name="jsign" classname="net.jsign.JsignTask" classpath="jsign-6.0.jar"/> <jsign file="application.exe" name="My Application" url="http://www.example.com" keystore="keystore.jks" storepass="password" alias="test" tsaurl="http://timestamp.sectigo.com"/>
Another example with SPC
and PVK
files commonly used with signcode.exe
:
<jsign file="application.exe" certfile="certificate.spc" keyfile="key.pvk" keypass="password" tsaurl="http://timestamp.digicert.com"/>
The task also accepts a fileset to sign multiple files:
<jsign keystore="keystore.p12" storepass="password" alias="test"> <fileset dir="build/binaries" includes="*.exe"/> </jsign>
The sign
command is used by default, but other commands can be specified with the command
attribute. For example for tagging a signed file with user identification data without
invalidating the signature:
<jsign command="tag" value="userid:1234-ABCD-5678-EFGH" file="application.exe"/>
Attributes
Attribute | Description | Required |
---|---|---|
file | The file to be signed. The supported files are Windows executables (EXE), DLLs, Microsoft Installers (MSI), Cabinet files (CAB), Catalog files (CAT), Windows packages (APPX/MSIX), Microsoft Dynamics 365 extension packages, NuGet packages and scripts (PowerShell, VBScript, JScript, WSF) | Yes, unless a fileset is specified. |
name | The name of the application | No |
url | The URL of the application | No |
keystore | The keystore file, the SunPKCS11 configuration file, the cloud keystore name, or the smart card or hardware token name. | Yes for file based keystores, PKCS#11 and cloud signing services. Optional for cards/tokens.
No when certfile and keyfile are specified. |
storepass |
The password to open the keystore. The password can be loaded from a file by using the file: prefix
followed by the path of the file, or from an environment variable by using the env: prefix followed
by the name of the variable.
|
No |
storetype |
The type of the keystore.
File based:
Hardware tokens:
Cloud key management systems:
|
No, automatically detected for file based keystores. |
alias | The alias of the certificate used for signing in the keystore. | Yes, if keystore is specified and more than one alias exist |
certfile |
The file containing the PKCS#7 certificate chain, in PEM or DER format (.p7b or .spc
files). This parameter is required if keystore isn't specified, or if the keystore used contains
only the key and not the certificate chain. It may be specified if the keystore holds only the signing
certificate and not the full certificate chain, otherwise Jsign will attempt to download the missing
certificates from the URL specified in the Authority Information Access field of the certificates.
This parameter can also be used to replace the certificate chain from the keystore.
|
No, depends on the keystore used. |
keyfile |
The file containing the private key. PEM and PVK files are supported.
|
|
keypass |
The password of the private key. When using a keystore, this parameter can be omitted if the keystore shares
the same password. The password can be loaded from a file by using the file: prefix followed by
the path of the file, or from an environment variable by using the env: prefix followed by the
name of the variable.
|
No |
alg | The digest algorithm (SHA-1, SHA-256, SHA-384 or SHA-512). | No; defaults to SHA-256 or a format specific value |
tsaurl |
The URL of the timestamping authority, either RFC 3161 or Authenticode services.
You can use for example the Sectigo (http://timestamp.sectigo.com)
or the DigiCert (http://timestamp.digicert.com) services. Several URLs separated by a comma can be specified to fallback on alternative servers. |
No |
tsmode | The timestamping mode (RFC3161 or Authenticode) | No; defaults to Authenticode |
tsretries | The number of retries for timestamping | No; defaults to 3 |
tsretrywait | The number of seconds to wait between timestamping retries | No; defaults to 10 seconds |
replace | Tells if previous signatures should be replaced. | No; defaults to "false" |
encoding | The encoding of the script to be signed (if it doesn't contain a byte order mark). | No; defaults to "UTF-8" |
detached |
Tells if a detached signature should be generated or reused. The detached signature
is a file in the same directory using the name of the file signed with the .sig
suffix added (for example application.exe.sig ).
|
No; defaults to "false" |
value |
The value of the unsigned attribute when tagging a file. The value is either:
If no value is specified a default 1KB template is used, filled with zeros and delimited by
|
No; defaults to 1KB template |
Maven plugin
Here is an example showing how the signing works with Maven. The parameters
are the same as those described above for the Ant task. The execution is bound
by default to the package
phase.
<build> <plugins> <plugin> <groupId>net.jsign</groupId> <artifactId>jsign-maven-plugin</artifactId> <version>6.0</version> <executions> <execution> <goals> <goal>sign</goal> </goals> <configuration> <file>application.exe</file> <name>My Application</name> <url>http://www.example.com</url> <keystore>keystore.jks</keystore> <alias>test</alias> <storepass>password</storepass> </configuration> </execution> </executions> </plugin> </plugins> </build>
It's possible to sign multiple files by using a fileset
element instead of file
:
... <configuration> <fileset> <directory>target</directory> <includes> <include>*.exe</include> </includes> </fileset> <keystore>keystore.jks</keystore> <alias>test</alias> <storepass>password</storepass> </configuration> ...
The value of the storepass
and keypass
elements can be encrypted using the
Maven master password:
<configuration> <file>application.exe</file> <keystore>keystore.jks</keystore> <storepass>{COQLCE6DU6GtcS5P=}</storepass> </configuration>
The storepass
and keypass
elements may also reference a password defined
in the Maven settings file.
In ${user.home}/.m2/settings.xml
a server is defined with the password of the keystore:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"> ... <servers> <server> <id>keystore</id> <password>password</password> </server> </servers> ... </settings>
And in the Maven project file, the password element references the server id prefixed with mvn:
:
<configuration> <file>application.exe</file> <keystore>keystore.jks</keystore> <storepass>mvn:keystore</storepass> </configuration>
Gradle plugin
Here is an example showing how to use Jsign with Gradle. The parameters are the same as those described above for the Ant task.
With the Groovy syntax:
plugins { id 'net.jsign' version '6.0' } task sign { doLast { jsign(file : 'application.exe', name : 'My Application', url : 'http://www.example.com', keystore : 'keystore.p12', alias : 'test', storepass : 'secret', tsaurl : 'http://timestamp.sectigo.com') } }
With the Kotlin syntax:
plugins { id("net.jsign") version "6.0" } task("sign") { doLast { val jsign = project.extensions.getByName("jsign") as groovy.lang.Closure<*> jsign("file" to "application.exe", "name" to "My Application", "url" to "http://www.example.com", "keystore" to "keystore.p12", "alias" to "test", "storepass" to "secret", "tsaurl" to "http://timestamp.sectigo.com") } }
GitHub Actions
Jsign can be used in GitHub Actions by inserting the following steps in the workflow:
steps: [...] - name: Set up Java uses: actions/setup-java@v4 with: java-version: 17 distribution: 'temurin' - name: Download Jsign run: wget https://github.com/ebourg/jsign/releases/download/6.0/jsign-6.0.jar - name: Sign run: > java -jar jsign-6.0.jar --storetype TRUSTEDSIGNING --keystore weu.codesigning.azure.net --storepass ${{ secrets.AZURE_ACCESS_TOKEN }} --alias <account>/<profile> ${{ github.workspace }}/dist/application.exe
Command Line Tool
On systems with an installation package available the command line is invoked with:
jsign [OPTIONS] [FILE]...
On other systems the command line is invoked by running the jar with:
java -jar jsign-6.0.jar [OPTIONS] [FILE]...
The parameters expected are the same as those used by the Ant task:
usage: jsign [COMMAND] [OPTIONS] [FILE] [PATTERN] [@FILELIST]... Sign and timestamp Windows executable files, Microsoft Installers (MSI), Cabinet files (CAB), Catalog files (CAT), Windows packages (APPX/MSIX), Microsoft Dynamics 365 extension packages, NuGet packages and scripts (PowerShell, VBScript, JScript, WSF) commands: sign (default), timestamp, extract, remove, tag sign: -s,--keystore <FILE> The keystore file, the SunPKCS11 configuration file, the cloud keystore name, or the card/token name --storepass <PASSWORD> The password to open the keystore --storetype <TYPE> The type of the keystore File based: - JKS: Java keystore (.jks files) - JCEKS: SunJCE keystore (.jceks files) - PKCS12: Standard PKCS#12 keystore (.p12 or .pfx files) Hardware tokens: - PKCS11: PKCS#11 hardware token - ETOKEN: SafeNet eToken - NITROKEY: Nitrokey HSM - OPENPGP: OpenPGP card - OPENSC: Smart card - PIV: PIV card - YUBIKEY: YubiKey security key Cloud key management systems: - AWS: AWS Key Management Service - AZUREKEYVAULT: Azure Key Vault key management system - DIGICERTONE: DigiCert ONE Secure Software Manager - ESIGNER: SSL.com eSigner - GARASIGN: Garantir Remote Signing - GOOGLECLOUD: Google Cloud KMS - HASHICORPVAULT: HashiCorp Vault - ORACLECLOUD: Oracle Cloud Key Management Service - SIGNSERVER: Keyfactor SignServer - TRUSTEDSIGNING: Azure Trusted Signing -a,--alias <NAME> The alias of the certificate used for signing in the keystore --keypass <PASSWORD> The password of the private key. When using a keystore, this parameter can be omitted if the keystore shares the same password --keyfile <FILE> The file containing the private key (supports PEM & PVK files) -c,--certfile <FILE> The file containing the PKCS#7 certificate chain (.p7b or .spc files). -d,--alg <ALGORITHM> The digest algorithm (SHA-1, SHA-256, SHA-384 or SHA-512) -t,--tsaurl <URL> The URL of the timestamping authority -m,--tsmode <MODE> The timestamping mode (RFC3161 or Authenticode) -r,--tsretries <NUMBER> The number of retries for timestamping -w,--tsretrywait <SECONDS> The number of seconds to wait between timestamping retries -n,--name <NAME> The name of the application -u,--url <URL> The URL of the application --proxyUrl <URL> The URL of the HTTP proxy --proxyUser <NAME> The user for the HTTP proxy. If a user is needed --proxyPass <PASSWORD> The password for the HTTP proxy user. If a user is needed --replace Tells if the previous signatures should be replaced -e,--encoding <ENCODING> The encoding of the script to be signed (UTF-8 by default, or the encoding specified by the byte order mark if there is one) --detached Tells if a detached signature should be generated or reused --quiet Print only error messages --verbose Print more information --debug Print debugging information -h,--help Print the help timestamp: -t,--tsaurl <URL> The URL of the timestamping authority -m,--tsmode <MODE> The timestamping mode (RFC3161 or Authenticode) -r,--tsretries <NUMBER> The number of retries for timestamping -w,--tsretrywait <SECONDS> The number of seconds to wait between timestamping retries --proxyUrl <URL> The URL of the HTTP proxy --proxyUser <NAME> The user for the HTTP proxy. If a user is needed --proxyPass <PASSWORD> The password for the HTTP proxy user. If a user is needed --replace Tells if the previous timestamps should be replaced extract: --format <FORMAT> The output format of the signature (DER or PEM) tag: --value <VALUE> The value of the unsigned attribute
After the options Jsign accepts one or more files to sign as arguments. The arguments may contain '*'
or '**'
wildcards to match multiple files and scan through directories recursively. For example using
build/*.exe
will sign the executables in the build directory, and installdir/**/*.dll
will
scan the installdir directory recursively and sign all the DLLs found. If an argument starts with @ it is considered
as a text file containing a list of files to sign, one per line.
Examples
Signing with a Java keystore
jsign --keystore keystore.jks --storepass password --alias test \ --tsaurl http://timestamp.sectigo.com application.exe
Signing with a SPC certificate and a PVK key
jsign --certfile certificate.spc --keyfile key.pvk --keypass password application.exe
Signing with a YubiKey
When using a Yubikey, the alias is required only if the device contains more than one certificate. The certificate is specified by its name (typically X.509 Certificate for Digital Signature for the slot 9c, or X.509 Certificate for PIV Authentication for the slot 9a). The ykcs11 library from the Yubico PIV Tool must be installed on the system at the default location.
jsign --storetype YUBIKEY --storepass 123456 application.exe
Alternatively, the PIV storetype can also be used to sign with a Yubikey and doesn't require the ykcs11 library.
Signing with a Nitrokey HSM
Signing with a Nitrokey HSM requires the installation of OpenSC.
jsign --storetype NITROKEY --storepass 123456 --alias test \ --certfile full-chain.pem application.exe
Other Nitrokeys based on the OpenPGP card standard are also supported with this storetype, but an X.509 certificate must be imported into the Nitrokey (using the gnupg writecert command). Keys without certificates are ignored. Alternatively, the OPENPGP storetype can also be used, it doesn't require OpenSC and any key can be used by providing an external certificate.
Signing with a SafeNet eToken
Signing with a SafeNet eToken requires the installation of the SafeNet Authentication Client.
jsign --storetype ETOKEN --storepass <PIN> application.exe
Signing with a smart card
Signing with a smart card requires the installation of OpenSC.
jsign --storetype OPENSC --storepass 123456 --alias test \ --certfile full-chain.pem application.exe
If multiple devices are connected, the keystore
parameter can be used to specify
the name of the one to use.
Signing with an OpenPGP card
OpenPGP cards contain up to 3 keys, one for signing, one for encryption, and one for authentication. All of them
can be used for code signing (except encryption keys based on an elliptic curve). The alias to select the key is either,
SIGNATURE
, ENCRYPTION
or AUTHENTICATION
. The OPENPGP storetype can be used with
a Nitrokey (non-HSM models) or a Yubikey.
jsign --storetype OPENPGP --storepass 123456 --alias SIGNATURE \ --certfile full-chain.pem application.exe
The certfile
parameter is only required if no X.509 certificate is stored on the card for the key used.
If multiple devices are connected, the keystore
parameter can be used to specify
the name of the one to use.
Signing with a PIV card
PIV cards contain up to 24 keys and certificates. The alias to select the key is either AUTHENTICATION
,
SIGNATURE
, KEY_MANAGEMENT
, CARD_AUTHENTICATION
, or RETIRED<1-20>
.
Slot numbers are also accepted (for example 9c
for the digital signature key).
jsign --storetype PIV --storepass 123456 --alias SIGNATURE application.exe
If multiple devices are connected, the keystore
parameter can be used to specify
the name of the one to use.
Signing with AWS Key Management Service
AWS Key Management Service (KMS) stores only the private key,
the certificate must be provided separately. The keystore
parameter references the AWS region.
Setting the AWS_USE_FIPS_ENDPOINT
environment variable to true
will ensure the FIPS
endpoint is used.
The AWS access key, secret key, and optionally the session token, are concatenated
and used as the storepass
parameter; if the latter is not provided, Jsign attempts to fetch the credentials
from the environment variables (AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
and AWS_SESSION_TOKEN
)
or from the IMDSv2 service
when running on an AWS EC2 instance.
In any case, the credentials must allow the following actions:
kms:ListKeys
, kms:DescribeKey
and kms:Sign
.
The alias
parameter can specify either the key id or an alias.
jsign --storetype AWS \ --keystore eu-west-3 \ --storepass "<access-key>|<secret-key>|<session-token>" \ --alias 12345678-abcd-1234-cdef-1234567890ab \ --certfile full-chain.pem application.exe
Signing with Azure Key Vault
Certificates and keys stored in the Azure Key Vault key management system can be used with:
jsign --storetype AZUREKEYVAULT \ --keystore vaultname \ --storepass <api-access-token> \ --alias test application.exe
The access token can be obtained with the Azure CLI:
az account get-access-token --resource "https://vault.azure.net"
The Azure account used must have the "Key Vault Crypto User" and "Key Vault Certificate User" roles.
Signing with Azure Trusted Signing
With the Azure Trusted Signing service
the keystore
parameter specifies the endpoint URI, and the alias
combines the account name and
the certificate profile. The Azure API access token is used as the keystore password.
jsign --storetype TRUSTEDSIGNING \ --keystore weu.codesigning.azure.net \ --storepass <api-access-token> \ --alias <account>/<profile> application.exe
The access token can be obtained with the Azure CLI:
az account get-access-token --resource https://codesigning.azure.net
The Azure account used must have the "Code Signing Certificate Profile Signer" role.
The certificates issued by Azure Trusted Signing have a lifetime of 3 days only, and timestamping is necessary to ensure the long term validity of the signature. For this reason timestamping is automatically enabled when signing with this service.
Implementation note: Jsign performs an extra call to the signing API to retrieve the current certificate chain before signing. When signing multiple files it's recommended to invoke Jsign only once with the list of files to avoid doubling the quota usage.
Signing with DigiCert ONE / DigiCert KeyLocker
Certificates and keys stored in the DigiCert ONE Secure Software Manager
can be used directly without installing the DigiCert client tools. It requires an API key and a PKCS#12 keystore holding
a client certificate for the authentication. The US DigiCert ONE host is used by default (https://clientauth.one.digicert.com)
but a different host can be specified with the --keystore
parameter.
jsign --storetype DIGICERTONE \ --storepass "<api-key>|/path/to/Certificate_pkcs12.p12|<password>" \ --alias test application.exe
Signing with SSL.com eSigner
When signing with the SSL.com eSigner service, the SSL.com username and password are used as the keystore password, and the base64 encoded TOTP secret is used as the key password:
jsign --storetype ESIGNER \ --storepass "<username>|<password>" \ --alias 8b072e22-7685-4771-b5c6-48e46614915f \ --keypass <totp-secret> application.exe
SSL.com provides a sandbox environment, to use a test certificate simply add the parameter
--keystore https://cs-try.ssl.com
.
Signing with GaraSign
GaraSign is a remote signing service provided by Garantir.
The authentication is performed by specifying the username/password or the TLS client certificate in the
storepass
parameter. If the TLS client certificate is stored in a password protected keystore,
the password is specified in the keypass
parameter. The keystore
parameter references
the URL of the GaraSign REST API (https://garasign.com:8443/CodeSigningRestService/ by default).
Authenticating with a username and a password:
jsign --storetype GARASIGN \ --storepass "<username>|<password>" \ --alias test \ application.exe
Authenticating with a TLS client certificate and a non-default endpoint:
jsign --storetype GARASIGN \ --keystore https://demo.garantir.io/CodeSigningRestService \ --storepass "/path/to/client-certificate.p12" \ --keypass <client-certificate-password> \ --alias test \ application.exe
Signing with Google Cloud KMS
Google Cloud KMS stores only the private key, the certificate must be provided separately. The keystore parameter references the path of the keyring. The alias specifies the name and the version of the key:
jsign --storetype GOOGLECLOUD \ --keystore projects/first-rain-123/locations/global/keyRings/mykeyring \ --storepass <api-access-token> \ --alias test/cryptoKeyVersions/1 \ --certfile full-chain.pem application.exe
The version of the key can be omitted (e.g. --alias test
), in this case the most recent version
of the key is picked automatically. This avoids modifying the parameters every time the key is updated, but the signing
process is slightly slower due to an additional API call, and it requires an extra permission.
The access token is typically provided by the gcloud tool:
gcloud auth print-access-token
When creating the key the purpose must be set to "Asymmetric sign", and the algorithm must be either Elliptic Curve or RSA with PKCS#1 v1.5 padding and SHA digest. Keys with PSS padding or raw RSA mode are not supported.
The Google Cloud account used must have the following permissions:
cloudkms.cryptoKeyVersions.useToSign
cloudkms.cryptoKeyVersions.list
(required if the version of the key isn't specified)cloudkms.cryptoKeys.list
(required to list the keys available when the alias isn't found)
These permissions are covered by the Cloud KMS CryptoKey Signer and Cloud KMS Viewer roles.
Signing with HashiCorp Vault
HashiCorp Vault exposes keys through secrets engines. Jsign
supports the Google Cloud KMS and
Transit secrets engines. The keystore
parameter references the endpoint of the secrets engine, which is typically the Vault server URL and the API version
v1
followed by the secrets engine path. The certificate must be provided separately using the
certfile
parameter. The alias
parameter specifies the name of the key in Vault. For the
Google Cloud KMS secrets engine, the version of the Google Cloud key is appended to the key name, separated by a colon
character.
jsign --storetype HASHICORPVAULT \ --keystore https://vault.example.com/v1/gcpkms \ --storepass <vault-token> \ --alias test:1 \ --certfile full-chain.pem application.exe
Signing with Keyfactor SignServer
SignServer is an on-premises open source signing service developed by Keyfactor.
SignServer supports various signing operations handled by signer workers. Jsign requires a
Plain Signer
worker configured with the CLIENTSIDEHASHING
or ALLOW_CLIENTSIDEHASHING_OVERRIDE
properties
set to true
, and the SIGNATUREALGORITHM
property set to NONEwithRSA
or
NONEwithECDSA
.
The authentication is performed by specifying the username/password or the TLS client certificate in the
storepass
parameter. If the TLS client certificate is stored in a password protected keystore, the password
is specified in the keypass
parameter. The keystore
parameter references the URL of the
SignServer REST API. The alias
parameter specifies the id or the name of the worker.
Authenticating with a username and a password:
jsign --storetype SIGNSERVER \ --keystore https://example.com/signserver \ --storepass "<username>|<password>" \ --alias test \ application.exe
Authenticating with a TLS client certificate:
jsign --storetype SIGNSERVER \ --keystore https://example.com/signserver \ --storepass "/path/to/client-certificate.p12" \ --keypass <client-certificate-password> \ --alias test \ application.exe
Signing with Oracle Cloud Key Management Service
Signing with the Oracle Cloud Infrastructure Key Management Service requires the
configuration file or the
environment variables
used by the OCI CLI. The OCI CLI isn't required for signing, but it may be used to initialize the configuration file
with oci setup bootstrap
.
The storepass parameter specifies the path to the configuration file (~/.oci/config
by default). If the
configuration file contains multiple profiles, the name of the non-default profile to use is appended to the storepass
(for example ~/.oci/config|PROFILE
). The keypass
parameter may be used to specify the
passphrase of the key file used for signing the requests to the OCI API if it isn't set in the configuration file.
The certificate must be provided separately using the certfile
parameter. The alias specifies the OCID
of the key.
The general syntax looks like this:
jsign --storetype ORACLECLOUD \ --storepass "<oci-config-file>|<profile>" \ --keypass <passphrase> \ --alias ocid1.key.oc1.eu-paris-1.abcdefghijklm.abrwiljrwkhgllb5zfqchmvdkmqnzutqeq5pz7 \ --certfile full-chain.pem application.exe
When using the default configuration file and profile, the command is simplified to:
jsign --storetype ORACLECLOUD \ --alias ocid1.key.oc1.eu-paris-1.abcdefghijklm.abrwiljrwkhgllb5zfqchmvdkmqnzutqeq5pz7 \ --certfile full-chain.pem application.exe
The configuration file can be replaced (or overridden) by environment variables. Here are the variables expected:
OCI_CLI_USER
: OCID of the user (e.g.ocid1.user.oc1..<unique_ID>
)OCI_CLI_TENANCY
: The OCID of the tenancy (e.g.ocid1.tenancy.oc1..<unique_ID>
)OCI_CLI_REGION
: The OCI region (e.g.eu-paris-1
)OCI_CLI_KEY_FILE
: The path to the private key signing the API requests in PEM formatOCI_CLI_PASS_PHRASE
: The pass phrase of the private key
Tagging
A signed file can be modified to include additional data without invalidating the signature. This feature is useful for embedding user identification data, such as a licence key or a session token, within a signed installer when the file is downloaded. Upon installation, the installer extracts this data, enabling the application to automatically authenticate the user without requiring credentials.
For example, to tag a signed installer with a licence key:
jsign tag --value userid:1234-ABCD-5678-EFGH installer.exe
For an executable file, the tag can be found next to the timestamp of the signature, in the last few kilobytes of the file.
A common pattern consist in embedding a default template at build time, providing enough space for the data to be inserted when the file is downloaded. This allows a simple search-and-replace operation to be performed on the download server without needing Jsign to be installed. For example:
jsign tag --value "<TEMPLATE>XXXXXXXXXXXXXXXXXXXXXXXXXXX</TEMPLATE>" installer.exe
If the value
parameter is omitted Jsign will insert a default 1KB template filled with zeros, delimited by
-----BEGIN TAG-----
and -----END TAG-----
markers.
API
Jsign also provides a simple API for signing files and can be embedded in another application.
Simply add this dependency to the project:
<dependency> <groupId>net.jsign</groupId> <artifactId>jsign-core</artifactId> <version>6.0</version> </dependency>
and then use the AuthenticodeSigner
class like this:
KeyStore keystore = new KeyStoreBuilder().keystore("keystore.p12").storepass("password").build(); AuthenticodeSigner signer = new AuthenticodeSigner(keystore, "test", "secret"); signer.withProgramName("My Application") .withProgramURL("http://www.example.com") .withTimestamping(true) .withTimestampingAuthority("http://timestamp.sectigo.com"); try (Signable file = Signable.of(new File("application.exe"))) { signer.sign(file); }
See the Javadoc for more details about the API.
JCA security provider
Jsign implements a JCA security provider that can be integrated with other Java based signing tools to extend their range of supported keystores.
JAR signing
The JCA provider can be used to sign JAR files with with the jarsigner
tool.
With Java 11 or later the syntax looks like this:
jarsigner -J-cp -Jjsign-6.0.jar -J--add-modules -Jjava.sql \ -providerClass net.jsign.jca.JsignJcaProvider \ -providerArg <keystore> \ -keystore NONE \ -storetype <storetype> \ -storepass <storepass> \ -keypass <keypass> \ -certchain <certfile> \ application.jar <alias>
With Java 8 the classpath must reference tools.jar
from the JDK and the --add-modules
parameter is removed:
jarsigner -J-cp -Jjsign-6.0.jar:$JAVA_HOME/lib/tools.jar \ ...
The keystore
parameter must be set to NONE
, the actual value of the keystore is specified
with the providerArg
parameter instead.
APK signing
The JCA provider can be used to sign Android applications with the apksigner
tool.
The syntax looks like this:
java -cp apksigner.jar:jsign.jar com.android.apksigner.ApkSignerTool sign \ --provider-class net.jsign.jca.JsignJcaProvider \ --provider-arg <keystore> \ --ks NONE \ --ks-type <storetype> \ --ks-pass pass:<storepass> \ --ks-key-alias <alias> \ --key-pass pass:<keypass> \ --cert <certfile> \ --in application.apk
Credits
Jsign leverages the cryptography API developed by the Bouncy Castle project.
PVK parsing is based on the pvktool by Stephen N Henson.
MSI signing was possible thanks to the work done by the osslsigncode and Apache POI projects.
Jsign includes contributions from Emmanuel Bourg, Florent Daigniere, Michael Szediwy, Michael Peterson, Markus Kilås, Erwin Tratar, Björn Kautler, Joseph Lee, Maria Merkel, Vincent Malmedy, Sebastian Müller, Sebastian Stamm and Eatay Mizrachi.
Contact
Emmanuel Bourg (ebourg@apache.org, @smanux)