HTTPsec-Java » Documentation » Package Docs

HTTPsec-Java

HTTPsec-Java is an implementation of the HTTPsec/1.0 specification in Java.

HTTPsec-Java includes a wrapper for java.net.HttpURLConnection that adds HTTPsec authentication to client applications and a servlet filter that can add HTTPsec authentication to any servlet webapp.


Index

  1. Package Contents
  2. System Requirements
  3. Installation
  4. Usage
    1. A Quick Test
    2. Client
    3. Servlet Filter
  5. javadocs
  6. JCE Configuration
    1. The Quick Way That Always Works
    2. The Other Way
  7. Certificates
  8. Performance Considerations
  9. Known Issues
  10. Legal Note
  11. Links

Package Contents

httpsec.jar The HTTPsec-Java library.
httpsec-tools.jar Command line tools.
web/ Sample webapp
docs/ Documentation

index

System Requirements

  1. Java 1.5 or later
  2. A compatible Java Cryptography Extension ( "JCE" ) provider. JCE Configuration docs for more details.
  3. Java Cryptography Extension Unlimited Strength Jurisdiction Policy Files 1.4.2
  4. The com.secarta.httpsec.tools package ( in httpsec-tools.jar ) requires the Bouncy Castle libraries.

index

Installation

  1. Client / Command-line tools

    Include httpsec.jar in your classpath.

    If you are using the com.secarta.httpsec.tools package include httpsec-tools.jar.

  2. Sample Webapp

    Copy the web/ directory of the distribution to your servlet containers webapps/ directory.

  3. Servlet Filter

    Copy httpsec.jar to your webapps WEB-INF/lib/ directory. Use the sample web.xml from the sample webapp as a guide to edit your web.xml.


index

Usage

Note:

You must configure the Java Cryptography Extension ( JCE ) before these examples will work. Unless you have specfic JCE configuration requirements try The Quick Method That Always Works.

A Quick Test

Make simple http "GET" request to the HTTPsec test server at http://server3.clinksystems.com:8080/httpsec/ The test servlet "echo" will return our request in the response body ( in the manner of the http method "TRACE" ).

java -jar httpsec-tools.jar client -id test http://server3.clinksystems.com:8080/httpsec/echo

Should produce output like this:

no private key specified - creating a self-signed CA...
local principal: test#aa4242443a3c4445e2af5a8b29077835b6f3b532491f19f97398991cbefa3a44
remote principal: httpsec_sample_webapp#c9a7f07c16f7dd04f2e735dff616a9b6fe575d5a50d4a0c80faf2368ce8f7b89

200 OK
Server: Apache-Coyote/1.1
Content-Encoding: x-httpsec/1.0-cipher
Expires: Thu, 26 Oct 2006 10:49:37 GMT
Cache-Control: no-transform
WWW-Authenticate: httpsec/1.0 continue; count=2; mac=AUatMW+yNuSW24MFYgjfuVaJ5hxUDI6gc7IQ0PTcSFk=; digest=P+ziUUKo6rkKjtYUdmDQxHI/PNyO5gb2RWIpXjVIoy8=
Content-Type: message/http
Content-Length: 496
Date: Thu, 26 Oct 2006 10:49:37 GMT

HTTP/1.1 GET /httpsec/echo
accept-encoding: x-httpsec/1.0-cipher
authorization: httpsec/1.0 continue; count=1; mac=b3nxfxuolaiNKWRjfKFOq/9B4JTR9++aPVHds+aMBrM=; digest=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=; url=http://server3.clinksystems.com:8080/httpsec/echo; token=/UV1euebPt8=
user-agent: Java/1.5.0_04
host: server3.clinksystems.com:8080
accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection: keep-alive
content-type: application/x-www-form-urlencoded

Client

Import the HTTPsec-Java classes:

import com.secarta.httpsec.HttpsecException;
import com.secarta.httpsec.HttpsecURLConnection;
import com.secarta.httpsec.HttpsecURLConnectionFactory;

Choose an id for the local principal or "requester":

String id = "test";

We need a certificate url and a private key. We could use the url of a certificate we've published on the a web server and load a private key from a file. This time we'll create a self-signed certificate authority that contains a certificate and private key.

com.secarta.httpsec.tools.tools.CA ca = new com.secarta.httpsec.tools.CA( id );

Then we'll initialize an HttpsecURLConnectionFactory with the id, certificate and private key:

HttpsecURLConnectionFactory cf = new HttpsecURLConnectionFactory(
    id,
    ca.getCertificate(),
    ca.getPrivateKey
);

Now we'll create an ordinary java.net.HttpURLConnection:

HttpURLConnection c = ( HttpURLConnection )new URL(
    "http://server3.clinksystems.com:8080/httpsec/echo"
);

Then we'll use the HttpsecURLConnectionFactory to wrap it and add HTTPsec authentication:

HttpsecURLConnection hc = cf.wrap( c );

We can use the HttpsecURLConnection just like an ordinary java.net.HttpURLConnection:

try {
    hc.setRequestMethod( "POST" );
    hc.setRequestProperty( "Content-Type", "text/plain; charset=utf-8" );
    hc.setDoOutput( true );
    hc.getOutputStream().write( "hello world".getBytes() );
    System.out.println( hc.getResponseCode() + " " + hc.getResponseMessage() );
} catch ( IOException e ) {
    // handle exceptions
} finally {
    hc.close();
}

Note the finally { hc.close(); } block. HTTPsec-Java might create a temporary file to buffer large messages. Calling HttpsecURLConnection.close() in a "finally" block ensures that if a file has been created it will be deleted regardless of whether exceptions are thrown.

HttpsecURLConnection reports the remote principal or "responder" as an HttpsecPrincipal object:

HttpsecPrincipal p = hc.getPrincipal();
System.out.println( p );

> httpsec_sample_webapp#c9a7f07c16f7dd04f2e735dff616a9b6fe575d5a50d4a0c80faf2368ce8f7b89

System.out.printnln( p.getID() );

> httpsec_sample_webapp

System.out.println( p.getFingerprint() );

> c9a7f07c16f7dd04f2e735dff616a9b6fe575d5a50d4a0c80faf2368ce8f7b89

Servlet Filter

Here is an annotated version of the web.xml from the sample webapp.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<!-- This filter does httpsec/1.0 authentication. see the javadocs for com.secarta.httpsec.servlet.HttpsecFilter for more info. -->
<filter>
<filter-name>
httpsec
</filter-name>
<filter-class>
com.secarta.httpsec.servlet.HttpsecFilter
</filter-class>
<!-- Out of the box the filter only supports a single local identity. This is what appears in the "id" field of challenge and initialize headers. -->
<init-param>
<param-name>
local-id
</param-name>
<param-value>
httpsec_sample_webapp
</param-value>
</init-param>
<!-- The filename of the private key associated with local-id. For obvious reasons you must make sure this is not accessible from the web. -->
<init-param>
<param-name>
private-key
</param-name>
<param-value>
WEB-INF/httpsec_sample_webapp.key
</param-value>
</init-param>
<!-- The url of the certificate associated with local-id. This url must be accessible from the web. See the httpsec documentation for more about how to communicate your certificate to other users. -->
<init-param>
<param-name>
certificate
</param-name>
<param-value>
http://secarta.com/products/httpsec-java/httpsec_sample_webapp.cert
</param-value>
</init-param>
<!-- If set to "yes" ( or "true" ) the filter will send a 401 Authorization Required response with an httpsec/1.0 challenge header. to unauthenticated requests. Otherwise it will ignore them. -->
<init-param>
<param-name>
challenge
</param-name>
<param-value>
yes
</param-value>
</init-param>
<!-- Should the filter expect a valid digest with each authenticated request. -->
<init-param>
<param-name>
request-digest
</param-name>
<param-value>
yes
</param-value>
</init-param>
<!-- Should the filter add a digest to authenticated responses. -->
<init-param>
<param-name>
response-digest
</param-name>
<param-value>
yes
</param-value>
</init-param>
<!-- Should the filter cipher responses for clients that have sent Accept-Encoding: x-httpsec/1.0-cipher -->
<init-param>
<param-name>
cipher
</param-name>
<param-value>
yes
</param-value>
</init-param>
<!-- Delete httpsec sessions ( *NOT* servlet sessions ) that have not been used for this many milliseconds. -->
<init-param>
<param-name>
session-timeout
</param-name>
<param-value>
600000
</param-value>
</init-param>
<!-- The filter will examine it's table of sessions every so many milliseconds and delete expired sessions. -->
<init-param>
<param-name>
session-cleanup
</param-name>
<param-value>
60000
</param-value>
</init-param>
<!-- Log filter activity. -->
<init-param>
<param-name>
verbose
</param-name>
<param-value>
yes
</param-value>
</init-param>
</filter>
<!-- This servlet returns the request it receives as message/http in the manner of the http TRACE method. -->
<servlet>
<servlet-name>
echo
</servlet-name>
<servlet-class>
com.secarta.httpsec.servlet.Echo
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
echo
</servlet-name>
<url-pattern>
/echo
</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>
httpsec
</filter-name>
<servlet-name>
echo
</servlet-name>
</filter-mapping>
</web-app>

index

JCE Configuration

This section is about how to configure the Java Cryptography Environment ( "JCE" ) to work with HTTPsec-Java and how to configure HTTPsec-Java to work with the JCE.

If you are unfamilliar with the JCE this might help.

You MUST install the Java Cryptography Extension Unlimited Strength Jurisdiction Policy Files 1.4.2. Sun has to cripple its crypto libraries to export them legally. These "policy files" de-restrict them.

The Quick Way That Always Works

Do not touch Primitives.conf

Download the provider package from the Legion of the Bouncy Castle.

For client applications put it in the same directory as httpsec.jar and, if you're using it httpsec-tools.jar.

For servlet applications ( with Apache Tomcat anyway ) you can't put the provider library in your webapps WEB-INF/lib/ directory because if you do the webapp will refuse to reload. Instead put it in your servlet containers common libs directory ( $TOMCAT/common/lib/ with Tomcat ).

The Other Way

If you have a more complicated application, or you want to use another provider, or a combination of providers you might need to make some changes to Primitives.conf to make HTTPsec-Java work for your application.

Primitives.conf is a java properties file which should be included at the bottom level of the classpath where httpsec.jar is installed.

Loading Providers

The first entry in Primitives.conf is a space-separated list of JCE provider classes that HTTPsec-Java will attempt to install.

providers = org.bouncycastle.jce.provider.BouncyCastleProvider:2 com.rsa.jsafe.provider.JsafeJCE
Each provider in the list can have an optional index after a colon at the end:
...BouncyCastleProvider:2
Which if present will make HTTPsec-Java use java.security.Security.insertProviderAt( provider, index ) rather than the default java.security.Security.addProvider( provider ).

If a provider class cannot be found HTTPsec-Java will print a warning, but not fail. If any exception happens whilst instantiating the provider HTTPsec-Java will fail with a java.lang.IllegalStateException.

Mapping Algorithm Names

HTTPsec-Java uses symbolic names to map JCE algorithm names to it's cryptographic services. Primitives.conf allows you to override the defaults.

The following properties are shown with their default values.

Hash                = SHA-256
Hmac                = HmacSHA256
PublicKeyCipher     = RSA/NONE/OAEPwithSHA1andMGF1padding
BlockCipher         = AES/ECB/NoPadding
StreamCipher        = AES/CBC/PKCS5padding
PublicKeyGenerator  = RSA
PublicKeyFactory    = RSA
DHGenerator         = DiffieHellman
DHAgreement         = DiffieHellman
CertificateFactory  = X.509
Signature           = SHA256withRSAandMGf1
SecureRandom        = SHA1PRNG

Note that you can completely mess up HTTPsec-Java by substituting different algorithms.

Using a Specific Provider

For each of the above properties you can also specify a provider. For example:

BlockCipher.provider = BC
Would force HTTPsec-Java to use the Bouncy Castle ( BC ) provider to create java.security.Cipher instances using the BlockCipher algorithm.

By default HTTPsec-Java uses whatever provider provides the algorithm it's after.

Default Diffie-Hellman Parameters

The HTTPsec specification defines Diffie-Hellman parameter groups ( MODP groups ) that implementations must support. You can use Primitives.conf to set the default MODP group that HTTPsec-Java uses.

DHGroup = rfc3526#14

index

Certificates

HTTPsec uses X.509 certificates. For many applications self-signed certificates are useful. The sample webapp contains a test certificate and private key.

To generate a self-signed certificate and private key ( a "certificate authority" ) first define the HTTPsec "peer identifier" to use:

ID=test

To create the certificate authority with HTTPsec-Java do:

java -jar httpsec-tools.jar ca -cert certificate.pem -private private.pem $ID

Alternatively you can generate the certificate authority with openssl:

openssl genrsa 2048 > test.key
openssl req -new -x509 -nodes -sha1 -days 365 -key test.key -subj "/CN=$ID" > certificate.pem
openssl pkcs8 -nocrypt -topk8 < test.key > private.pem

You can use openssl to view the contents of a certificate by using the command:

openssl x509 -text -noout < certificate.pem

The HTTPsec specification defines several ways to communicate certificates. The simplest is to publish certificate.pem on a web server.

The private key private.pem should always be stored somewhere that is not accessible via external http.


index

Performance Considerations

Using HTTPsec in your application adds overheads and constraints to its ordinary http conversations.

  1. Caching

    Messages authenticated with HTTPsec are not cachable.

  2. Extra Messages

    Initializing an HTTPsec session involves an extra request / response exchange. Both peers may need to make a subsequent database / http request to locate a certificate for the other.

  3. Generating Message Digests

    The http protocol allows for messages of arbitrary length with the end of the message delimited by the sender closing the stream ( Connection: close ) or by sending a final chunk ( Transfer-Encoding: chunked ).

    This, in combination with HTTPsec message digests can lead to an arbitrarily long wait as the receiver has to reach the end of the message to calculate the message digest.

    Both client and server components of HTTPsec-Java allow the user to switch off message digest processing at the expense of establishing message integrity.

  4. Cryptographic Algorithm Performance

    Cryptographic algorithm performance in Java is not as predictable as native implementations. Alright, it's crap. Then again no sometimes it's not. It will depend on which provider you use for which algorithm.


index

Known Issues

  1. certificate=this:entity-body not supported

    This version of HTTPsec-Java does not recognise the this:entity-body URI in the "certificate" field of initialize headers. If a peer receives a message with the certificate specified like this it will be unable to retrieve the certificate and will fail.

  2. No "certificate" field in challenge headers

    The optional certificate=... field is never sent in challenge responses. Since the field is optional this has no effect on protocol operation.

  3. Sharing private keys with openssl

    The default formats for private keys produced by HTTPsec-Java and openssl differ.

    To convert an existing private key created with openssl ( that wasn't created with the -topk8 option ) to HTTPsec-Java ( PKCS#8 ) format do:

    openssl pkcs8 -nocrypt -topk8 < openssl-key

    To convert a key created with HTTPsec-Java to the default openssl format ( PKCS#12 ) do:

    openssl pkcs8 -nocrypt < httpsec-java-key


index

Legal Note

This product uses strong cryptography and may be illegal or subject to import / export restrictions in your country or jurisdiction.

index

Links

HTTPsec-Java
http://secarta.com/products/httpsec-java/
HTTPsec-Java Documentation index
http://secarta.com/products/httpsec-java/doc/
HTTPsec-Java FAQ
http://secarta.com/products/httpsec-java/doc/FAQ.html
HTTPsec/1.0 specification
http://httpsec.org/
Secarta
http://secarta.com/
HTTP/1.1
rfc 2616
http://www.w3.org/Protocols/rfc2616/rfc2616.html
The Legion of the Bouncy Castle
http://bouncycastle.org/
openssl
http://www.openssl.org