Security.insertProviderAt(new MyProvider(), 1);
to add your custom provider programmatically, so you will not have to modifiy your global java configuration :-)
Regards, Rodrigo Ruiz
Stuart Miller wrote:
Gary, thank you very much indeed for this. I will try this out, and post my findings here for others to see (likely early January). I think this is the solution I am looking for, as indeed it provides me with a per-connection customization of key usage.
Interesting that in the javax.net.ssl.X509KeyManager has chooseClientAlias() which takes an array of Issuer Principals (trusted CAs), which certainly will influence the selection process of a client-cert to use. And yet if I'm writing the server-side part of this connection, in SSLServerSocket I cannot seem to specify which Issuer CA's to allow from the client's certs (but I can setEnabledCipherSuites()). Hmmm, I was considering writing a test for my solution which would do just that. Anyway...
Thanks again, Stuart
-----Original Message----- From: Gary L Peskin [mailto:[EMAIL PROTECTED] Sent: Thursday 18 December 2003 21:29 To: [EMAIL PROTECTED] Subject: RE: SecureSocketFactory pluggability?
Hi, Stuart --
Thank you for the explanation. I think I understand what you're trying to do. It seems to me that there is a much better way to go about this. Please bear in mind, however, that I've never actually done this myself so you can take this for what it's worth but I think it bears exploring.
What you are really looking for, as I see it, is to implement your own KeyManager. It is the KeyManager that decides which certification to present to the other side as part of the SSL handshake. You could use a single KeyStore with a single password and have the KeyManager determine which client certificate to present to each partner.
Providing your own KeyManager using JSSE pluggability is documented in an extremely poor fashion but here is what I've been able to glean and surmise from the documentation.
Select your own KeyManagerFactory algorithm. The one provided by Sun is
SunX509 so you could pick anything else. Let's say you use "Anachron".
In your java.security properties file, change
ssl.KeyManagerFactory.algorithm=SunX509
to
ssl.KeyManagerFactory.algorithm=Anachron
Now, you need to write a Master Class for a provider for the
KeyManagerFactory. For this, see
http://java.sun.com/j2se/1.4.2/docs/guide/security/HowToImplAProvider.html#S teps
There is a sample provider shown that you can leverage off of. For example, your master class might be called com.anachron.security.Provider. In the constructor, your provider will "put" the property
KeyManagerFactory.Anachron
and assign it a value that is a classname of a simple class that you will write that extends KeyManagerFactorySpi. We'll call that class com.anachron.security.KeyManagerFactorySpi.
Now, all you need to do is implement the abstract methods of javax.net.ssl.KeyManagerFactorySpi in your class. For the implementation of engineKeyManagers(), you'll return a one entry array consisting of an instance of KeyManager that you'll write which we'll call com.anachron.security.X509KeyManager which, in turn, wraps com.sun.net.ssl.internal.ssl.JsseX509KeyManager. For an idea (only an idea) of how to do this, see the example at:
http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#Ow nX509TM
Note that this example is for a TrustManager, not a KeyManager, but it will give you the general flavor of what to do. Instead of implementing the checkServerTrusted method, you'll implement the chooseClientAlias. When you are called, the SSL drivers will pass you the Socket that you're connecting to as the third argument. In your routine, you should be able to call socket.getRemoteSocketAddress() to see who you're connected to. However, it (obviously) won't show you the URL that has passed over the socket. You might want to stash something in ThreadLocal storage (: or somewhere to let you know where this thread is trying to connect.
Just my thoughts.
Gary
-----Original Message-----
From: Stuart Miller [mailto:[EMAIL PROTECTED] Sent: Thursday, December 18, 2003 8:42 AM
To: '[EMAIL PROTECTED]'
Subject: RE: SecureSocketFactory pluggability?
Gary, thanks for offering to help. Let me try to clarify my problem.
As I understand it, Axis will create HTTPS (SSL) connections transparently, using the underlying JSSE. When the client connects to the server, the SSL connection will receive the server's certificate, which much be trusted in order for the connection to succeed. That means I must have the server-cert's CA in my 'trustStore' (not surprising there). The trustStore is by default the "cacerts" file in $JAVA_HOME/jre/lib/security". If I want to use a different Trust Store, I can set the 'javax.net.ssl.trustStore' System property (and corresponding 'javax.net.ssl.trustStorePassword') in order for JSSE to use the proper store. This is a system-wide setting (per-VM), and hence not changeable for each client within a VM making SSL connections.
Furthermore, if the server challenges me for a client-certificate, JSSE will look for an <<appropriate>> (i am unsure how a cert is selected if there is more than 1) certificate in the default 'keyStore'. Similarly, I can override the default KeyStore with the 'javax.net.ssl.keyStore' (and
javax.net.ssl.keyStorePassword') System properties. I believe that the key/cert in the store must either have the same password as the KeyStore, or else none (if not, how do I pass it in?)
Since I don't want keys/certs with no password in my KeyStore, and I don't want them all to have the same password as the KeyStore itself... I _could_ also create the KeyStore (and TrustStore) dynamically, the following way:
SSLContext.getInstance("SSL").init(keyManagers, trustManagers, secureRandom);
...and hence build a 1-key keyManager and 1 CA trustManager to use, on-demand. Using Axis's generated Java stubs (wsdl2java) I don't have access to the SSL context of the specific connection (and I'm not even sure if I can alter the SSL properties of a single SSL connection), and I don't want to alter the gloabl SSLContext as it will affect other connections which occurr simultaneously.
If I could override the SecureSocketFactory inside JSSE (which JDK1.4 does not let you do), I could write a factory which is pre-configured to use speicific client key/certs and CA certs for specific URLs or hostsnames.
Example:
https://soapserver1.com/ key1 CAx https://soapserver2.net key2 CAy etc...
Since I cannot, my only option _seems_ to be putting all keys in one KeyStore, putting all CA certs in one TrustStore (naturally, this I can live with), and making all keys have the same password, which is that of the KeyStore itself. Then, the SSL connection will figure out which client-certificate to use to establish the session (I don't know how this works, but I suppose a combination of algorithm support and/or Issuer DN??, but there could be more than one acceptable client cert to use).
I didn't know about the 'axis.secureSocketFactory' property (I'm quite new to Axis), but I figured since JSSE won't let me plug in my own, then Axis cannot either. Perhaps this property was used only for people running JDK1.3 + JSSE extension? There is of course the SunJSSESocketFactory provided with Axis, which gives me some customization, though I have no idea if I can use it, nor how to instantiate it with the 'attributes' Hashtable it takes which can hold 'keyStore', 'keyStorePass', etc. Is this coming from AxisClientEngine??
In summary, I need to have each Axis client connection proivde it's own client-cert that it will present to the server, if/when prompted. Is this possible in some (nice, configurable) way? If there is a way, does using generated Stubs leave me with fewer options, without having to edit their source?
Many thanks in advance for any light you can shed on this.
Kind regards, Stuart
-----Original Message----- From: Gary L Peskin [mailto:[EMAIL PROTECTED] Sent: Wednesday 17 December 2003 18:37 To: [EMAIL PROTECTED] Subject: RE: SecureSocketFactory pluggability?
I'd like to understand better what's happening here and I think I can help.
Can you please explain the first few paragraphs in baby steps so that I can understand the exact problem?
Is the problem that you can't specify the socket factory that Axis will use? Have you looked at the properties axis.SocketFactory and axis.socketSecureFactory?
If you could take just a few minutes, it would be great.
Thanks, Gary
secureRandom);-----Original Message----- From: Stuart Miller [mailto:[EMAIL PROTECTED] Sent: Wednesday, December 17, 2003 2:21 AM To: '[EMAIL PROTECTED]' Subject: SecureSocketFactory pluggability?
The Axis framework seems pluggable with respect to
SocketFactories, as was JSSE prior to the JDK 1.4. Now with JDK 1.4, I cannot swap SocketFactory impls (via java.security file) due to US export regulations.
With the out-of-the-box JSSESocketFactory, I can alter the
System properties 'javax.net.ssl.xxx' to point it to my trust/cert stores, and tell it the passwords. However, what if I need a different cert/trust store for each client?
If I could tell Java/Axis to use the SunJSSESocketFactory (or
my own version), then I could build a Hashtable of properties specifying 'keystore' 'keyStorePass', etc. But alas, I cannot with JDK1.4
eg. SecureSocketFactory ssf =
(SecureSocketFactory)SocketFactoryFactory.getFactory("https", myProps);
So I'm left with System.setProperty("javax.net.ssl.xxx", "xyz");
as the only way to tell Aix which CA's to trust and which
client certs it can use. But I assume these properties are only read once.. the first time the SocketFactory for HTTPS is created. Even if not, changing them at run-time is not safe due to multiple clients running at the same time.
Furhtermore, when I use wsdl2java to generate Java stubs, I
seem to be completely insulated from any ability to change SSL environment things such as trustStore and keyStore. It's all automatic and hidden.
Has someone any idea of how I can do what I'm trying to do?
Can I, for example, alter the SSL connection parameters in
the context of some Stub (ie. access the SecureSocket being used)? Something like this...
SSLContext.getInstance("SSL").init(keyMgrs, trustMgrs,
...only synchronized in a way that prevents other clients from connecting with these params until i'm done?
Any help is greatly appreciated. I have connections working
fine, including client-auth, but I [seem to] lack the ability to have different settings for each client in a single VM.
Stuart
