osslsigncode
BUILD STATUS

WHAT IS IT?
osslsigncode is a small tool that implements part of the functionality
of the Microsoft tool signtool.exe - more exactly the Authenticode
signing and timestamping. But osslsigncode is based on OpenSSL and cURL,
and thus should be able to compile on most platforms where these exist.
WHY?
Why not use signtool.exe? Because I don't want to go to a Windows
machine every time I need to sign a binary - I can compile and build
the binaries using Wine on my Linux machine, but I can't sign them
since the signtool.exe makes good use of the CryptoAPI in Windows, and
these APIs aren't (yet?) fully implemented in Wine, so the signtool.exe
tool would fail. And, so, osslsigncode was born.
WHAT CAN IT DO?
It can sign and timestamp PE (EXE/SYS/DLL/etc), CAB, CAT, MSI and APPX files,
as well as script files with extensions .ps1, .ps1xml, .psc1, .psd1,
.psm1, .cdxml, .mof, and .js.
It supports the equivalent of signtool.exe's "-j javasign.dll -jp low",
i.e. add a valid signature for a CAB file containing Java files.
It supports getting the timestamp through a proxy as well. It also
supports signature verification, removal and extraction.
BUILDING
This section covers building osslsigncode for Unix-like operating systems.
See INSTALL.W32.md for Windows notes.
We highly recommend downloading a release tarball instead of cloning from a git repository.
Configure, build, make tests and install osslsigncode
- Install prerequisites on a Debian-based distributions, such as Ubuntu:
sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev zlib1g-dev python3
- Install prerequisites on macOS with Homebrew:
brew install cmake pkg-config openssl@1.1
export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"
NOTE: osslsigncode requires CMake 3.17 or newer.
You may need to use cmake3 instead of cmake to complete the following steps on your system.
- Navigate to the build directory and run CMake to configure the osslsigncode project
and generate a native build system:
mkdir build && cd build && cmake -S ..
optional CMake parameters:
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_C_COMPILER=clang
-DCMAKE_PREFIX_PATH=[openssl directory];[curl directory]
-DCMAKE_INSTALL_PREFIX=[installation directory]
-DBASH_COMPLETION_USER_DIR=[bash completion installation directory]
- Then call that build system to actually compile/link the osslsigncode project (alias
make):
cmake --build .
ctest -C Release
sudo cmake --install .
- Make tarball (simulate autotools'
make dist):
cmake --build . --target package_source
USAGE
Before you can sign a file you need a Software Publishing
Certificate (spc) and a corresponding private key.
This article provides a good starting point as to how
to do the signing with the Microsoft signtool.exe:
http://www.matthew-jones.com/articles/codesigning.html
To sign with osslsigncode you need the certificate file mentioned in the
article above, in SPC or PEM format, and you will also need the private
key which must be a key file in DER or PEM format, or if osslsigncode was
compiled against OpenSSL 1.0.0 or later, in PVK format.
To sign a PE or MSI file you can now do:
osslsigncode sign -certs -key \
-n "Your Application" -i http://www.yourwebsite.com/ \
-in yourapp.exe -out yourapp-signed.exe
or if you are using a PEM or PVK key file with a password together
with a PEM certificate:
osslsigncode sign -certs \
-key -pass \
-n "Your Application" -i http://www.yourwebsite.com/ \
-in yourapp.exe -out yourapp-signed.exe
or if you want to add a timestamp as well:
osslsigncode sign -certs -key \
-n "Your Application" -i http://www.yourwebsite.com/ \
-t http://timestamp.digicert.com \
-in yourapp.exe -out yourapp-signed.exe
You can use a certificate and key stored in a PKCS#12 container:
osslsigncode sign -pkcs12 -pass \
-n "Your Application" -i http://www.yourwebsite.com/ \
-in yourapp.exe -out yourapp-signed.exe
To sign a CAB file containing Java class files:
osslsigncode sign -certs -key \
-n "Your Application" -i http://www.yourwebsite.com/ \
-jp low \
-in yourapp.cab -out yourapp-signed.cab
Only the 'low' parameter is currently supported.
Using the PKCS#11 Engine with osslsigncode
If you want to use a PKCS#11 token, specify the PKCS#11 engine and module.
Example usage with SoftHSM:
osslsigncode sign \
-engine /usr/lib64/engines-1.1/pkcs11.so \
-pkcs11module /usr/lib64/pkcs11/libsofthsm2.so \
-pkcs11cert 'pkcs11:token=softhsm-token;object=cert' \
-key 'pkcs11:token=softhsm-token;object=key' \
-in yourapp.exe -out yourapp-signed.exe
Using the PKCS#11 Provider with osslsigncode (OpenSSL 3.x only)
OpenSSL 3.0 introduced a new provider-based architecture. To use a PKCS#11 token
with osslsigncode, specify the PKCS#11 provider and module.
Example usage with OpenSC:
osslsigncode sign \
-provider /usr/lib64/ossl-modules/pkcs11prov.so \
-pkcs11module /usr/lib64/opensc-pkcs11.so \
-pkcs11cert 'pkcs11:token=my-token;object=cert' \
-key 'pkcs11:token=my-token;object=key' \
-in yourapp.exe -out yourapp-signed.exe
Using a cloud PKCS#11 module with osslsigncode
Some code signing services keep the private key in their own HSM and publish a
PKCS#11 module that talks to it over the network, so there is no token to plug
in and no vendor desktop application to run. osslsigncode drives such a module
exactly like a local token, which makes headless signing on Linux and in CI
possible.
ssign-pkcs11 is one example. It is an
independent, third-party project, not affiliated with or endorsed by
osslsigncode, and it exposes a Certum SimplySign cloud certificate as a
PKCS#11 module.
The engine and provider options are the same as for a local token. With the
PKCS#11 provider (OpenSSL 3.x only):
export CERTUM_EMAIL=you@example.com CERTUM_OTP=
osslsigncode sign \
-provider /usr/lib64/ossl-modules/pkcs11prov.so \
-pkcs11module ./libssign_pkcs11.so \
-pkcs11cert 'pkcs11:type=cert' \
-key 'pkcs11:type=private' \
-ac certum-code-signing-2021-ca.pem \
-h sha256 -t http://time.certum.pl/ \
-in yourapp.exe -out yourapp-signed.exe
or with the PKCS#11 engine:
osslsigncode sign \
-engine /usr/lib64/engines-1.1/pkcs11.so \
-pkcs11module ./libssign_pkcs11.so \
-pkcs11cert 'pkcs11:type=cert' \
-key 'pkcs11:type=private' \
-ac certum-code-signing-2021-ca.pem \
-h sha256 -t http://time.certum.pl/ \
-in yourapp.exe -out yourapp-signed.exe
Either option may be omitted, in which case osslsigncode loads the
pkcs11prov provider if it is available and otherwise falls back to the libp11
pkcs11 engine.
This module holds one certificate and one key, so the pkcs11: URIs only have
to select by object type; a module backed by a token with several objects still
needs the usual token= and object= attributes. The credentials are read from
the environment by the module itself, never passed on the osslsigncode command
line. -ac adds the issuing CA certificate, obtained from the service, so the
signed chain verifies.
Using the CNG Engine with osslsigncode (Windows only)
The CNG engine allows using certificates and keys stored in the Windows
Certificate Store. It requires CNG engine version 1.1 or later. For more
information, refer to
https://www.stunnel.org/cng-engine.html
A non-commercial edition of CNG engine is available for testing, personal,
educational, or research purposes.
To ensure osslsigncode can locate and load the CNG engine module (cng.dll)
even when it is not installed in the default system engine directory, you can:
- Specify the full or relative path to
cng.dll:
osslsigncode sign -engine C:\my\engines\cng.dll ...
- Or set the
OPENSSL_ENGINES environment variable to the directory containing
cng.dll, and refer to the engine by its ID:
set OPENSSL_ENGINES=C:\my\engines
osslsigncode sign -engine cng ...
Below is an example of how to use osslsigncode with the CNG engine on Windows:
set OPENSSL_ENGINES=C:\my\engines
osslsigncode sign ^
-engine cng ^
-pkcs11cert osslsigncode_cert ^
-key osslsigncode_cert ^
-engineCtrl store_flags:0 ^
-engineCtrl store_name:MY ^
-engineCtrl PIN:yourpass ^
-in yourapp.exe -out yourapp-signed.exe
You can check that the signed file is correct by right-clicking
on it in Windows and choose Properties --> Digital Signatures,
and then choose the signature from the list, and click on
Details. You should then be presented with a dialog that says
amongst other things that "This digital signature is OK".
UNAUTHENTICATED BLOBS
The "-addUnauthenticatedBlob" parameter adds a 1024-byte unauthenticated blob
of data to the signature in the same area as the timestamp. This can be used
while signing, while timestamping, after a file has been code signed, or by
itself. This technique (but not this project) is used by Dropbox, GoToMeeting,
and Summit Route.
Example 1. Sign and add blob to unsigned file
osslsigncode sign -addUnauthenticatedBlob -pkcs12 yourcert.pfx -pass your_password -n "Your Company" -i https://YourSite.com/ -in srepp.msi -out srepp_added.msi
Example 2. Timestamp and add blob to signed file
osslsigncode.exe add -addUnauthenticatedBlob -t http://timestamp.digicert.com -in your_signed_file.exe -out out.exe
Example 3. Add blob to signed and time-stamped file
osslsigncode.exe add -addUnauthenticatedBlob -in your_signed_file.exe -out out.exe
WARNING
This feature allows for doing dumb things. Be very careful with what you put
in the unauthenticated blob, as an attacker could modify this. Do NOT, under
any circumstances, put a URL here that you will use to download an additional
file. If you do that, you would need to check the newly downloaded file is
code signed AND that it has been signed with your cert AND that it is the
version you expect.
BUGS, QUESTIONS etc.
Check whether your question or suspected bug was already
discussed on https://github.com/mtrojnar/osslsigncode/issues.
Otherwise, open a new issue.
BUT, if you have questions related to generating spc files,
converting between different formats and so on, please
spend a few minutes searching on google for your particular
problem since many people probably already have had your
problem and solved it as well.