How To Secure an Organization That Is Under Constant Attack

Battle of GeonosisThere have been many recent security incidents at well-respected organizations like the Federal Reserve, the US Energy Department, the New York Times, and the Wall Street Journal.

 

If these large organizations are incapable of keeping unwanted people off their systems, then who is?

The answer unfortunately is: not many. So we must assume our systems are compromised. Compromised is the new normal.

This has implications for our security efforts:

  1. We need to increase our detection capabilities
  2. We need to be able to respond quickly, preferably in an automated fashion, when we detect an intrusion

Increasing Intrusion Detection Capabilities with Security Analytics

There are usually many small signs that something fishy is going on when an intruder has compromised your network.

For instance, our log files might show that someone is logging in from an IP address in China instead of San Francisco. While that may be normal for our CEO, it’s very unlikely for her secretary.

Another example is when someone tries to access a system it normally doesn’t. This may be an indication of an intruder trying to escalate his privileges.

Security AnalyticsMost of us are currently unable to collect such small indicators into firm suspicions, but that is about to change with the introduction of Big Data Analytics technology.

RSA recently released a report that predicts that big data will play a big role in Security Incident Event Monitoring (SIEM), network monitoring, Identity and Access Management (IAM), fraud detection, and Governance, Risk, and Compliance (GRC) systems.

RSA is investing heavily in Security Analytics to prevent and predict attacks, and so is IBM.

Quick, Automated, Responses to Intrusion Detection with Risk-Adaptive Access Control

The information we extract from our big security data can be used to drive decisions. The next step is to automate those decisions and actions based on them.

Large organizations, with hundreds or even thousands of applications, have a large attack surface. They are also interesting targets and therefore must assume they are under attack multiple times a day.

Anything that is not automated is not going to scale.

Risk-Adaptive Access Control (RAdAC)One decision than can be automated is whether we grant someone access to a particular system or piece of data.

This dynamic access control based on risk information is what NIST calls Risk-Adaptive Access Control (RAdAC).

As I’ve shown before, RAdAC can be implemented using eXtensible Access Control Markup Language (XACML).

What do you think?

Is your organization ready to look at security analytics? What do you see as the major road blocks for implementing RAdAC?

Advertisements

Book review: Secure Programming with Static Analysis

Secure Programming with Static AnalysisOne thing that should be part of every Security Development Lifecycle (SDL) is static code analysis.

This topic is explained in great detail in Secure Programming with Static Analyis.

Chapter 1, The Software Security Problem, explains why security is easy to get wrong and why typical methods for catching bugs aren’t effective for finding security vulnerabilities.

Chapter 2, Introduction to Static Analysis, explains that static analysis involves a software program checking the source code of another software program to find structural, quality, and security problems.

Chapter 3, Static Analysis as Part of Code Review, explains how static code analysis can be integrated into a security review process.

Chapter 4, Static Analysis Internals, describes how static analysis tools work internally and what trade-offs are made when building them.

This concludes the first part of the book that describes the big picture. Part two deals with pervasive security problems.

InputChapter 5, Handling Input, describes how programs should deal with untrustworthy input.

Chapter 6, Buffer Overflow, and chapter 7, Bride to Buffer Overflow, deal with buffer overflows. These chapters are not as interesting for developers working with modern languages like Java or C#.

Chapter 8, Errors and Exceptions, talks about unexpected conditions and the link with security issues. It also handles logging and debugging.

Chapter 9, Web Applications, starts the third part of the book about common types of programs. This chapter looks at security problems specific to the Web and HTTP.

Chapter 10, XML and Web Services, discusses the security challenges associated with XML and with building up applications from distributed components.

CryptographyChapter 11, Privacy and Secrets, switches the focus from AppSec to InfoSec with an explanation of how to protect private information.

Chapter 12, Privileged Programs, continues with a discussion on how to write programs that operate with different permissions than the user.

The final part of the book is about gaining experience with static analysis tools.

Chapter 13, Source Code Analysis Exercises for Java, is a tutorial on how to use Fortify (a trial version of which is included with the book) on some sample Java projects.

Chapter 14, Source Code Analysis Exercises for C does the same for C programs.

rating-five-out-of-five

This book is very useful for anybody working with static analysis tools. Its description of the internals of such tools helps with understanding how to apply the tools best.

I like that the book is filled with numerous examples that show how the tools can detect a particular type of problem.

Finally, the book makes clear that any static analysis tool will give both false positives and false negatives. You should really understand security issues yourself to make good decisions. When you know how to do that, a static analysis tool can be a great help.

Using Cryptography in Java Applications

This post describes how to use the Java Cryptography Architecture (JCA) that allows you to use cryptographic services in your applications.

Java Cryptography Architecture Services

The JCA provides a number of cryptographic services, like message digests and signatures. These services are accessible through service specific APIs, like MessageDigest and Signature. Cryptographic services abstract different algorithms. For digests, for instance, you could use MD5 or SHA1. You specify the algorithm as a parameter to the getInstance() method of the cryptographic service class:

MessageDigest digest = MessageDigest.getInstance("MD5");

You find the value of the parameter for your algorithm in the JCA Standard Algorithm Name Documentation. Some algorithms have parameters. For instance, an algorithm to generate a private/public key pair will take the key size as a parameter. You specify the parameter(s) using the initialize() method:

KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
generator.initialize(1024);

If you don’t call the initialize() method, some default value will be used, which may or may not be what you want. Unfortunately, the API for initialization is not 100% consistent across services. For instance, the Cipher class uses init() with an argument indicating encryption or decryption, while the Signature class uses initSign() for signing and initVerify() for verification.

Java Cryptography Architecture Providers

The JCA keeps your code independent from a particular cryptographic algorithm’s implementation through the provider system. Providers are ranked according to a preference order, which is configurable (see below). The best preference is 1, the next best is 2, etc. The preference order allows the JCA to select the best available provider that implements a given algorithm. Alternatively, you can specify a specific provider in the second argument to getInstance():

Signature signature = Signature.getInstance("SHA1withDSA", "SUN");

The JRE comes with a bunch of providers from Oracle by default. However, due to historical export restrictions, these are not the most secure implementations. To get access to better algorithms and larger key sizes, install the Java Cryptography Extension Unlimited Strength Jurisdiction Policy Files. Update: Note that the above statement is true for the Oracle JRE. OpenJDK doesn’t have the same limitation.

Make Your Use of Cryptography Configurable

You should always make sure that the cryptographic services that your application uses are configurable. If you do that, you can change the cryptographic algorithm and/or implementation without issuing a patch. This is particularly valuable when a new attack on an (implementation of an) algorithm becomes available. The JCA makes it easy to configure the use of cryptography. The getInstance() method accepts both the name of the algorithm and the name of the provider implementing that algorithm. You should read both and any values for the algorithm’s parameters from some sort of configuration file. Also make sure you keep your code DRY and instantiate cryptographic services in a single place. Check that the requested algorithm and/or provider are actually available. The getInstance() method throws NoSuchAlgorithmException when a given algorithm or provider is not available, so you should catch that. The safest option then is to fail and have someone make sure the system is configured properly. If you continue despite a configuration error, you may end up with a system that is less secure than required. Note that Oracle recommends not specifying the provider. The reasons they provide is that not all providers may be available on all platforms, and that specifying a provider may mean that you miss out on optimizations. You should weigh those disadvantages against the risk of being vulnerable. Deploying specific providers with known characteristics with your application may neutralize the disadvantages that Oracle mentions.

Adding Cryptographic Service Providers

The provider system is extensible, so you can add providers. For example, you could use the open source Bouncy Castle or the commercial RSA BSAFE providers. In order to add a provider, you must make sure that its jar is available to the application. You can put it on the classpath for this purpose. Alternatively, you can make it an installed extension by placing it in the $JAVA_HOME/lib/ext directory, where $JAVA_HOME is the location of your JDK/JRE distribution. The major difference between the two approaches is that installed extensions are granted all permissions by default whereas code on the classpath is not. This is significant when (part of) your code runs in a sandbox. Some services, like Cipher, require the provider jar to be signed. The next step is to register the provider with the JCA provider system. The simplest way is to use Security.addProvider():

Security.addProvider(new BouncyCastleProvider());

You can also set the provider’s preference order by using the Security.insertProviderAt() method:

Security.insertProviderAt (new JsafeJCE(), 1);

One downside of this approach is that it couples your code to the provider, since you have to import the provider class. This may not be an important issue in an modular system like OSGi. Another thing to look out for is that code requires SecurityPermission to add a provider programmatically. The provider can also be configured as part of your environment via static registration by adding an entry to the java.security properties file (found in $JAVA_HOME/jre/lib/security/java.security):

security.provider.1=com.rsa.jsafe.provider.JsafeJCE
security.provider.2=sun.security.provider.Sun

The property names in this file start with security.provider. and end with the provider’s preference. The property value is the fully qualified name of the class implementing Provider.

Implementing Your Own Cryptographic Service Provider

Don’t do it. You will get it wrong and be vulnerable to attacks.

Using Cryptographic Service Providers

The documentation for the provider should tell you what provider name to use as the second argument to getInstance(). For instance, Bouncy Castle uses BC, while RSA BSAFE uses JsafeJCE. Most providers have custom APIs as well as JCA conformant APIs. Do not use the custom APIs, since that will make it impossible to configure the algorithms and providers used.

Not All Algorithms and Implementations Are Created Equal

It’s important to note that different algorithms and implementations have different characteristics and that those may make them more or less suitable for your situation. For instance, some organizations will only allow algorithms and implementations that are FIPS 140-2 certified or are on the list of NSA Suite B cryptographic algorithms. Always make sure you understand your customer’s cryptographic needs and requirements.

Using JCA in an OSGi environment

The getInstance() method is a factory method that uses the Service Provider Interface (SPI). That is problematic in an OSGi world, since OSGi violates the SPI framework’s assumption that there is a single classpath. Another potential issue is that JCA requires some jars to be signed. If those jars are not valid OSGi bundles, you can’t run them through bnd to make them so, since that would make the signature invalid. Fortunately, you can kill both birds with one stone. Put your provider jars on the classpath of your main program, that is the program that starts the OSGi framework. Then export the provider package from the OSGi system bundle using the org.osgi.framework.system.packages.extra system property. This will make the system bundle export that package. Now you can simply use Import-Package on the provider package in your bundles. There are other options for resolving these problems if you can’t use the above solution.

Permissions in OSGi

In a previous post, we looked at implementing a sandbox for Java applications in which we can securely run mobile code.

This post looks at how to do the same in an OSGi environment.

OSGi

The OSGi specification defines a dynamic module system for Java. As such, it’s a perfect candidate for implementing the kind of plugin system that would enable your application to dynamically add mobile code.

Security in OSGi builds on the Java 2 security architecture that we discussed earlier, so you can re-use your knowledge about code signing, etc.

OSGi goes a couple of steps further, however.

Revoking Permissions

One of the weaknesses in the Java permissions model is that you can only explicitly grant permissions, not revoke them. There are many cases where you want to allow everything except a particular special case.

There is no way to do that with standard Java permissions, but, luckily, OSGi introduces a solution.

The downside is that OSGi introduces its own syntax for specifying policies.

The following example shows how to deny PackagePermission for subpackages of com.acme.secret:

DENY {
  ( ..PackagePermission "com.acme.secret.*" "import,exportonly" )
} "denyExample"

(In this and following examples, I give the simple name of permission classes instead of the fully qualified name. I hint at that by prefixing the simple name with ..)

PackagePermission is a permission defined by OSGi for authorization of package imports and exports. Your application could use a policy like this to make sure that mobile code can’t call the classes in a given package, for instance to limit direct access to the database.

Extensible Conditions on Permissions

The second improvement that OSGi brings is that the conditions under which a permission are granted can be dynamically evaluated at runtime.

The following example shows how to conditionally grant ServicePermission:

ALLOW {
  [ ..BundleSignerCondition "* ; o=ACME" ]
  ( ..ServicePermission "..ManagedService" "register" )
} "conditionalExample"

ServicePermission is an OSGi defined permission that restricts access to OSGi services.

The condition is the part between square brackets. OSGi defines two conditions, which correspond to the signedBy and codeBase constructs in regular Java policies.

You can also define your own conditions. The specification gives detailed instructions on implementing conditions, especially with regard to performance.

Different Types of Permissions

The final innovation that OSGi brings to the Java permissions model, is that there are different types of permissions.

Bundles can specify their own permissions. This doesn’t mean that bundles can grant themselves permissions, but rather that they can specify the maximum privileges that they need to function. These permissions are called local permissions.

The OSGi framework ensures that the bundle will never have more permissions than the local permissions, thus implementing the principle of least privilege.

Actually, that statement is not entirely accurate. Every bundle will have certain permissions that they need to function in an OSGi environment, like being able to read the org.osgi.framework.* system properties.

These permissions are called implicit permissions, since every bundle will have them, whether the permissions are explicitly granted to the bundle or not.

The final type of permissions are the system permissions. These are the permissions that are granted to the bundle.

The effective permissions are the set of permissions that are checked at runtime:

effective = (local ∩ system) ∪ implicit

Local permissions enable auditing. Before installing a bundle into your OSGi environment, you can inspect the Bundle Permission Resource in OSGI-INF/permissions.perm to see what permissions the bundle requires.

If you are not comfortable with granting the bundle these permissions, you can decide to not install the bundle. The point is that you can know all of this without running the bundle and without having access to its source code.

Integration into the Java Permissions Model

The OSGi framework integrates their extended permissions model into the standard Java permissions model by subclassing ProtectionDomain.

Each bundle gets a BundleProtectionDomainImpl for this purpose.

This approach allows OSGi to tap into the standard Java permissions model that you have come to know, so you can re-use most of your skills in this area. The only thing you’ll have to re-learn, is how to write policies.

Comparison of Permission Models

To put the OSGi permission model into perspective, consider the following comparison table, which uses terminology from the XACML specification:

Permission Models Standard Java OSGi
Effects permit permit, deny
Target, Condition codeBase, signedBy codeBase, signedBy, custom conditions
Combining Algorithms first-applicable first-applicable, local/system/implicit

From this table you can see that the OSGi model is quite a bit more expressive than the standard Java permission model, although not as expressive as XACML.

Sandboxing Java Code

In a previous post, we looked at securing mobile Java code. One of the options for doing so is to run the code in a cage or sandbox.

This post explores how to set up such a sandbox for Java applications.

Security Manager

The security facility in Java that supports sandboxing is the java.lang.SecurityManager.

By default, Java runs without a SecurityManager, so you should add code to your application to enable one:

System.setSecurityManager(new SecurityManager());

You can use the standard SecurityManager, or a descendant.

The SecurityManager has a bunch of checkXXX() methods that all forward to checkPermission(permission, context). This method calls upon the AccessController to do the actual work (see below).

[The checkXXX() methods are a relic from Java 1.1.]

If a requested access is allowed, checkPermission() returns quietly. If denied, a java.lang.SecurityException is thrown.

Code that implements the sandbox should call a checkXXX method before performing a sensitive operation:

SecurityManager securityManager = System.getSecurityManager();
if (securityManager != null) {
  Permission permission = ...;
  securityManager.checkPermission(permission);
}

The JRE contains code just like that in many places.

Permissions

A permission represents access to a system resource.

In order for such access to be allowed, the corresponding permission must be explicitly granted (see below) to the code attempting the access.

Permissions derive from java.security.Permission. They have a name and an optional list of actions (in the form of comma separated string values).

Java ships with a bunch of predefined permissions, like FilePermission. You can also add your own permissions.

The following is a permission to read the file /home/remon/thesis.pdf:

Permission readPermission = new java.io.FilePermission(
    "/home/remon/thesis.pdf", "read");

You can grant a piece of code permissions to do anything and everything by granting it AllPermission. This has the same effect as running it without SecurityManager.

Policies

Permissions are granted using policies. A Policy is responsible for determining whether code has permission to perform a security-sensitive operation.

The AccessController consults the Policy to see whether a Permission is granted.

There can only be one Policy object in use at any given time. Application code can subclass Policy to provide a custom implementation.

The default implementation of Policy uses configuration files to load grants. There is a single system-wide policy file, and a single (optional) user policy file.

You can create additional policy configuration files using the PolicyTool program. Each configuration file must be encoded in UTF-8.

By default, code is granted no permissions at all. Every grant statement adds some permissions. Permissions that are granted cannot be revoked.

The following policy fragment grants code that originates from the /home/remon/code/ directory read permission to the file /home/remon/thesis.pdf:

grant codeBase "file:/home/remon/code/-" {
    permission java.io.FilePermission "/home/remon/thesis.pdf",
        "read";
};

Note that the part following codeBase is a URL, so you should always use forward slashes, even on a Windows system.

A codeBase with a trailing / matches all class files (not JAR files) in the specified directory. A codeBase with a trailing /* matches all files (both class and JAR files) contained in that directory. A codeBase with a trailing /- matches all files (both class and JAR files) in the directory and recursively all files in subdirectories contained in that directory.

For paths in file permissions on Windows systems, you need to use double backslashes (\\), since the \ is an escape character:

grant codeBase "file:/C:/Users/remon/code/-" {
    permission java.io.FilePermission
        "C:\\Users\\remon\\thesis.pdf", "read";
};

For more flexibility, you can write grants with variable parts. We already saw the codeBase wildcards. You can also substitute system properties:

grant codeBase "file:/${user.home}/code/-" {
    permission java.io.FilePermission
        "${user.home}${/}thesis.pdf", "read";
};

Note that ${/} is replaced with the path separator for your system. There is no need to use that in codeBase, since that’s a URL.

Signed Code

Of course, we should make sure that the code we use is signed, so that we know that it actually came from who we think it came from.

We can test for signatures in our policies using the signedBy clause:

keystore "my.keystore";
grant signedBy "signer.alias", codeBase ... {
  ...
};

This policy fragment uses the keystore with alias my.keystore to look up the public key certificate with alias signer.alias.

It then verifies that the executing code was signed by the private key corresponding to the public key in the found certificate.

There can be only one keystore entry.

The combination of codeBase and signedBy clauses specifies a ProtectionDomain. All classes in the same ProtectionDomain have the same permissions.

Privileged Code

Whenever a resource access is attempted, all code on the stack must have permission for that resource access, unless some code on the stack has been marked as privileged.

Marking code as privileged enables a piece of trusted code to temporarily enable access to more resources than are available directly to the code that called it. In other words, the security system will treat all callers as if they originated from the ProtectionDomain of the class that issues the privileged call, but only for the duration of the privileged call.

You make code privileged by running it inside an AccessController.doPrivileged() call:

AccessController.doPrivileged(new PrivilegedAction() {
  public Object run() {
    // ...privileged code goes here...
    return null;
  }
});

Assembling the Sandbox

Now we have all the pieces we need to assemble our sandbox:

  1. Install a SecurityManager
  2. Sign the application jars
  3. Grant all code signed by us AllPermission
  4. Add permission checks in places that mobile code may call
  5. Run the code after the permission checks in a doPrivileged() block

I’ve created a simple example on GitHub.

XACML Vendor: NextLabs

This is the third in a series of posts where I interview XACML vendors. This time we talk to NextLabs.

Why does the world need XACML? What benefits do your customers realize?

Over the last 20 years IT has focused on building walls around their networks and applications. Now with cross-organizational collaboration, cloud and mobile we are finding that those walls are no longer relevant for protecting critical information.

The world needs XACML to protect critical information in today’s collaborative business and IT environment.

At NextLabs we focus on applying Extensible Access Control Markup Language (XACML) to information protection to enable our customers to accelerate global collaboration while simultaneously protecting their most sensitive intellectual property.

Using Attribute-Based Access Control (ABAC) and externalized authorization we can protect data based on its sensitivity, defined by attributes, across applications and systems. Traditional access control models such as Role-Based Access Control (RBAC) and Access Control Lists (ACLs) simply do not scale to address the information protection problem.

What products do you have in the XACML space?

NextLabs has taken an industry-solution approach to the market. We provide several industry-solutions for regulatory compliance, secure partner collaboration, and intellectual property protection.

Each solution is comprised of pre-built policy libraries that implement industry best-practices, pre-built policy-enforcement-points (PEPs) for critical enterprise applications, our Control Center Information Control Platform based on XACML, and pre-built reporting.

Control Center is our Information Control Platform. It has several components:

  • Control Center Server – the Control Center server includes our Policy Administration Point (PAP) and additional services necessary for information control use cases. These include:
    • Information Classification Services – a compressive set of services that automate information classification such as content-analysis, data tagging, and user driven classification
    • Policy Development and Lifecycle Management Services – Services to govern and simplify the development and management of policy such as delegated administration, approval workflow, testing and validation, audit trail, versioning, and dictionary services. On top of this we provide Policy Studio, a graphical policy integrated development environment (IDE)
    • Policy Deployment and PDP Management Services – services that allow us to reliably deploy policies to distributed PDPs, even over the public internet
    • Audit and Reporting Services – role-based dashboards, analytics, and reporting to provide insights into information activity and policy compliance
  • Control Center Policy Controller – the Policy Controller is our policy-decision-point (PDP). We provide three different editions of the Policy Controller:
    • Endpoint Policy Controller – designed to run on laptops and desktops, even when disconnected
    • Server Policy Controller – designed to run co-located with a server based applications. Can be run as a service/daemon or embedded into an application
    • Policy Controller Service – designed to run as a stand-alone PDP service in J2EE Application Server

NextLabs provides over a dozen pre-built Policy Enforcement Points (PEPs) for common applications and system. These are separated into three product lines:

  • Entitlement Management – pre-built PEPs for server applications, including:
    • Document Management (Microsoft SharePoint, SAP Document Management)
    • SAP Enterprise Resource Planning
    • Product Lifecycle Management (SAP PLM, Dassault Enovia)
    • Collaboration (CIFS and NFS File Servers)
  • Collaborative Rights Management – Collaborative Rights Management (cRM) applies XACML to protect unstructured data (files)
  • Data Protection – Data Protection is a suite of endpoint PEPs for removable devices, networking, email applications, web meeting applications and unified communication applications

What versions of the spec do you support? What optional parts? What profiles?

We support the core 2.0 and 3.0 specifications as well as the SAML, EC-US and IPC profiles.

What sets your product apart from the competition?

At NextLabs we differentiate ourselves through comprehensive industry solutions and our focus on information protection.

XACML is a generic authorization standard and can be applied to many things. Making it useful to the business buyer requires significant work beyond the standard – resources need attributes (i.e. information needs to be classified), PEPs need to be built, obligations/advise need to be implemented and policies need to be designed, developed and tested.

We have addressed this solution gap to make XACML useful for protecting critical information, and that’s what sets us apart.

What customers use your product? What is your biggest deployment?

NextLabs works with leading companies in the Manufacturing, High-Tech, Aerospace and Defense, Chemical, Energy, and Industrial Equipment industries. These companies typically have very high-value or sensitive intellectual property, global operations and are subject to strict global regulations.

We have multiple deployments above 50,000 users and have a project that will soon reach 100,000 users.

We have a few webinars where you can hear how some of our customers like GE and Tyco benefitted from our solutions. Recently one of our customers, BAE Systems, was recognized by CIO magazine for their use of our product.

What programming languages do you support? Will you support the REST profile? And JSON?

We support Java, C#, C++, SOAP, and SAP ABAP. We plan to support the REST and JSON profiles in a future release.

Do you support OpenAz? Spring-Security? Other open source efforts?

NextLabs contributed the C++ implementation of OpenAz and also supports OpenAz in Java.

We are committed to open APIs for authorization since this is critical to the growth of the XACML market and will support any effort that moves the industry forward in this regard.

How easy is it to write a PEP for your product? And a PIP? How long does an implementation of your product usually take?

NextLabs provides over a dozen PEP products and pre-built PIP integrations, which eliminate the need to build PEPs or PIPs for many common commercial applications.

For a custom PEP/PIPs, the time required depends on the nature of the application and the use case you are trying to support. The time can vary from hours to weeks.

Installing the product only takes hours, but the time required to implement a solution to production will vary depending on the number and type of applications and the policy use cases.

Can your product be embedded (i.e. run in-process)?

Yes, our Policy Controller can be embedded into another application.

What optimizations have you made? Can you share performance numbers?

Any latency introduced by external queries to information points (PIP) and evaluating large numbers of policy is a concerns for all customers.

We designed our architecture with the principle of a PDP that can run completely off-line – with the ability to make complex decisions without any network calls. This was a critical requirement for our endpoint products and has the benefit of eliminating latency associated with network roundtrips or external queries to PIPs.

To enable our off-line PDP we developed a patented policy deployment technology, called ICENet, which pre-evaluates multiple dimensions of policy when it is deployed to distributed PDPs.

99% of our policy queries are under 5 milliseconds, with most of those under 1 millisecond.

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.