Here is some info on how you can interop between a Java application and
Microsoft's .NET web security enhancements (WSE). Just some useful info I
found out as we tried to do interop with an XML gateway product our team is
developing [1]. Hope it is useful to someone.
You should know some
====================
* Basic .NET and Java
* Basic XML and web service standards, such as SOAP and WS-Security.
* Basic cryptography and PKI, such as what signing and encrypting is,
what an X.509 certificate is, and how all that relate to XML.
Scenarios
=========
We wanted to interoperate in two scenarios. Firstly, we set up a .NET web
service and use a Java client to consume services. Secondly, we reversed
the setting and connected a .NET client to a Java-based web service. Our
goal was to successfully implement this from a secure web service point
of view, utilizing WS-Security.
As a Java-based service (and acting as a client as well) we used our product,
the Trust Gateway, mentioned above. You should be able to use any
WS-compliant client and server though.
In .NET, the WS-series of standards is implemented in the WSE add-on. There
currently are two WSE versions, WSE 1.0 SP1 and WSE 2.0 Technology Preview.
We will briefly discuss the security-relevant differences between those two
versions.
Keys
====
To set up a secure connection between two parties, you need a means of
authenticating each side. Typically this is made with digital keys and
certificates.
WSE is a bit peculiar on which keys it will find usable. The keys and
certificates need to be placed in the correct certificate container, such as
current user or local machine, so that the application can find them. The
corresponding private keys need to be readable by the application process
that accesses them. This is well documented in WSE, but easy to miss.
What isn't well documented is the fact that the certificates must have an
exact set of X.509 critical extensions: Digital Signature, Non-Repudiation,
Key Encipherment, and Data Encipherment (F0). It is important that these
extensions are marked critical for .NET WSE to acknowledge these keys. This
goes for both 1.0 and 2.0 TP. You need Data Encipherment if you plan to use
the key for WS-Security with encryption.
How to generate keys with OpenSSL
=================================
We choose to use OpenSSL to generate the keys, and not Microsoft's
makecert.exe utility, since the latter only works within a Windows
environment.
This is how we created the keys:
1. OpenSSL may already be installed on your machine. If not, download and
install from http://www.openssl.org
2. Edit openssh.conf if needed. You need to make sure the certificate usage
extensions are marked as critical like this
[usr_cert]
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, \
dataEncipherment
3. You then need to create a CA that can issue certificates. To issue a
certificate you then create and sign requests in common order:
/usr/ssl/misc/CA.sh -newca
/usr/ssl/misc/CA.sh -newreq
/usr/ssl/misc/CA.sh -sign
4. Finally, convert files into PKCS #12 (.p12) files. PKCS#12 is a
standardized key and certificate format, readable by Windows and Java.
openssl pkcs12 -export -in newcert.pem -inkey newreq.pem \
-out filename.p12
Setting up .NET keys
====================
The keys and certificates need to be imported into your Windows certificate
stores. You should be able to double click the .p12 file and import it. Since
there are multiple certificate stores in windows, you will want to make sure
the cert and key is put into the correct store that is used by your service
or client. For instance, there is a local machine and a current user
store. By default, the latter is used by a .NET WSE client, and the former is
used by a web service.
You will also have to be careful to make sure the private keys are readable
by the process that runs your service. This is documented in the WSE
releases, but another thing easy to overlook.
WSE 1.0 SP1 and WSE 2.0 TP
==========================
There are some minor code changes in the WSE 2.0 preview. You will need to
rename some packages and change some code related to SOAP context. This is no
biggie and is well documented.
A more obscure change is that some namespaces have changed. This may throw
your interoperability effort off track. In fact, you will find that using a
WSE 1.0 SP1 connecting to a WSE 2.0 server will fail with error messages of
type invalid WS-Routing header.
WSE 2.0 has an extra element that contain two namespaces, for security and
timestamp:
<microsoft.web.services>
<protocols>
<security version="http://schemas.xmlsoap.org/ws/2002/12/secext"/>
<timestamp version="http://schemas.xmlsoap.org/ws/2002/07/utility"/>
</protocols>
</microsoft.web.services>
These two elements translate into URIs used for prefixes wsse and wsu in the
SOAP header.
The above setting reflect the (default) WS-Security setting. If you choose
the OASIS setting, you will end up with the following namespaces
<microsoft.web.services>
<protocols>
<security version="http://schemas.xmlsoap.org/ws/2003/06/secext"/>
<timestamp version="http://schemas.xmlsoap.org/ws/2003/06/utility"/>
</protocols>
</microsoft.web.services>
You can of course hand edit these URIs to suit your application.
Trust Gateway
=============
The Trust Gateway is a commercial VeriSign web services gateway. It is a pure
Java product (JDK 1.4 based) that installs as a few servlets inside a servlet
container (we use Jetty). It is available for download (see [1] below) and a
sixty day evaluation license is available for anyone.
The Trust Gatewy product uses the Trust Services Integration Toolkit (TSIK)
that is available in separate download [2] if desired and free for
non-commercial use.
Setting up
==========
The Trust Gateway is simple to use. Once installed, point your favorite web
browser to its start page, login with the username and password created
during installation, and configure your gateway through its web based
console.
First you will import the .p12 files into the key store that the Trust
Gateway uses. Just click on Keystores tab and choose Import PKCS#12. Once you
have imported the test keys that we generated above, you can set up the gates
needed. A gate can be of either inflow or outflow type.
* Inflow denotes a gate listening for an external connection,
* Outflow is a gate that you would connect to from inside your corporation,
perhaps to have the Trust Gateway automatically apply some security
processing before it leaves your network.
We set up two gates. The first gate is an outflow gate that will listen for
connections, then take the incoming XML and sign and encrypt it according to
WS-Security. The Trust Gateway will then wait for the response, and check
that it is signed and encrypted as defined in the security settings.
Once the gate is set up correctly, the important parts of its definition
should read (numbered for reference below):
1 <Gate loggingLevel="all" name="echo wsstest keys">
2 ...
3 <HTTPServiceConnector>
4 <Service enabled="true">http://localhost/Echo/Service1.asmx</Service>
5 </HTTPServiceConnector>
6 <ResponsePipeline>
7 <X509ChainValidation>
8 <ValidateCredentials>signature</ValidateCredentials>
9 <Certificate keystore="trustpoints">ca</Certificate>
10 </X509ChainValidation>
11 </ResponsePipeline>
12 <MessageSecurity scheme="wssecurity">
13 <SigningKey>
14 <Key keystore="keys">tg key</Key>
15 <KeyInfo>certificate</KeyInfo>
16 </SigningKey>
17 <EncryptionKey>
18 <Certificate keystore="trustpoints">.NETcert</Certificate>
19 <KeyInfo>keyidentifier</KeyInfo>
20 </EncryptionKey>
21 <SignBeforeEncrypt>true</SignBeforeEncrypt>
22 <PerformDecryption>true</PerformDecryption>
23 ...
23 </MessageSecurity>
24 </Gate>
The gate is set up using the wizard in the console, but it can also be
hand-edited in the configuration file. In the gateway file extract above, the
gate is defined to connect via HHTP to the .NET service [4]. The response
pipeline (which the response is processed in) will do an X509 chain
validation [7-10] using a trust point ca (which in this example is the
certificate authority that issued the certificates we use).
The outgoing message's security scheme [12-23] is set to be WS-Security [12]
and it will use signing key tg key [14] which is the trust gateway's key. For
encryption, it will use the .NET service's certificate [17-20].
The gate is furthermore defined to sign before it encrypts [21], as well as
to perform decryption of the result [22].
Test run
========
We tested in two ways. First the trust gateway client connected to a .NET
server, and then the .NET server connected to a Trust Gateway protected
resource.
.NET WSE server and client
==========================
We used the stock code from samples that come with the WSE distribution. It
is somewhat trivial to create .NET WSE ASP.NET services and client. A lot
of the WS-* standard processing happens implicitly before your code executes,
which may be a good thing.
Trust Gateway client -> .NET WSE server
=======================================
We use a simple test program to send some XML data into an outflow gate. The
outflow gate described above will take the incoming XML and apply
WS-Security.
When you download the Trust Gateway, there is a tiny helper application you
can use. Remember that .NET services demand a SOAP action to be in the SOAP
headers. In our example we use the default test URI http://tempuri.org/
This command will send the xml into the outflow gate, which will contact the
.NET service, process the results and print it on the console. (The port 8080
is in the gateway configuration file):
$ ../jvm/bin/java -cp tsik.jar com.verisign.messaging.tools.SendXML \
-soapaction "http://tempuri.org" \
http://localhost:8080/echo < test.xml
The result should be the content of test.xml inside a SOAP envelope.
.NET/WSE client -> Trust Gateway server
=======================================
This test uses a .NET client to call into a Trust Gateway inflow gate. The
inflow gates are set up in a similar way as an outflow gate:
1 <Gate loggingLevel="all" name="in with wstest keys">
2 <RequestPipeline/>
3 <ServiceConnector>
4 <Class>EchoServiceConnector</Class>
5 </ServiceConnector>
6 <ResponsePipeline/>
7 <MessageSecurity scheme="wssecurity">
8 <SigningKey>
9 <Key keystore="keys">wsstest2</Key>
10 <KeyInfo>certificate</KeyInfo>
11 </SigningKey>
12 <EncryptionKey>
13 <Certificate keystore="trustpoints">wsstest1</Certificate>
14 <KeyInfo>keyidentifier</KeyInfo>
15 </EncryptionKey>
16 <SignBeforeEncrypt>true</SignBeforeEncrypt>
17 <PerformDecryption>true</PerformDecryption>
18 <PerformResponseEncryption>matchRequest</PerformResponseEncryption>
19 <ExpirationInterval>3600000</ExpirationInterval>
20 </MessageSecurity>
21 </Gate>
The inflow gate is also set up using a console wizard, but can also be
hand-edited. The inflow gate uses no particular request or response
processing [2] and [6]. The lines [3-6] refers to a service connector
implementation. This implementation is a Java class that processes an XML
document and returns a result document. In this sample code, we use the
EchoServiceConnector that ships with the Trust Gateway. It simply echoes its
input as output.
We set up the keys in a similar fashion as we did in the outflow gate. We of
course have to change so that we sign and encrypt with the correct keys that
the client app is instructed to use [8-11] and [12-15]. We also set the gate
to encrypt its responses to match the security of the incoming message [18].
That's pretty much it. The rest, as they say, is left as an excercise for
the reader ;) Feel free to email me with comments/questions.
Thanks,
Hans Granqvist
========
[1] http://www.verisign.com/products/trustgateway
[2] http://www.xmltrustcenter.org/developer/verisign/tsik/index.htm
Mark Chen - 20 Jan 2004 05:29 GMT
It's a good article. Is there any similar article about how to create a X509 certificate used both by J2EE (WebSphere Application Server 5.1) and .NET Web Services.
Thanks in advance!
Mark