Code Signing for Authenticode, Java and Netscape
JavaScience Consulting April 05, 2007
Digital code-signing, based on industry standard PKI technology standards, is a powerful approach for
secure distribution of software over the Internet with authentication and integrity verification capability.
This technology also facilitates more
powerful web-based client-side applications which rely on the end user making a trust decision in the
downloaded software, particularly for signed Java applets, installable ActiveX controls etc... However, the situation
for developers is complicated by various approaches, tools and implementations of code-authentication
verification, the main approaches being Microsoft Authenticode (based on cryptoAPI win32technology),
Netscape based "object signing" and Sun Java code signing. Each of these vendors offer different
tools and technologies, with generally incompatible "keystore" implementation technologies for key/certificate storage,
even though code signed with each technology involves some elements that are based on public PKI
standards (e.g. pkcs#7 signature blocks, X509v3 certificates etc..).
This document describes how a *single* code signing certificate can be used with the
three vendor technologies and tools to sign code targeting Microsoft Authenticode (signed cabs, exe, dll, ocs etc..), Netscape
(signed applets in JARs) and Sun (signed JARs for JavaPlugin, Netscape etc..).
Only one particular type of commercial certificate has been tested for this "3-ply" capability.
Demo of applet signed 3 ways
The
Thawte Microsoft Authenticode - (Multi-Purpose Certificate) has been tested for compatibility, using
the procedure detailed below. See the official Thawte site for
official documentation.
The information is being provided to developers who must sign code
targeting an audience using several vendor technologies. The results below have been verified on only one platform:
- Win2000 Pro SP2
- IE 5+, Netscape 4.76, J2SE 1.3.1
The Authenticode Process
[Note:
The Thawte certificate registration process for IE (Authenticode) currently generates ONLY 512 bit RSA long key, which
is generally viewed as inadequate from a security perspective. This problem arises from inadequate implementation of the Microsoft
"Enrollment Control" (an ActiveX Control) used by the web-page for key generation/registration. The process for Netscape and Java key
registration however generates larger RSA keys. ]
- Apply for the Thawte Authenticode (Multi-purpose Certificate) Developer code-signing certificate at the Thawte web site.
Use Internet Explorer 5+ during the process and follow the
installation instructions
VERY carefully. In particular, specify a file path when asked for a location to store your automatically-generated
private key, otherwise it will be stored in the win32 registry automatically. This will allow greater flexibility for code signing
with Authenticode and provides a better understand of the Authenticode processes.
- When your issued certificate has been approved, download the public certificate component from the Thawte site, as instructed
by email sent to you. Keep the public and private key files (typically in .pvk and .spc file types) in a safe place.
Back-up these key-sets several times and store in different physical locations.
- Use the Microsoft pvkimprt.exe utility to now import
the public and private key into the win32 registry. This provides greater convenience for code-signing with Microsoft
Authenticode, and will make the public and private key available for "export" out of the Authenticode world.
[Alternatively,it is possible to directly use the .spc and .pvk cert/key files to generate the pkcs12 file as described in
the pvkimprt documentation].
Generating a standard pkcs12 protected key/cert container file is a required step for moving your public/private key
information to Netscape and Sun environments.
Note that you must install and run pvkimprt.exe with administrator privileges on Win2000+. To use the
code-signing certificate with Authenticode technology, obtain the
Authenticode 5 Tools which are
designed to work with components installed with Internet Explorer 5+. Similar tools of similar version are also distributed with the
Microsoft Platform SDK in its bin directory.
If you wish to sign Java code, you must also install the
Microsoft SDK for Java, Version 4.0 (the final version
available).
- Once the Authenticode tools are installed, you can sign code (exe, dll, ocx, cat, vbs etc..) using either your two key files:
signcode -spc mycert.spc -v mykey.pvk -t http://timestamp.verisign.com/scripts/timstamp.dll myapp.exe
or you can use the "Common Name" of your public certificate to access the same key information in the win32 registry:
signcode -cn "Your Common Name" -t http://time.certum.pl myapp.exe
where both examples include the -t option to "timestamp" the signature.
- To sign java code for IE deployment, you would typically compile, archive (into a .cab file) and then sign the code as follows:
jvc MyJavaApplet.java
cabarc -p n myarchive.cab *.class
signcode -j javasign.dll -jp LOW -cn "Your Common Name" -n "About my Applet" -t http://time.certum.pl myarchive.cab
[Update note: In the Feb. 2003 PSDK release, the Signcode.exe signing tool has been replaced with
Signtool.exe
which provides similar levels of Authenticode signing support with more robust signature verification capabilities.]
[Note on Timestamp support:
Currently VeriSign and
Certum both offer
free Internet timestamp services based on IETF
RFC 3161 protocol and compatible with
Microsoft Authenticode request format.]
Porting To Netscape Environment
- To make the keys/certificate available for use with Netscape "object signing" technology, you simply export you public and
private keys together in one step using Internet Explorer menu selection:
Tools | Internet Options | Content | Certificates | Personal
and select your certificate and EXPORT it. Select the option to include the private key. Select to protect
the resultant .pfx file with the highest security (requiring a password for subsequent importing to any other environment).
When the file is generated (say myIEexport.pfx), you now have a standard "PKCS#12" format password-protected key
container which contains all the encrypted information of your public and private keys and certificate information. Back
this file up several times.
To import the keys/cert into Netscape, use the menu selection (Netscape 4.76):
Communicator | Tools | Security Info | Yours
and click "Import a Certificate". This will access the Netscape keystore files, and if this is the first time, you will
be required to enter a password to protect THAT keystore (and will be asked to re-enter it). Then you will be
asked for a file to import. Browse to select myIEexport.pfx, enter the password protecting that file and the
import should succeed. Unfortunately, this process assigns a cryptic nick-name to the certificate in Netscape, the
name you will use in the signtool command line below.
To use the Netscape environment to sign code (for Netscape deployment, or to sign code for JavaPlugin deployment),
obtain the netscape
signtool1.3 tool.
Follow the Netscape documentation to use your Netscape cert and key
files (key3.db and cert7.db) with signtool.exe. A typical signing command, which combines JAR archiving and signing
in one step is:
signtool -k "b1345-somecryptic-l432537" -d cacertdb -Z mynew.jar signingdir
Porting To Sun Java Environment
- To also make the keys/certificate available for use with Sun's Java code-signing technology, the keys/cert must now be
contained in a PKCS#12 container which can be properly recognized by your Sun j2se environment. Unfortunately earlier
versions of j2se (versions <= 1.3.1) ONLY recognize PKCS#12 files exported by Netscape and NOT those exported by
Internet Explorer. At the present time, j2se v 1.4 b3 does recognize IE-exported PKCS#12 files (including keytool.exe and
the jsse api included with j2se v1.4 b3). Thus, for j2se v1.4 b3+, simply use the myIEexport.pfx file exported above from IE directly with
the keytool and jarsigner as a PKCS#12 keystore.
For j2se v1.3.x, Netscape must be used to generate a PKCS#12 file recognized by keytool, jarsigner :
From Netscape using the menu selection (Netsape 4.76):
Communicator | Tools | Security Info | Yours
and click "Export". You are required to enter the Netscape Database keystore password, and then you must choose a password (and re-enter
for verification) to protect the exported file, say mynnexport.p12. This file is again a PKCS#12 format key container which
will be recognized directly by the Sun j2se tool keytool.exe as a keystore file of type pkcs12.
-
To use Sun tools with either j2se v1.3.x and the exported mynnexport.p12, or
j2se v1.4 b3+ and the exported myIEexport.pfx, the keytool.exe and jarsigner.exe utilities need support for the pkcs12 keystore provider.
This is currently available in at least three different configurations:
(j2se v1.3 + jsse 1.0.2), (j2se v1.3 +j2ee v1.3), or j2se v1.4+
where j2se == "Java 2 Standard Edition"
, jsse == Java Secure Socket Extension
, j2ee == Java 2 Enterprise Edition
For the illustrative example below, j2se v1.3.1 was used and the j2ee v1.3
archive "j2ee.jar" was added into the j2se v1.3 ext (extensions) directory and the java.security file
was updated with the new pkcs12 provider information as discussed in the jsse 1.0.2 install instructions.
[Note: this step is not required if using j2se v1.4+].
Note that both the j2sdk and j2re environments (ext directory modification and java.security file modification)
must be changed since the tools like keytool and jarsigner use j2sdk paths like:
C:\jdk1.3.1\jre\lib\ext
whereas deployed examples (say with JavaPlugin etc..) use j2re paths like:
C:\Program Files\JavaSoft\JRE\1.3.1\lib\ext
-
To verify that your configuration is correct, ensure that you can read the Netscape-exported keystore file:
keytool -list -storetype pkcs12 -keystore mynnexport.p12
which should show a single entry in this pkcs12 keystore file.
- Now compile some code, JAR it, sign the JAR, and verify the signature using the Sun j2se tools:
javac mycode.java
jar -cf mycode.jar mycode.class
jarsigner -storetype pkcs12 -keystore mynnexport.p12 mycode.jar "b1345-somecryptic-l432537"
jarsigner -verbose -verify -certs mycode.jar
[Note on Timestamping for Java and JAR files: J2SE 5.0 offers
support for timestamping
signed JAR contents, but the
timestamp is only recognized on J2SE V 1.5+. Typical signing and verification with timestamping commands are:
jarsigner -storetype pkcs12 -keystore mynnexport.p12 -tsa "http://time.certum.pl" mycode.jar myalias
jarsigner -verbose -verify -certs mycode.jar ]
Alternate Procedure (advanced)
It is also possible to directly import the public/private key from the Netscape-exported pkcs12 file (for j2se v1.3.x) or from
the IE-exported pkcs12 file (for j2se v1.4 b3+) into a
j2se JKS type keystore and to rename the alias to a more meaningful name than that imposed by IE/Netscape.
Again, the jsse support for pkcs12 keystore provider is required as described above.
The java.security.KeyStore class methods
(load, getInstance, aliases, setCertificateEntry, setKeyEntry etc..) can
be used in a simple Java application to transfer the keys from a pkcs12 file
to an existing JKS keystore thus conveniently consolidating all code-signing keys for j2se code-signing within one keystore.
A
KeystoreMove.java simple code sample
is available based on a Java Developer Connection code snippet.
This utility provides a prompt during the key-copy operation, to change the key alias from the source keystore to something more meaningful
in the destination keystore.
An alternate way of changing the alias name is available using the keytool -keyclone ... option (which simply
duplicates the private key and certificate chain in the Sun keystore):
keytool -keyclone -alias "b1345-somecryptic-l432537" -dest "thawtemig" -keystore .keystore
3rd Party Solutions:
Currently, at release j2se v1.4 b3, the Sun keystore provider implementation does not include the ability to WRITE
pkcs12 keystores. Thus keys generated with keytool.exe into a JKS type keystore cannot be written out to a pkcs12 keystore file, either
with keytool.exe or using the standard API. However, a freely available (see license)
jce provider implementation which DOES support writing pkcs12
stores is available via Legion of the BouncyCastle. Uwe Guenther has written a Java application utility
BCMain.java which exports a user-specified JKS keystore to a pkcs12 file which can
subsequently be imported into either Microsoft Authenticode or Netscape object-signing key/cert stores essentially completing the "reverse porting"
process, complementing the information presented previously on this page.
To use the "Bouncy Castle Provider" extension, download the relevant JDK 1.x bcprov-jdk1x-112.jar archive and place
it in the following extension directory locations (one for compiler visibility, one for runtime visibility):
${jdk.home}/jre/lib/ext/
${java.home}/jre/lib/ext/
The sample code can be compiled with j2se v1.3.1, but requires jce to execute.
Jce is included with j2se v1.4+ but must be added as an extension to j2se v1.3.x.
Note that the BouncyCastle provider is only being used here to export the keys from JKS to PKCS12 keystores.
The code-signing process using jarsigner.exe and RSA keys is of course
fully supported by j2se v1.3.
The "Bouncy Castle" jse provider has been verified to work with j2se v1.4b3, but j2se v.1.3.1 cannot properly read the exported pkcs12 file.
The advantage of using the Sun keytool.exe for key generation and PKCS10 Certificate Request processing is that
RSA key strengths up to 2048 bits can be generated with the j2se keytool, and the Thawte/Java key registration process correctly
handles this key strength (see note above on current Thawte/Authenticode IE 512 bit generation process limitation).
Further, test (self-signed) certificates
can be generated with keytool.exe and then, after exporting to pkcs12 keystores using this 3rd party jse provider, used with MS Authenticode signcode.exe
or Netscape signtool.exe, as an alternative to using test certificates generated by these vendors.
A simple self-signed example:
j2se v1.3.1 was used to generate a new 2048-bit RSA self-signed certificate:
keytool -genkey -keyalg rsa -keysize 2048 -validity 730 -alias mig -keystore .keystore
This key was exported to a pkcs12 store file mig.p12 using the sample java application BCMain.java above. This pkcs12 file, mig.p12 was imported into
"Personal" Authenticode store (by double-clicking it) . The
Authenticode 5 tool signcode.exe was then used in GUI mode
to sign a simple win32 application sguitartuner.exe (a little guitar tuner utility for Win2000, XP) successfully.
If this application is downloaded using IE4+, then
a security dialog appears prompting the user to Open, Save or Cancel the download. If Open is selected, a Security
Warning dialog appears (screen shop), indicating that the "authenticity of this content cannot
be verified, therefore it cannot be trusted". This is because the code was signed with a self-signed certificate which
is its own root CA, which most end users will not have installed (in a real issued Thawte/Verisign certificate, the certificate and
signature would be trusted since the root CA issuer would already be present in the "Trusted Root Certification Authorities" list. However,
the end user would still be prompted with a choice to trust subsequent code (without any prompting) signed with the same certificate.).
If one of the links in the Security Warning panel is clicked, it allows the end user to view the certificate
contents and potentially import the public certificate included with the signature within the .exe file.
(Note: be extremely cautious about doing this for a ROOT CERTIFICATE).
Download sguitartuner.exe
|
Java SE 6 support for Windows CryptoAPI Stores/Keys
Starting at Java SE 6 (developer version 1.6.0), there is support for accessing native Windows CrypoAPI services such as certificate stores and keys.
-
"The SunMSCAPI provider is layered on top of CAPI and helps Java platform
applications access CAPI cryptographic services using existing Java
technology security and cryptography APIs.
This means that Java platform applications can now use the SunMSCAPI
provider to do the following:
Access private keys and certificates stored in CAPI
Use CAPI's cryptographic algorithm implementations "
(More details).
-
Also of interest is the 2048 bit RSA keysize restriction in previous versions
of Java has now been removed (without requiring the unlimited encryption
policy file replacement) and also support for PKCS 5 V2 algorithm
PBKDF2WithHmacSHA1 has been added: (
Java 6 Enhancements)
The "alias" for the key/cert is chosen as follows:
-
- if there is a "Friendly Name" associated with the matching Windows
certificate to the keypair, that name is used
-
- if no "Friendly Name" field is found ( in IE Certs properties
pane) then the CN name of the Subject Name is used.
For RSA keypairs that are natively password access protected (DPAPI strong
protection) then the native capi/DPAPI dialog for password is properly
invoked when access to the private key is required (e.g. for signing).
-
The standard Java 6 security tools now support the larger RSA keys as well as the capi store hook.
e.g.
keytool -list -v -storetype Windows-MY
(note that you don't specify a keystore or provider here).
JAR archiving and signing with a certificate in the capi MY store, timestamping the JAR, and verifying it:
jar cf myCards.jar cards
jarsigner -storetype Windows-MY -tsa "http://time.certum.pl" myCards.jar MaxSizeRSAalias
jarsigner -verbose -verify -certs myCards.jar
RSA key sizes up to the maximum size supported in Windows (16,384 bits = 2048 bytes) are supported.
Note that the .rsa pkcs#7 component in the jar is a detached signature
covering the manifest and sf file which lists hashes of all JAR'd files.
(note that the VeriSign timestamp service does not seem to support the
timestamp protocol used by jarsigner .. only certum which is 2048 bit timestamp
service).
Sample code for signing using Windows CryptoAPI certificate:
import java.io.*;
import java.util.*;
import java.security.*;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.*;
class javasig {
public static void main(String args[]) {
KeyStore ks = null;
PublicKey pub = null;
PrivateKey priv = null;
String pkcs1file = "pkcs1";
byte[] data = null;
String filename = null;
if (args.length != 1) {
System.out.println("Usage: java javasig ");
return;
}
filename = args[0];
data = getFileData(filename) ;
if (data == null){
System.out.println("Couldn't get filedata for " + filename) ;
return;
}
try{
ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
ks.load(null, null);
String alias = "My CryptAPI store alias"; // either Friendly Name (if present) or CN or certificate
PrivateKey privKey = (PrivateKey) ks.getKey(alias, null);
Certificate cert = ks.getCertificate(alias);
System.out.println("Got private key and cert for alias '" + alias + "'") ;
Provider p = ks.getProvider();
Signature sig = Signature.getInstance("SHA1withRSA", p);
sig.initSign(privKey);
sig.update(data);
byte[] signature = sig.sign();
System.out.println("Generated signature for file '" + filename + "'");
FileOutputStream fos = new FileOutputStream(pkcs1file);
fos.write(signature);
fos.close();
System.out.println("Wrote PKCS#1 signature file '" + pkcs1file + "' (" + signature.length + " bytes)") ;
sig.initVerify(cert);
sig.update(data);
if (sig.verify(signature))
System.out.println("Signature verified!");
}
catch(Exception exc){
System.out.println("Problem with keystore access: " + exc.toString()) ;
return;
}
}
public static byte[] getFileData (String filename)
{
File blobfile = new File(filename) ;
if (!blobfile.exists())
return null;
int blobsize = ((int) blobfile.length());
byte[] blobdata = new byte[blobsize];
try
{
FileInputStream freader = new FileInputStream(blobfile);
freader.read(blobdata, 0, blobsize) ;
freader.close();
return blobdata;
}
catch(IOException ioe)
{
return null;
}
}
}
Java SE 6 Security (general)
JDK Tools and Utilities for detailed
information on javac, jar, and jarsigner.
JSSE Reference Guide for
information on pkcs12 support issues.
JCA and JCE Documentation (combined) for information on
keystores, ciphers etc.