Oracle Advanced Security Administrator's Guide Release 9.0.1 Part Number A90150-01 |
|
This appendix describes the Oracle implementation of Java Secure Socket Extension (JSSE), in the following sections:
To use the Oracle Java SSL implementation, JDK version 1.1 or 1.2 must be installed, and the CLASSPATH environment variable must include the following jar files:
In addition, the Java SSL shared library must be added to the shared library path:
libnjssl8.so
must be included in the library path specified by the LD_LIBRARY_PATH environment variable.
njssl8.dll
must be included in the path specified by the PATH environment variable.
Oracle Java SSL is a commercial-grade implementation of Java Secure Socket Extension (JSSE). In order to create a secure, fast implementation of SSL, Oracle Java SSL uses native code to improve the performance.
In addition to the functionality included in the JSSE specifications, Oracle Java SSL supports the following:
Oracle Java SSL features are described in further detail in the following sections:
Before data can flow through an SSL connection, both sides of the connection must negotiate common algorithms to be used for data transmission. A set of such algorithms combined to provide a mix of security features is called a cipher suite. Selecting a particular cipher suite lets the participants in an SSL connection establish the appropriate level for their communications.
Oracle Java SSL supports cipher suites with the following options:
You can use Oracle Wallet Manager to generate public/private key pairs and certificate requests. A signed certificate request and the appropriate trusted certificates must be added to produce a complete Oracle wallet.
You can export a complete wallet with a certificate in Ready status, in a BASE64-formatted file, using the menu option Operation ->ExportWallet. This file can be used to add SSL credentials in a Java SSL-based program.
If you are not using Oracle Wallet Manager, you can manually add individual components to a file:
See Also:
|
Some security-aware application do not set trust points. In order to let these applications perform their own validation, Oracle Java SSL lets handshakes complete if no security credentials are set--if a complete certificate chain is sent by the peer. This feature is useful when there is a large number of trust points stored in a database, and the application is constrained from passing all of them to the SSL layer.
Once the handshake is complete, it is possible to obtain the peer certificate chain and extract individual peer certificates. These certificates can be used for application-specific validation, such as matching the certificate's distinguished name (DN) against a user database.
Security-unaware applications that need the trust point check must ensure that trust points are set in the application.
The examples in this section illustrate the use of Oracle Java SSL. For purposes of the examples, we created a model server and client named SSLServerExample and SSLClientExample, respectively. Together, they demonstrate some common features of Oracle Java SSL, as well as the basics of socket communication. In addition, SSLProxyClientExample demonstrates one of the possible ways to implement firewall tunnelling connections.
We present the complete code for each program, and discuss some of its more important sections.
This example does not cover every feature available in Oracle Java SSL. For more detailed information about different security options available in this package please consult the latter sections of this chapter.
See Also:
|
Oracle Java SSL examples are described in the following sections:
SSLServerExample is a simple SSL server. It uses a wallet exported from Oracle Wallet Manager to set up its security credentials. When the server is started it waits for a client to initiate a connection. After the SSL handshake is complete, the server sends a short message to the client and closes the connection.
import oracle.security.ssl.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.net.*;
import javax.net.ssl.*;
public class SSLServerExample
{
private OracleSSLServerSocketFactoryImpl _socketFactory;
private OracleSSLCredential _credential;
private SSLServerSocket _svrSoc;
private void initCredential(String wltPath, String password)
throws java.io.IOException
{
_credential = new OracleSSLCredential();
_credential.setWallet(wltPath, password);
}
private void initSocketFactory()
throws javax.net.ssl.SSLException
{
_socketFactory
= (OracleSSLServerSocketFactory)SSLServerSocketFactory.getDefault();
_socketFactory.setSSLProtocolVersion(
OracleSSLProtocolVersion.SSL_Version_3_0_With_2_0_Hello);
_socketFactory.setSSLCredentials(_credential);
}
private void initServerSocket(int port)
throws java.io.IOException
{
_svrSoc = (SSLServerSocket)_socketFactory.createServerSocket(port);
_svrSoc.setUseClientMode(false);
_svrSoc.setNeedClientAuth(false);
_svrSoc.setEnabledCipherSuites(new String[]{"SSL_RSA_WITH_RC4_128_SHA",
"SSL_RSA_WITH_RC4_128_MD5"});
}
public SSLServerExample(String wltPath, String password, int port)
throws java.io.IOException, javax.net.ssl.SSLException
{
initCredential(wltPath, password);
initSocketFactory();
initServerSocket(port);
}
public void runServer()
{
String message = "Hello! Current Server Time is " + new Date() + "\n";
Socket csocket = null;
OutputStreamWriter out = null;
try
{
csocket = _svrSoc.accept();
out = new OutputStreamWriter(csocket.getOutputStream());
out.write(message);
System.out.println("Connection Succeeded");
}
catch(IOException e)
{
System.out.println("Connection Failed");
e.printStackTrace();
}
finally
{
try
{
if(out != null)
out.close();
if(csocket != null)
csocket.close();
_svrSoc.close();
}
catch(IOException e){}
}
}
public static void main(String[] argv)
{
System.getProperties().put("SSLServerSocketFactoryImplClass",
"oracle.security.ssl.OracleSSLServerSocketFactoryImpl");
try
{
SSLServerExample myServer = new SSLServerExample("mywallet.txt",
"welcome1", 19978);
myServer.runServer();
}
catch(IOException i)
{
System.out.println("Failied to start up server");
i.printStackTrace();
}
}
}
SSLServerExample uses a wallet created by Oracle Wallet Manager, so the job of setting up the credential object is quite easy. In initCredential()
we call
_credential = new OracleSSLCredential();
_credential.setWallet(wltPath, password);
to read the wallet located at wltPath
. The private key, user certificate, certificate and trust points located in the wallet are used in the connection. An IOException is thrown if an error occurs while accessing the wallet.
If you do not elect to use the wallet, you can install the necessary security credentials manually.
To create SSL sockets, you must access the proper socket factory. For Oracle Java SSL, oracle.security.ssl.OracleSSLSocketFactoryImpl
is the name of the class that implements javax.net.ServerSocketFactory.
In order to make sure we access it correctly we must set up the System Properties in the main()
function using
System.getProperties().put("SSLServerSocketFactoryImplClass","oracle.security.ss l.OracleSSLServerSocketFactoryImpl");
Once the system properties are set, we can obtain an instance of the socket factory and customize it. In initSocketFactory()
we specify the SSL protocol the sockets created by this factory are to support, and install the security credentials to be used by all sockets created by this factory.
The method initServerSocket()
uses the socket factory to create a new server socket that listens in server mode on the specified port:
_svrSoc = (SSLServerSocket)_socketFactory.createServerSocket(port);
_svrSoc.setUseClientMode(false);
Once the socket is created, we can change some of its attributes:
_svrSoc.setNeedClientAuth(false);
_svrSoc.setEnabledCipherSuites(new String[]{"SSL_RSA_WITH_RC4_128_SHA"
"SSL_RSA_WITH_RC4_128_MD5"});
For this example we do not require the clients to authenticate themselves to the server. However, instead of using the default enabled cipher suites, we only let those clients connect that support RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_MD5 cipher suites.
Use OracleSSLServerSocketFactory.getSupportedCipherSuites()
to determine which cipher suites are supported by Java SSL.
SSLServerExample waits until the client connects to the server. Notice that the method accept()
blocks until a connection is established. Once the client connects we obtain the output stream for the socket by calling getOutputStream().
We use this output stream to send information to the client. When the server has no more data to send to the client, the server closes the corresponding output stream and socket. In order to stop accepting connections, the server must close the corresponding server socket. The server closes the ServerSocket when it cannot accept any further connections.
The SSLClientExample is a simple program (JDK1.1) used to connect to the SSLServerExample program. Notice that the initilization of the SSLClientExample is very similar to that of the server. However, certain differences have been included in this example to demonstrate some of the features of JavaSSL. The explanations focus on these differences whenever appropriate:
import oracle.security.ssl.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.net.*;
import javax.net.ssl.*;
import javax.security.cert.*;
public class SSLClientExample
{
protected OracleSSLSocketFactoryImpl _socketFactory;
private OracleSSLCredential _credential;
protected SSLSocket _socket;
private void initCredential(String wltPath, String password)
throws java.io.IOException
{
_credential = new OracleSSLCredential();
_credential.setWallet(wltPath, password);
}
private void initSocketFactory()
throws javax.net.ssl.SSLException
{
_socketFactory
= (OracleSSLSocketFactoryImpl)SSLSocketFactory.getDefault();
_socketFactory.setSSLProtocolVersion(
OracleSSLProtocolVersion.SSL_Version_3_0);
_socketFactory.setSSLCredentials(_credential);
}
private void initSocket(String host, int port)
throws java.io.IOException
{
_socket = (SSLSocket)_socketFactory.createSocket(host, port);
_socket.setUseClientMode(true);
}
public SSLClientExample(String wltPath, String pass, String host, int port)
throws java.io.IOException, javax.net.ssl.SSLException
{
initCredential(wltPath, pass);
initSocketFactory();
initSocket(host, port);
}
public void connectSocket()
{
try
{
_socket.startHandshake();
getData();
}
catch(IOException e)
{
System.out.println("Connection Failed");
e.printStackTrace();
}
finally
{
try
{
_socket.close();
}
catch(IOException e){}
}
}
public void getData()
{
InputStreamReader in = null;
try
{
int ch;
SSLSession session = _socket.getSession();
System.out.println("Negotiated Cipher Suite " +
session.getCipherSuite());
X509Certificate[] peerCerts = session.getPeerCertificateChain();
for(int i = 0; i < peerCerts.length; i++)
{
System.out.println(peerCerts[i]);
}
System.out.println("Server Response:");
in = new InputStreamReader(_socket.getInputStream());
ch = in.read();
while((char)ch != '\n')
{
if(ch != -1)
System.out.print((char)ch);
ch=in.read();
}
System.out.println();
}
catch(IOException e)
{
System.out.println("Connection Failed");
e.printStackTrace();
}
finally
{
try
{
if(in != null)
in.close();
}
catch(IOException e){}
}
}
public static void main(String[] argv)
{
System.getProperties().put("SSLSocketFactoryImplClass",
"oracle.security.ssl.OracleSSLSocketFactoryImpl");
try
{
SSLClientExample myClient = new SSLClientExample("mywallet.txt","welcome1","localhost", 19978);
myClient.connectSocket();
}
catch(IOException i)
{
System.out.println("Failied to start up client");
i.printStackTrace();
}
}
}
The client intializes the credentials in the same way as the server. For purposes of the example, the client and the server use the same wallet. However, in real life applications the client and the server must have different security credentials. In order for an SSL connection to complete successfully it is important that the proper trusted certificates are present in the wallets.
The socket factory class used to create client sockets is similar to the one used by the server. Once again it is necessary to set the system properties in order to obtain the correct socket factory before configuring it in initSocketFactory()
. The correct socket factory is set in main()
using:
System.getProperties().put("SSLSocketFactoryImplClass",
"oracle.security.ssl.OracleSSLSocketFactoryImpl");
Client sockets are created by the socket factory just as server sockets are created by the server socket factory. However, in order to connect the client socket to a specific server, we supply the server's name and the port number at creation. In addition, we ensure that the socket connects in client mode:
_socket = (SSLSocket)_socketFactory.createSocket(host, port);
_socket.setUseClientMode(true);
Once the socket is created it can connect to the server using:
_socket.startHandshake();
After the socket connects to the server, information about the connection can be accessed. The information is stored in the OracleSSLSession class, an instance of which can be obtained using _socket.getSession().
In our program we print out the cipher suite negotiated between the client and the server as well as the security credentials of the server. This information can be used by security-aware applications to determine whether it should trust the connection. For example, most browsers check to confirm that the common name in the server certificate matches the URL that was accessed, and they display a warning if it does not. However, this check is not required by the SSL protocol.
Receiving and sending data through an SSL Socket is no different than receiving data through any other socket. In this example we access the socket's input stream, and proceed to read until an end-of-line character occurs.
SSLProxyClientExample uses firewall tunneling to establish a secure connection to the server. Please note that this program might not work for all firewalls. For example, some firewalls do not permit a connection to non-standard ports, such as port 19978 that is used here. In this case you have to set up a secure server on port 443 and modify the client appropriately.
import oracle.security.ssl.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.net.*;
import javax.net.ssl.*;
import javax.security.cert.*;
public class SSLProxyClientExample extends SSLClientExample
{
private String _proxyName;
private int _proxyPort;
protected void initSocket(String host, int port)
throws java.io.IOException
{
final String connString = "CONNECT" + host + ":" + port +
" HTTP/1.0 \n" + "User-Agent: Oracle Proxy Enabled SSL Socket\n\n";
Socket normalSocket = new Socket(_proxyName, _proxyPort);
OutputStreamWriter out
= new OutputStreamWriter(normalSocket.getOutputStream());
out.write(connString, 0, connString.length());
_socket = (SSLSocket)_socketFactory.createSocket(normalSocket);
}
public SSLProxyClientExample(String wltPath, String password,String host,
int port, String proxyName, int proxyPort)
throws java.io.IOException, javax.net.ssl.SSLException
{
super(wltPath, password, host, port);
_proxyName = proxyName;
_proxyPort = proxyPort;
}
public static void main(String[] argv)
{
System.getProperties().put("SSLSocketFactoryImplClass", "oracle.security.ssl.OracleSSLSocketFactory");
try{
SSLClientExample myClient
= new SSLProxyClientExample("mywallet.txt", "welcome1",
"localhost", 19978, "www-proxy", 80);
myClient.connectSocket();
}
catch(IOException i)
{
System.out.println("Failied to start up client");
i.printStackTrace();
}
}
}
The only significant difference between SSLProxyClientExample and its superclass, SSLClientExample, lies in the method initSocket().
In order to set up a tunnelling connection it is necessary to create a plain socket. This socket is used to send a special message, connString,
to the firewall, setting up the connection to the actual server. Once this connection is set up, we can use the plain socket to initialize an SSL Socket using:
_socketFactory.createSocket(normalSocket)
This section describes some typical Java SSL errors.
During the handshake the program fails with SSLException and message X509CertExpiredErr.
The program worked yesterday, and no changes were made.
Your user certificate has expired. You must obtain a new user certificate.
The handshake fails on the client side with SSLException and message X509CertChainInvalidErr.
A web browser can connect to the server successfully.
Either your server or your client does not have the proper credentials. If the client program sets trusted certificates, you must ensure that the list includes at least one of the certificates in the server's certificate chain. In addition you must ensure that the server sends the complete certificate chain to the client--as Java SSL cannot build the certificate chain itself. If you are using an Apache server, you must set the variables SSLCertificateChainFile
and SSLCertificateFile
correctly. This is especially important if the client program does not set trusted certificates.
For more information consult your web server documentation.
Server lets client connect even though no OracleSSLCredentials
are set in the client program.
In order to enable security-aware applications to perform their own validation, Java SSL permits a connection if no credentials are set by the client, if the server sends a complete certificate chain. To avoid this behavior, your application must set at least one trusted certificate.
This section describes the public classes and interfaces used in Oracle Java SSL. Since Oracle Java SSL is an implementation of JSSE, only the Oracle additions to the JSSE package are described.
This section describes the following Oracle Java SSL classes and interfaces:
See Also:
http://java.sun.com/products/jsse/doc/apidoc/index.htm
l, for a description of JSSE classes.
This public class extends java.lang.Object.
Credentials are used to authenticate the server and the client to each other. OracleSSLCredential is used to load user certificates, trusted certificates (trust points), and private keys from base64 or der encoded certificates.
public
OracleSSLCredential
()
Creates an empty OracleSSCredential. An empty credential lets the socket connect to any peer that sends a complete certificate chain during the handshake.
public void
addTrustedCert
(java.lang.String b64TrustedCert)
Adds a trusted certificate to the credential.
Parameters: b64TrustedCert
- A Base64 encoded X509 certificate.
public void
addTrustedCert
(byte[] trustedCert)
Adds a trusted certificate to the credential.
Parameters: trustedCert
- A der encoded X509 trusted certificate.
public void
setPrivateKey
(java.lang.String b64PvtKey,
java.lang.String password)
Adds a private key to the credential.
Parameters: b64PvtKey
- A Base64 encoded X509 Private Key
password
- The password needed to decipher the private key.
public void
setPrivateKey
(byte[] pvtKey,
java.lang.String password)
Adds a private key to the credential.
Parameters: b64PvtKey
- A der encoded X509 Private Key
password
- The password needed to decipher the private key.
public void
addCertChain
(java.lang.String b64certChainCert)
Adds a certificate to the certificate chain. The certificate chain is sent along with the user certificate during the SSL handshake. It is used by the peer to verify the user certificate. The first certificate added to the certificate chain must be the Root CA certificate. Each subsequent certificate added must be signed by its immediate predecessor.
Parameters: b64certChainCert
- A Base64 encoded X509 certificate.
public void
addCertChain
(byte[] certChainCert)
Adds a certificate to the certificate chain.
Parameters: certChainCert
- A der encoded X509 certificate.
public void
setWallet
(java.lang.String wltPath,
java.lang.String password) throws java.io.IOException
If Oracle Wallet Manager is used to create a wallet, the wallet can be exported in text format and used by JavaSSL. The text file must contain the user certificate, followed by the private key, the certificate chain, and any other trusted certificates. The method throws a java.io.IOException
if the wallet cannot be opened.
Parameters: wltPath
- The pathname of the wallet
This interface defines the available SSL protocol versions.
public static final int
SSL_Version_Undetermined
public static final int
SSL_Version_3_0_With_2_0_Hello
public static final int
SSL_Version_3_0_Only
public static final int
SSL_Version_2_0
public static final int
SSL_Version_3_0
This public class extends javax.net.ssl.SSLServerSocketFactory; it is used to create SSL server sockets.
This class implements javax.net.ssl.SSLServerSocketFactory methods
that are needed to create server sockets. In addition it provides extra methods, described bellow, that are necessary to configure options specific to Oracle Java SSL.
public
OracleSSLServerSocketFactoryImpl
()
Creates a socket factory that may be used to create sockets. However, setting the system property SSLServerSocketFactoryImplClass to oracle.security.sslOracleSSLServerSocketFactoryImpl is the preferred method for creating socket factories. For example:
System.getProperties().put("SSLServerSocketFactoryImplClass",
"oracle.security.ssl.OracleSSLServerSocketFactoryImpl");
SSLServerSocketFactory factory = OracleSSLServerSocketFactoryImpl.getDefault();
public void
setSSLCredentials
(OracleSSLCredential
sslCredential)throws javax.net.ssl.SSLException
Sets the OracleSSLCredential (holding private keys, certificate chains, and similar data) that is to be used for the SSL connection. The method throws a javax.net.ssl.SSLSocketException
if an error occurs.
public void
setSSLProtocolVersion
(int version)
throws javax.net.ssl.SSLException
Sets the SSL protocol version. The method throws a javax.net.ssl.SSLSocketException
if the SSL version is not supported.
This public class extends java.lang.Object; implements javax.net.ssl.SSLSession.
This class implements most methods specified in javax.net.ssl.SSLSession
. However, the following methods have not been implemented: getPeerHost(), getValue(), invalidate(), removeValue(),
and getValueNames()
. This class provides extra methods, described bellow, that are specific to Oracle Java SSL.
public byte[][]
getPeerRawCertificateChain
()
throws javax.net.ssl.SSLPeerUnverifiedException
Returns the certificate chain presented by the peer as and array of peer X.509 certificates in der format. The peer's certificate is first in the chain, and the root CA last. The method throws a javax.net.ssl.SSLPeerUnverifiedException
if the peer certificate could not be verified
public java.lang.String
getNegotiatedProtocolVersion
()
This public class extends javax.net.ssl.SSLSocketFactory.
This class implements javax.net.ssl.SSLSocketFactory
methods that are needed to create server sockets. In addition it provides extra methods, described below, that are necessary to configure options specific to Oracle Java SSL.
public
OracleSSLSocketFactoryImpl
()
Creates a socket factory that may be used to create sockets. However, setting the system property SSLSocketFactoryImplClass to oracle.security.sslOracleSSLSocketFactoryImpl is the preferred method for creating socket factories. For example:
System.getProperties().put("SSLSocketFactoryImplClass",
"oracle.security.ssl.OracleSSLSocketFactoryImpl");
SSLSocketFactory factory = OracleSSLSocketFactoryImpl.getDefault();
public java.net.Socket createSocket(java.net.Socket socket)
throws java.io.IOException
Returns a new instance of an SSLSocket that will read and write using an existing socket. This is particularly useful when tunneling through firewalls. The method throws a java.io.IOException
if an error occurs while creating the socket.
Parameters: socket
- a socket object through which data will be transferred
public void
setSSLCredentials
(OracleSSLCredential
sslCredential)throws javax.net.ssl.SSLException
Sets the OracleSSLCredential (holding private keys, certificate chains, and similar data) that is to be used for the SSL connection. The method throws a javax.net.ssl.SSLSocketException
if an error occurs.
public void
setSSLProtocolVersion
(int version)
throws javax.net.ssl.SSLException
|
Copyright © 1996-2001, Oracle Corporation. All Rights Reserved. |
|