Signing Java Code
In a previous post, we discussed how to secure mobile code.
One of the measures mentioned was signing code. This post explores how that works for Java programs.
Digital Signatures
The basis for digital signatures is cryptography, specifically, public key cryptography. We use a set of cryptographic keys: a private and a public key.
The private key is used to sign a file and must remain a secret. The public key is used to verify the signature that was generated with the private key. This is possible because of the special mathematical relationship between the keys.
Both the signature and the public key need to be transferred to the recipient.
Certificates
In order to trust a file, one needs to verify the signature on that file. For this, one needs the public key that corresponds to the private key that was used to sign the file. So how can we trust the public key?
This is where certificates come in. A certificate contains a public key and the distinguished name that identifies the owner of that key.
The trust comes from the fact that the certificate is itself signed. So the certificate also contains a signature and the distinguished name of the signer.
When we control both ends of the communication, we can just provide both with the certificate and be done with it. This works well for mobile apps you write that connect to a server you control, for instance.
If you don’t control both ends, then we need an alternative. The distinguished name of the signer can be used to look up the signer’s certificate. With the public key from that certificate, the signature in the original certificate can be verified.
We can continue in this manner, creating a certificate chain, until we reach a signer that we explicitly trust. This is usually a well-established Certificate Authority (CA), like VeriSign or Thawte.
Keystores
In Java, private keys and certificates are stored in a password-protected database called a keystore.
Each key/certificate combination is identified by a string known as the alias.
Code Signing Tools
Java comes with two tools for code signing: keytool and jarsigner.
Use the jarsigner
program to sign jar files using certificates stored in a keystore.
Use the keytool
program to create private keys and the corresponding public key certificates, to retrieve/store those from/to a keystore, and to manage the keystore.
The keytool
program is not capable of creating a certificate signed by someone else. It can create a Certificate Signing Request, however, that you can send to a CA. It can also import the CA’s response into the keystore.
The alternative is to use tools like OpenSSL or BSAFE, which support such CA capabilities.
Code Signing Environment
Code signing should happen in a secure environment, since private keys are involved and those need to remain secret. If a private key falls into the wrong hands, a third party could sign their code with your key, tricking your customers into trusting that code.
This means that you probably don’t want to maintain the keystore on the build machine, since that machine is likely available to many people. A more secure approach is to introduce a dedicated signing server:
You should also use different signing certificates for development and production.
Timestamping
Certificates are valid for a limited time period only. Any files signed with a private key for which the public key certificate has expired, should no longer be trusted, since it may have been signed after the certificate expired.
We can alleviate this problem by timestamping the file. By adding a trusted timestamp to the file, we can trust it even after the signing certificate expires.
But then how do we trust the timestamp? Well, by signing it using a Time Stamping Authority, of course! The OpenSSL
program can help you with that as well.
Beyond Code Signing
When you sign your code, you only prove that the code came from you. For a customer to be able to trust your code, it needs to be trustworthy. You probably want to set up a full-blown Security Development Lifecycle (SDL) to make sure that it is as much as possible.
Another thing to consider in this area is third-party code. Most software packages embed commercial and/or open source libraries. Ideally, those libraries are signed by their authors. But no matter what, you need to take ownership, since customers don’t care whether a vulnerability is found in code you wrote yourself or in a library you used.
Reference: Signing Java Code from our JCG partner Remon Sinnema at the Secure Software Development blog.