Oracle Advanced Security Administrator's Guide Release 2 (9.2) Part Number A96573-01 |
|
This appendix describes the Oracle implementation of Java Secure Socket Extension (JSSE), in the following sections:
Note: This appendix assumes that you are familiar with the basic principles of Java socket programming and the SSL protocol. |
To use the Oracle Java SSL implementation, perform the following tasks:
CLASSPATH
environment variable includes the following jar files:
CLASSPATH
, then use jssl-1_1.jar
and set the ssl.SocketFactory.provider
and the ssl.ServerSocketFactory
Java security properties as follows:
ssl.SocketFactory.provider=oracle.security.ssl.OracleSSLSocketFactoryImpl ssl.ServerSocketFactory.provider=oracle.security.ssl.OracleSSLServerSocketFactoryImpl
jsse.jar
or jcert.jar
are installed in the Java extensions folder, then jssl-1_1.jar
must also be installed in the extensions folder.
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 a public/private key pair and a certificate request. 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, by choosing Operation >
ExportWallet from the Oracle Wallet Manager menu. This file can be used to add SSL credentials in a Java SSL-based program.
If you are not using Oracle Wallet Manager, then you can manually add individual components to a file:
See Also:
|
Some security-aware applications 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 and 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.
See Also:
"Public Class: OracleSSLCredential" for more information about checking peer credentials |
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.
The complete code for each program is presented, and some of its more important sections are discussed.
Oracle Java SSL examples are described in the following sections:
See Also:
|
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.
The program contains the following code:
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. To read the wallet located at (wltPath)
, initCredential()
calls
_credential = new OracleSSLCredential();
_credential.setWallet(wltPath, password);
The private key, user certificate, certificate and trust points located in the wallet are used in the connection. An IOException is returned if an error occurs while accessing the wallet.
If you do not elect to use the wallet, then you can install the necessary security credentials manually.
See Also:
"Public Class: OracleSSLCredential" for more information about |
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 it is accessed correctly, set up the system properties in the main()
function by using the following settings:
System.getProperties().put("SSLServerSocketFactoryImplClass","oracle.security.ss
l.OracleSSLServerSocketFactoryImpl");
Once the system properties are set, you can obtain an instance of the socket factory and customize it. In initSocketFactory()
, specify the SSL protocol that 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, you can change some of its attributes by modifying the following properties:
_svrSoc.setNeedClientAuth(false);
_svrSoc.setEnabledCipherSuites(new String[]{"SSL_RSA_WITH_RC4_128_SHA"
"SSL_RSA_WITH_RC4_128_MD5"});
For this example, the clients are not required to authenticate themselves to the server. However, instead of using the default enabled cipher suites, only clients that support RSA_WITH_RC4_128_SHA
or SSL_RSA_WITH_RC4_128_MD5
cipher suites are allowed to connect.
Use OracleSSLServerSocketFactory.getSupportedCipherSuites()
to determine which cipher suites are supported by Java SSL.
SSLServerExample
waits until the client connects to the server. The method accept()
blocks until a connection is established. Once the client connects, the output stream for the socket is obtained by calling getOutputStream()
. This output stream is used 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. To stop accepting connections, the server must close the corresponding server socket. The server closes the socket when it cannot accept any further connections.
See Also:
Java documentation about the |
The SSLClientExample
is a simple program used to connect to the SSLServerExample
program by using JDK, version 1.1. The initialization of the SSLClientExample
is very similar to that of the server. However, certain differences are included in this example to demonstrate some of the features of Oracle Java SSL. The explanations focus on these differences whenever appropriate. The example program contains the following code:
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();
}
}
}
Note: If you use JDK, version 1.2, then change |
The client initializes 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 production 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.
See Also:
Chapter 17, "Using Oracle Wallet Manager", for more information about trusted certificates |
The socket factory class used to create client sockets is similar to the one used by the server. As with the SSLServerExample
program, it is necessary to set the system properties to obtain the correct socket factory before configuring it in initSocketFactory()
. The correct socket factory is set in main()
by using the following syntax:
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, to connect the client socket to a specific server, you must supply the server's name and the port number at creation. In addition, ensure that the socket connects in client mode by specifying the following settings:
_socket = (SSLSocket)_socketFactory.createSocket(host, port);
_socket.setUseClientMode(true);
After 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 by using _socket.getSession()
.
In this example, the cipher suite negotiated between the client and the server as well as the security credentials of the server is printed. 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, the socket's input stream is accessed and read until an end-of-line character occurs.
See Also:
Java documentation about their |
This example uses firewall tunneling to establish a secure connection to the server. Note that this program may 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("Failed to start up client");
i.printStackTrace();
}
}
}
Note: If you use JDK, version 1.2, then change |
The only significant difference between SSLProxyClientExample
and its superclass, SSLClientExample
, lies in the method initSocket()
. 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, by setting up the connection to the actual server. Once this connection is set up, use the plain socket to initialize an SSL Socket by using the following syntax:
_socketFactory.createSocket(normalSocket)
This section describes some typical Java SSL errors.
During the handshake the program fails with an SSLException
and returns the message X509CertExpiredErr
. The program worked previously and no changes were made.
Cause: Your user certificate has expired.
Action: You must obtain a new user certificate.
The handshake fails on the client side with SSLException
and returns the message X509CertChainInvalidErr
. A Web browser can connect to the server successfully.
Cause: Either your server or your client does not have the proper credentials.
Action: If the client program sets trusted certificates, then 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 because Oracle Java SSL cannot build the certificate chain itself. If you are using an Apache server, then you must set the variables SSLCertificateChainFile
and SSLCertificateFile
correctly. This is especially important if the client program does not set trusted certificates.
The handshake succeeds even though no OracleSSLCredentials
are set in the client program.
Cause: To enable security-aware applications to perform their own validation, Oracle Java SSL permits a connection if no credentials are set by the client, but only if the server sends a complete certificate chain.
Action: To avoid this behavior, you must set at least one trusted certificate in your application.
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:
A description of JSSE classes located at: http://java.sun.com/products/jsse/doc/apidoc/index.html |
This public class extends java.lang.Object
.
Credentials are used to authenticate the server and the client to each other. The OracleSSLCredential
class 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
credential. 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 X.509 certificate.
public void addTrustedCert(byte[] trustedCert)
Adds a trusted certificate to the credential
Parameters: trustedCert
- A der
encoded X.509 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 X.509 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 X.509 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 X.509 certificate
public void addCertChain(byte[] certChainCert)
Adds a certificate to the certificate chain.
Parameters: certChainCert
- A der
encoded X.509 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 Oracle Java SSL. 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 path name of the wallet
This interface defines the available SSL protocol versions.
public static final int SSL_Version_Undetermined
SSL protocol version undetermined
public static final int SSL_Version_3_0_With_2_0_Hello
SSL protocol version 3.0 with 2.0 hello
public static final int SSL_Version_3_0_Only
SSL protocol version 3.0 only
public static final int SSL_Version_2_0
SSL protocol version 2.0
public static final int SSL_Version_3_0
SSL protocol 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 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(OracleSSLCredentialsslCredential)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 returns 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 the java.lang.Object
class. It implements the javax.net.ssl.SSLSession
interface.
This class implements most methods specified in javax.net.ssl.SSLSession
. However, the following methods are not implemented with this class:
This class provides extra methods that are specific to Oracle Java SSL, which are described in the following sections.
public byte[][] getPeerRawCertificateChain() throws javax.net.ssl.SSLPeerUnverifiedException
Returns the certificate chain presented by the peer as an array of peer X.509 certificates in der
format. The peer's certificate is first in the chain, and the root CA is last. The method returns a javax.net.ssl.SSLPeerUnverifiedException
if the peer certificate cannot be verified.
public java.lang.String getNegotiatedProtocolVersion()
Returns the SSL protocol version used for this session.
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 in the following sections, 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 SSL socket that reads and writes by using an existing socket. This is particularly useful when tunneling through firewalls. The method returns 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(OracleSSLCredentialsslCredential) 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. This method also creates and sets a default OracleX509TrustManager
with the same trust points as in the OracleSSLCredential
. 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.
public void setTrustManagers(OracleX509TrustManagerInterface[] tm)
Sets the OracleX509TrustManagers
that are to be used for sockets created by this factory.
Parameter: tm
- an array of trust managers
public OracleX509TrustManagerInterface[] getTrustManagers()
Returns the X509TrustManagers that are set for this factory.
This public interface extends javax.net.ssl.TrustManager
. It is based on javax.net.ssl.X509TrustManager,
but it does not inherit from that interface.
This interface builds a valid certificate chain and manages which X.509 certificates may be used to authenticate the remote side of a secure socket. Decisions may be based on trusted certificate authorities, certificate revocation lists, online status checking or by other means that are specified. This function is called if trusted certificates are set and one of the following conditions are met:
public abstract void checkClientTrusted(X509Certificate[] chain) throws CertificateException
Given the partial or complete certificate chain that is provided by the peer, this method builds a certificate path to a trusted root and returns if it can be validated and is trusted for client SSL authentication. The method throws a javax.net.ssl.CertificateException
if the certificate chain is not trusted by this trust manager.
Parameters: chain
- an ordered array of peer X.509 certificates with the peer's own certificate listed first and followed by any certificate authorities
public abstract void checkServerTrusted(X509Certificate[] chain) throws CertificateException
Given the partial or complete certificate chain that is provided by the peer, this method builds a certificate path to a trusted root and returns if it can be validated and is trusted for server SSL authentication. This method throws a javax.net.ssl.CertificateException
if the certificate chain is not trusted by this trust manager.
Parameters: chain
- an ordered array of peer X.509 certificates with the peer's own certificate listed first and followed by any certificate authorities
public abstract X509Certificate[] getAcceptedIssuers()
This method returns an array of certificate authority certificates that are trusted for the authenticating peers. It returns a non-null (possibly empty) array of acceptable certificate authority issuer certificates.
|
Copyright © 1996, 2002 Oracle Corporation. All Rights Reserved. |
|