PKCS#11 Wrapper – APK Signing Integration Guide

For APK signing, we use APKSigner, which is a command-line utility included in the Android SDK Build Tools that allows you to sign Android application package (APK) files and verify their signatures. It is an essential tool for Android developers to ensure the integrity and authenticity of their apps.

Encryption Consulting’s PKCS#11 Wrapper exposes the keys held in your HSM through the standard PKCS#11 interface, which means APKSigner can use them through Java’s built-in SunPKCS11 provider without any change to the tool itself. The keystore is given as type PKCS11 rather than a local file, so the private key never leaves the HSM and every signing operation is recorded centrally.

Section 1 covers the steps that are common to every platform. After that, follow only the track for your operating system — Sections 2 and 3 for Linux (Ubuntu), Sections 4 and 5 for macOS, or Sections 6 and 7 for Windows. Each track ends with signing and verification.

Prerequisites: Access to the CodeSign Secure portal, administrative rights on the client machine, and a sample APK file to sign.

Common Setup

Two things are needed regardless of platform: a P12 authentication certificate that identifies your machine to CodeSign Secure, and the two configuration files that ship inside the PKCS#11 Wrapper download.

Step 1: Generate a P12 Authentication Certificate

Generate a P12 Authentication certificate from the System Setup > User > Generate Authentication Certificate dropdown in the CodeSign Secure portal.

Enter the certificate name, user name, and expiry date. A .pfx certificate is generated and downloaded, and its password is displayed.

NOTE: The password is displayed only once, so copy and store it safely. Both the certificate path and its password are referenced by the wrapper configuration in your platform track.

CodeSign Secure dialog showing the generated .pfx authentication certificate and password

Step 2: Understand the Two Configuration Files

The PKCS#11 Wrapper download contains two files that must be edited before use:

  • ec_pkcs11client.ini: Points the wrapper at your CodeSign Secure server and at the P12 authentication certificate generated in Step 1.
  • pkcs11properties.cfg: The SunPKCS11 provider configuration that Java reads. Its path is supplied to APKSigner through the --provider-arg option.

NOTE: When using a Luna HSM, the slot number must also be added to the pkcs11properties.cfg file. Each platform track below shows this variation.

Linux (Ubuntu): Set Up the Wrapper

To sign your APK using APKSigner and our PKCS#11 wrapper in Ubuntu, please follow the below steps.

Step 1: Download the PKCS#11 Wrapper for Ubuntu

Go to EC CodeSign Secure v3.02’s Signing Tools section and download the PKCS11 Wrapper for Ubuntu.

CodeSign Secure Signing Tools section showing the PKCS11 Wrapper for Ubuntu download

Step 2: Edit the Configuration Files

Go to your Ubuntu client system and edit the configuration files (ec_pkcs11client.ini and pkcs11properties.cfg) downloaded in the PKCS11 Wrapper.

ec_pkcs11client.ini and pkcs11properties.cfg files opened for editing on Ubuntu

NOTE: When using Luna HSM, add the slot number in the pkcs11properties.cfg file as shown below.

pkcs11properties.cfg file showing the Luna HSM slot number entry

Step 3: Set the EC_INI_FILE_PATH Environment Variable

Now we need to add the environment variable for the pkcs11 client library.

Run the below command to open the bashrc file:

nano ~/.bashrc
Terminal showing the .bashrc file opened in nano

Now add the EC_INI_FILE_PATH variable with the path of the .ini at the end of the bashrc file, like:

export EC_INI_FILE_PATH=\
/home/administrator/PKCS11_Wrapper-Ubuntu/ec_pkcs11client.ini
bashrc file showing the EC_INI_FILE_PATH variable added

Press Ctrl+X, then enter Y, and then press Enter to save.

Reload the environment variables:

source ~/.bashrc
Terminal output after sourcing the .bashrc file

Check whether the variable has been set correctly:

echo $EC_INI_FILE_PATH
Terminal output showing the EC_INI_FILE_PATH variable value

NOTE: If you cannot see the file location from the echo command, open a new terminal and try again.

Step 4: Install the Prerequisites

Now, let us install some prerequisites in your client system to run the PKCS11 Wrapper.

Install Java 8:

sudo apt install openjdk-8-jdk
Terminal output showing Java 8 being installed

Set Java 8 as the active version:

sudo update-alternatives --config java
Terminal output showing the update-alternatives prompt for selecting the active Java version

Install the Android SDK command-line tools:

sudo apt install google-android-cmdline-tools-13.0-installer
Terminal output showing the Android SDK command-line tools being installed

Ensure that the SDK Manager for Android Studio has been properly installed:

sdkmanager --version
Terminal output showing the sdkmanager version

Install Build tools using SDKManager, which contains the APKSigner:

sdkmanager "build-tools;34.0.0"
Terminal output showing the Android build tools being installed

Ensure that APKSigner is present:

apksigner --version
Terminal output showing the apksigner version

Two packages are required to run the PKCS11 Wrapper on your system. First, install liblog4cxx-dev:

sudo apt-get install liblog4cxx-dev
Terminal output showing liblog4cxx-dev being installed

The last prerequisite is to install the curl package:

sudo apt-get install curl
Terminal output showing curl being installed

Linux (Ubuntu): Sign and Verify

Now that all the configurations and prerequisites have been installed, let us perform the signing operation.

Step 1: Run the Signing Command

The signing command will look something like this. Ensure you run this command only inside the folder where your PKCS11 Wrapper is installed.

apksigner sign \
  --provider-class sun.security.pkcs11.SunPKCS11 \
  --provider-arg <path of the pkcs11properties.cfg file> \
  --ks NONE \
  --ks-type PKCS11 \
  --ks-pass pass:abcd1234 \
  --ks-key-alias <private key alias> \
  --in <path of the APK file you want to sign> \
  --out <path of the Signed APK file>

A sample command is provided below:

apksigner sign \
  --provider-class sun.security.pkcs11.SunPKCS11 \
  --provider-arg \
    /home/administrator/PKCS11_Wrapper-Ubuntu/pkcs11properties.cfg \
  --ks NONE --ks-type PKCS11 --ks-pass pass:abcd1234 \
  --ks-key-alias gpg2 --in Sample.apk --out signed.apk
Terminal showing the apksigner sign command being run on Ubuntu

NOTE: When working with Luna HSM, append --min-sdk-version 28 to the signing command shown above.

Step 2: Option Reference

The following are the options and their meaning in the command:

Option Description
--provider-class The Java security provider to use. This is always sun.security.pkcs11.SunPKCS11, the JDK’s built-in PKCS#11 provider.
--provider-arg The path to the pkcs11properties.cfg file in your system, which tells the provider how to reach the PKCS#11 Wrapper.
--ks The keystore. This is NONE because the keys live in the HSM rather than in a keystore file.
--ks-type The keystore type, which must be PKCS11.
--ks-pass The keystore password, supplied in the form pass:<password>.
--ks-key-alias The alias of the private key to sign with.
--in The path of the APK file you want to sign.
--out The path of the signed APK file to produce.
--min-sdk-version The lowest Android API level the signature must be valid for. Required when working with a Luna HSM.

Step 3: Verify the Signature

After successfully signing the APK, let us verify it using this command:

apksigner verify -verbose <path of the signed APK file>

A sample command is provided below:

apksigner verify -verbose signed.apk
Terminal output showing apksigner verify confirming a valid signature on Ubuntu

NOTE: When working with Luna HSM, use: apksigner verify -verbose --min-sdk-version 28 <path of the signed APK file>

Step 4: Cross-Check in CodeSign Secure

Open the CodeSign Secure portal and navigate to Reports > Signing Request Report, where every signing request performed through the wrapper is recorded for audit purposes.

macOS: Set Up the Wrapper

To perform APK Signing using the APKSigner tool and our PKCS11 Wrapper on a macOS machine, you would need to follow the below steps.

Step 1: Download the PKCS#11 Wrapper for macOS

Go to EC CodeSign Secure v3.02’s Signing Tools section and download the PKCS11 Wrapper for MacOS.

CodeSign Secure Signing Tools section showing the PKCS11 Wrapper for macOS download

Step 2: Edit the Configuration Files

Go to your macOS client system and edit the configuration files (ec_pkcs11client.ini and pkcs11properties.cfg) downloaded in the PKCS11 Wrapper.

ec_pkcs11client.ini and pkcs11properties.cfg files opened for editing on macOS

NOTE: When using Luna HSM, add the slot number in the pkcs11properties.cfg file as shown below.

pkcs11properties.cfg file showing the Luna HSM slot number entry on macOS

Step 3: Install and Activate Java 17

Install Java 17:

brew install openjdk@17
Terminal output showing Java 17 being installed via Homebrew

Set Java 17 as the active version. For Zsh:

nano ~/.zshrc
Terminal showing the .zshrc file opened in nano

For Bash:

nano ~/.bash_profile
Terminal showing the .bash_profile file opened in nano

Add these lines:

export JAVA_HOME=$(/usr/libexec/java_home -v 17)
export PATH=$JAVA_HOME/bin:$PATH

And then run one of the following, matching your shell:

source ~/.zshrc
source ~/.bash_profile

Step 4: Install the Android SDK Command-Line Tools

Install the Android SDK command-line tools from this site.

Android developer site showing the command-line tools download
Extracted Android SDK command-line tools folder on macOS

Ensure that the SDK Manager for Android Studio has been properly installed:

sdkmanager --sdk_root=/Users/subhayuroy/PKCS11_Wrapper-Mac \
  --version
Terminal output showing the sdkmanager version on macOS

Install Build tools using SDKManager, which contains the APKSigner:

sdkmanager --sdk_root=/Users/subhayuroy/PKCS11_Wrapper-Mac \
  "build-tools;34.0.0"
Terminal output showing the Android build tools being installed on macOS

Ensure that APKSigner is present:

ls /Users/subhayuroy/PKCS11_Wrapper-Mac/build-tools/34.0.0/\
apksigner
Terminal output confirming apksigner is present in the build-tools directory

Step 5: Install the Remaining Packages

Two packages are required to run the PKCS11 Wrapper on your system. First, install the log4cxx library:

brew install log4cxx
Terminal output showing log4cxx being installed via Homebrew

The last prerequisite is to install the curl package:

brew install curl
Terminal output showing curl being installed via Homebrew

Step 6: Add the Relative Paths to Your PATH

You need to ensure all the relative paths are added to your PATH variable in the ~/.zshrc file:

export PATH=/Users/subhayuroy/PKCS11_Wrapper-Mac/cmdline-tools/\
bin:$PATH
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
export PATH=$JAVA_HOME/bin:$PATH
export ANDROID_SDK_ROOT=/Users/subhayuroy/PKCS11_Wrapper-Mac
export PATH=$PATH:/Users/subhayuroy/PKCS11_Wrapper-Mac/\
build-tools/34.0.0
.zshrc file showing the PATH, JAVA_HOME, and ANDROID_SDK_ROOT exports

macOS: Sign and Verify

Now that all the configurations and prerequisites have been installed, let us perform the signing operation. On macOS the signing command invokes the APKSigner jar through java directly, so that the PKCS#11 module can be exported to the tool.

Step 1: Run the Signing Command

The signing command will look something like this. Ensure you run this command only inside the folder where your PKCS11 Wrapper is installed.

java \
  --add-exports=jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \
  -jar <path of the apksigner.jar in your system> sign \
  --provider-class sun.security.pkcs11.SunPKCS11 \
  --provider-arg <path of the pkcs11properties.cfg file> \
  --ks NONE \
  --ks-type PKCS11 \
  --ks-pass pass:abcd1234 \
  --ks-key-alias <private key alias> \
  --in <path of the APK file you want to sign> \
  --out <path of the Signed APK file>

A sample command is provided below:

java \
  --add-exports=jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \
  -jar /Users/subhayuroy/PKCS11_Wrapper-Mac/build-tools/34.0.0/\
lib/apksigner.jar \
  sign \
  --provider-class sun.security.pkcs11.SunPKCS11 \
  --provider-arg \
    /Users/subhayuroy/PKCS11_Wrapper-Mac/pkcs11properties.cfg \
  --ks NONE \
  --ks-type PKCS11 \
  --ks-pass pass:abcd1234 \
  --ks-key-alias gpg2 \
  --in Sample.apk \
  --out signed.apk
Terminal showing the java-invoked apksigner sign command being run on macOS

NOTE: The --add-exports option is required because the JDK used here keeps the SunPKCS11 classes in an encapsulated module. The Linux track does not need it because it runs on Java 8, which predates the module system.

Step 2: Verify the Signature

After successfully signing the APK, let us verify it using this command:

apksigner verify -verbose <path of the signed APK file>

A sample command is provided below:

apksigner verify -verbose signed.apk
Terminal output showing apksigner verify confirming a valid signature on macOS

Step 3: Cross-Check in CodeSign Secure

Open the CodeSign Secure portal and navigate to Reports > Signing Request Report, where every signing request performed through the wrapper is recorded for audit purposes.

Windows: Set Up the Wrapper

To perform APK Signing using the APKSigner tool and our PKCS11 Wrapper on a Windows machine, you would need to follow the below steps.

Step 1: Download the PKCS#11 Wrapper for Windows

Go to EC CodeSign Secure v3.02’s Signing Tools section and download the PKCS11 Wrapper for Windows.

CodeSign Secure Signing Tools section showing the PKCS11 Wrapper for Windows download

Step 2: Edit the Configuration Files

Go to your Windows client system and edit the configuration files (ec_pkcs11client.ini and pkcs11properties.cfg) downloaded in the PKCS11 Wrapper.

ec_pkcs11client.ini file opened for editing on Windows
pkcs11properties.cfg file opened for editing on Windows
Both configuration files edited and saved on Windows

NOTE: When using Luna HSM, add the slot number in the pkcs11properties.cfg file as shown below.

pkcs11properties.cfg file showing the Luna HSM slot number entry on Windows

Step 3: Install and Activate Java 22

Install Java 22 from Oracle’s official site, and follow the instructions in the msi file.

Java 22 installer welcome screen on Windows
Java 22 installer progress screen on Windows
Java 22 installer completion screen on Windows

Set Java 22 as the active version by storing the bin path in the PATH variable.

Windows Environment Variables dialog showing the Java 22 bin path added to PATH

Step 4: Install the Android SDK Command-Line Tools

Install the Android SDK command-line tools from this link here.

Android developer site showing the command-line tools download

Extract the files into a “cmdline-tools” folder and create a subfolder named latest. Now, move the bin and lib folders into the latest folder.

File Explorer showing the cmdline-tools folder structure with the latest subfolder

Set an environment variable called ANDROID_HOME and set it to the path where you extracted the command line tools.

Windows Environment Variables dialog showing the ANDROID_HOME variable

Install Build tools using SDKManager, which contains the APKSigner:

.\bin\sdkmanager --channel=0 --install "build-tools;34.0.0"
Command Prompt output showing the Android build tools being installed on Windows

Ensure that APKSigner is present:

Apksigner.bat --version
Command Prompt output showing the Apksigner.bat version on Windows

Step 5: Patch Apksigner.bat for the PKCS#11 Module

Open the Apksigner.bat file and note its current last line.

Apksigner.bat file showing the original last line before editing

Update the last line to the below command:

call "%java_exe%" --add-exports ^
  jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED ^
  %javaOpts% -jar "%jarpath%" %params%
Apksigner.bat file showing the updated last line after editing

NOTE: This is a single logical line in the batch file. The caret characters shown above are batch line continuations, so you may either keep them or join the three lines into one.

NOTE: This edit performs the same job as the --add-exports option used in the macOS command, so the Windows signing command itself stays short.

Windows: Sign and Verify

Now that all the configurations and prerequisites have been installed, let us perform the signing operation.

Step 1: Run the Signing Command

The signing command will look something like this. Ensure you run this command only inside the folder where your PKCS11 Wrapper is installed.

apksigner sign ^
  --provider-class sun.security.pkcs11.SunPKCS11 ^
  --provider-arg <path of the pkcs11properties.cfg file> ^
  --ks NONE ^
  --ks-type PKCS11 ^
  --ks-pass pass:abcd1234 ^
  --ks-key-alias <private key alias> ^
  --in <path of the APK file you want to sign> ^
  --out <path of the Signed APK file>

A sample command is provided below:

apksigner sign ^
  --provider-class sun.security.pkcs11.SunPKCS11 ^
  --provider-arg ^
    C:\Users\riley\Downloads\PKCS11_Wrapper-Windows\pkcs11properties.cfg ^
  --ks NONE --ks-type PKCS11 --ks-pass pass:secretpassword ^
  --ks-key-alias gpg2 --in Sample.apk --out signed.apk

NOTE: The caret characters are Command Prompt line continuations. You may keep them or join the command onto a single line.

Command Prompt showing the apksigner sign command being run on Windows

NOTE: The --ks-pass value must match the password configured for your wrapper. The sample above uses a different value from the Linux and macOS samples, so use whichever applies to your own configuration.

Step 2: Verify the Signature

After successfully signing the APK, let us verify it using this command:

apksigner verify -verbose <path of the signed APK file>

A sample command is provided below:

apksigner verify -verbose signed.apk
Command Prompt output showing apksigner verify confirming a valid signature on Windows

Step 3: Cross-Check in CodeSign Secure

Open the CodeSign Secure portal and navigate to Reports > Signing Request Report, where every signing request performed through the wrapper is recorded for audit purposes.