3 Pure Java SSL Design

advertisement
Java SSL Implementation
May 12, 1999
Richard Cardone
I’ve implemented a functioning subset of the Secure Sockets Layer
(SSL) protocol in pure Java with the ultimate goal of distributing a nonproprietary version of SSL. To test whether this implementation
performs at a practical level, other project members have performed a
number of comparative performance tests and reported their results in a
separate document.
1 Introduction
Distributed applications, especially those that span wide area networks, require a level of authentication,
data integrity and data privacy only available through the sophisticated use of a combination of
cryptographic algorithms. Some applications use encrypted communication links, but many important
classes of applications--such as those that use the Internet--cannot depend on secure networks. For these
applications, there’s a requirement for a secure transport layer protocol that also delivers good performance
and ease of programming. The Secure Sockets Layer (SSL) protocol has proven its utility and flexibility
by providing robust security at the transport layer in distributed applications and, especially, in web
browsers.
Programmers writing in C/C++ can download proven SSL implementations from the web for free. Among
the most prominent implementations is SSLeay, authored by Andrew Young [1], and SSLREF from
Netscape [2]. For Java programmers, a number of commercially available pure Java implementations of
SSL exist, but their cost can be substantial and licensing policies restrictive [3,4]. Java programmers could
build their own JNI/SSLeay library, but this would sacrifice portability. There is at least one SSLeay-based
implementation available on the web for free, but requires modifications to the standard Java sockets
library source code in addition to restricting portability.
The initial project motivation was to provide a functioning, pure Java version of SSL so that secure,
distributed Java applications could be built using a standard protocol. To determine if such an
implementation would actually be practical in real world usage, we wanted to compare the performance of
the pure Java implementation to other implementation approaches. Specifically, we wanted to see if a
C/C++ implementation of SSL called from Java using JNI would provide better performance. We also
wanted to how the pure Java implementation performed with and without JIT compilation and under native
compilation. We would also like to benchmark all the Java implementations and runtime environments
against a C/C++ compiled implementation.
At this time, a pure Java version subset of the SSL protocol has been implemented. The two cipher suites
supported allow valid performance testing to take place. We were unable to implement a JNI version of
SSL in time, so no comparisons can be made between the two Java implementation approaches. Francois
Caen and Malcolm Haynes have reported in a separate document the results of their performance testing.
The next section introduces the SSL protocol from an architectural point of view. The following sections
discuss the design and implementation of our pure Java implementation, the results of our performance
tests and our conclusions.
1
2 Background
2.1
SSL Architecture
SSL Architecture
SSL
SSL Change
Handshake
Cipher Spec
Protocol
Protocol
SSL Alert
Protocol
Application
Data
Protocol
SSL Record Layer
TCP
IP
Figure 1. The SSL Record and Message Protocol Layers (Stallings [5]).
The SSL Architecture is defined as two layers that reside just above the transport in the TCP/IP protocol
stack. All SSL messages originate in one of the message protocol modules and pass through the SLL
Record Layer. The record layer handles physical record blocking and applies cryptographic
transformations. Taken together, the four modules in the upper SSL layer form the Message Protocol
Layer. All SSL input and output takes the form of messages defined by one of these four protocol modules.
The Handshake Protocol establishes the security characteristics of an SSL session. Handshake messages
negotiate the session’s cryptographic parameters and perform client/server authentication. The Change
Cipher Spec Protocol is a one-message protocol used during the handshake negotiation. Its sole purpose is
to signal that the newly negotiated cipher suite is now in effect. SSL Alert messages report status between
communicating peers to indicate errors or normal connection termination. Application Data Protocol
messages contain user data protected according to the current cryptographic parameters.
The SSL Architecture does not specify any application programming interface. Each implementation is
free to devise its own interface allowing clients to send and receive SSL messages. Accordingly, SSL
implementations are not interchangeable from an application point of view.
SSL makes a distinction between sessions and connections. A connection is an actual TCP connection
between a client and server. The active connection initiator is always assigned the client role. On the other
hand, an SSL session is an agreed upon set of cryptographic and non-cryptographic parameters. When a
connection is initiated, the client can negotiate a new session or request that a previously negotiated session
be re-used. Thus, sessions can outlive the connection under which they were created. Also, multiple
connections can simultaneously participate in or use the same SSL session. Both the client and server
must cache sessions if they are going to be re-used. Session re-use allows an abbreviated handshake
protocol to be performed that avoids running the computationally intensive key exchange algorithm.
The SSL specification also allows client and server applications to re-negotiate a session’s parameters
anytime after the initial handshake completes. Application data messages may continue to flow during renegotiations. During any handshake negotiation, the client and server agree upon a cipher suite which
2
specifies a key exchange algorithm, a MAC algorithm and a cipher algorithm. The cryptographic
parameters generated under the cipher suite are known as the cipher spec.
2.1.1 SSL Record Layer
SSL Record Layer
Data
Fragment
Compress
Add MAC
Encrypt
Add Header
Figure 2. The Record Layer (Stallings [5]).
The SSL Record Layer interacts directly with TCP on the protocol stack. Figure 2 illustrates how data
written from the Message Protocol layer to the network is processed by the Record layer. The data is first
fragmented into blocks no larger than 214 (16384) bytes. Each block is then compressed to 2 14 + 1024 bytes
or less (hopefully compression will not actually expand the data very often) 1. At this point, the compressed
data block is hashed with a secret key to form a MAC as specified by the session’s current cipher suite.
The MAC is then appended to the compressed data block and both are encrypted, again in accordance with
the current cipher suite. The final result cannot be larger than 2 14 + 2048 bytes in length. A small header is
then appended to the front of the block before it is transmitted to the TCP layer. The Record layer
processing in the receiving application performs the inverse operations in reverse order to decode the SSL
message.
1
Currently, SSL defines no compression algorithms other than the null algorithm.
3
2.1.2 SSL Handshake Protocol
SSL Handshake Protocol
Client
Server
ClientHello
ServerHello
Certificate *
ServerKeyExchange *
CertificateRequest *
ServerHelloDone
Certificate *
ClientKeyExchange
CertificateVerify *
[ChangeCipherSpec]
Finished
[ChangeCipherSpec]
Finished
Application Data
Application Data
Figure 3. The new session handshake (SSL Specification [7]).
The typical handshake protocol consists of the above sequence of messages. Note that a full handshake
requires essentially two round trip message batches before application data can be securely transmitted with
the newly negotiated cipher suite. Messages in Figure 3 annotated with an asterisk are optional messages
that may be exchanged depending on the negotiation.
2.1.2.1
Cipher Spec Selection
The client begins the handshake message by sending a ClientHello message which contains a timestamp, a
block of 28 pseudo-random bytes, and the client’s list of preferred cipher suites. If a previously negotiated
session is to be re-used, the client also sends a non-null session id. The server responds to the ClientHello
message with a ServerHello message. The response contains a server timestamp, the server’s block of 28
pseudo-random bytes, the cipher suite selected by the server from the client’s list, the session id, and
optional key exchange data.
If the session chosen by the server was previously negotiated, then the server follows immediately with its
ChangeCipherSpec and Finalize messages. The client will respond by sending ChangeCipherSpec and
Finalize messages. If all validation checking is successful, application data can be transmitted securely
under the pre-established session. Note that session re-use skips the secret key exchange and authentication
processing steps.
If the client requests a new session be negotiated or if the server decides to negotiate a new session,
authentication and secret key exchange must be performed before final session validation can occur.
2.1.2.2
Secret Key Exchange
SSL specifies a number of key exchange algorithms that can be used to generate shared secret material.
This material is then used to generate keys and initialization vectors for use in MAC processing and
encryption. Depending on the cipher suite chosen, key exchange information may be included in the
ServerHello and/or the optional ServerKeyExchange message. The client will always respond with a
ClientKeyExchange message to allow the key exchange algorithm to be run to completion on both client
and server.
4
2.1.2.3
Authentication
SSL specifies cipher suites that allow for anonymous, server authenticated and mutually authenticated
sessions. The exchange of optional Certificate, CertificateRequest and CertificateVerify message permits
the required level of authentication to be carried out using X.509v3 certificates.
2.1.2.4
Change Cipher Spec
After all authentication and key exchange processing has completed, each party sends the
ChangeCipherSpec and Finalize messages to the other. Figure 3 describes this message exchange during
new session handshakes; the server transmits first during re-used session handshakes. In all negotiations,
the ChangeCipherSpec message tells the receiver that all subsequent data read from this connection will use
the just agreed upon cipher specifications. The Finalize message is always the first message sent using the
new session parameters and is used to validate that both parties have participated in the negotiation and
share the same secret information. This validation processing will be described in more detail in section
“Integrity and Privacy” on page 5.
2.2
Secret Material Generation
Generating Secrets
RSA
Diffie-Hellman
Fortezza
Pre-Master-Secret
Master Secret
Key-Block Material
Keys/IV
Figure 4. Shared secret material.
The result of any of the three supported key exchange algorithms is known as the SSL pre-master secret.
To generate the master secret, the pre-master secret is hashed six times using both MD5 and SHA. Client
and server random values from the Hello messages, along with nonces that vary on each hash, are also used
as input into each hash. In the end, the generated master secret is a 48 byte array of shared, secret material.
The master secret, along with the client and server random values and other nonces, is then hashed using
SHA. The resultant 20 byte value is then hashed again with the master secret using MD5 to yield a 16 byte
result. The whole procedure is repeated (with varying nonces) as many times as necessary to generate
enough secure material for a cipher write key, a MAC write key and a write initialization vector (needed for
certain block cipher modes) for both the client and the server. The selected cipher suite determines the
exact size of each of these six entities and, therefore, the number of hash iterations that must be performed.
2.2.1 Integrity and Privacy
The Finalize message terminates the handshake protocol. It’s used to validate that both parties share the
same secrets and can encrypt and decrypt using the newly agreed upon cipher suite. The data contained in
5
the Finalize message consists of an MD5 hash and an SHA hash. The data hashed in each case includes the
master secret, a number of nonces, and all previous handshake messages that occurred during the
negotiation. Hashing all previous handshake messages deters attacks in which messages are changed en
route. Any message tampering will cause the receiver to calculate a different set of Finalize hashes than the
sender.
As with all messages, the contents of the Finalize message are then hashed during MAC processing in the
record layer. This MAC hash includes as input the message sequence number along with the appropriate
secret MAC write key. Read and write sequence numbers are maintained and incremented by each party
on a connection. Hashing the appropriate sequence number in the MAC guards against replay attacks. The
Finalize message contents and the MAC are then encrypted before being sent over the network. If the
receiver cannot decrypt the message and validate the MAC, the MD5 and the SHA hash, the session is
terminated before any application data is sent under the new cipher suite.
In general, record layer MAC processing is designed to guard data integrity even if encryption keys and
cipher initialization vectors have been compromised. In such cases, an attacker would still have to learn the
MAC secret key to change the data or replay old messages. Since the read and write side of any connection
uses different keys and initialization vectors, both sets of secrets need to be compromised to subvert traffic
in both directions.
3 Pure Java SSL Design
3.1
Delivered Implementation
The pure Java SSL implementation delivers the following subset of SSL functionality:
1.
2.
3.
4.
Support for all SSL architectural features at the design level.
Support for the ChangeCipherSpec/Alert/Data message protocols.
Support for the Handshake protocol once per connection.
Fully compliant cryptographic support for the SSL_NULL_WITH_NULL_NULL,
SSL_DH_anon_WITH_DES_CBC_SHA, and SSL_DH_anon_3DES_EDE_CBC_SHA cipher
suites.
Features not implemented but anticipated in the design include:
1.
2.
3.
4.
Session re-use.
Session re-negotiation.
X.509 authentication.
Full-feature API support.
The current code footprint is approximately 7000 lines of code in 65 classes. The SSL code calls Sun’s
Java Cryptography Architecture 1.2 and Java Cryptography Extension 1.2 classes for all basic
cryptographic algorithms (DES, 3DES, MD5, SHA, DH, etc.).
3.2
SSL API
The application programming interface that Java applications use to interact with SSL is the API
recommended by Sun in the javax.net and javax.net.ssl packages. Parts of the interface not directly related
to input/output operations were not completely implemented.
The SocketFactory and ServerSocketFactory classes are used to obtain SSLSocket and SSLServerSocket
objects respectively. The initial SSL handshake takes place during the construction of all SSLSockets. The
user can explicitly enable specific cipher suites for consideration at this time. By the time an application
gets a reference to an SSLSocket, all security initialization has taken place and the connection will encrypt
and decrypt all application data automatically.
6
SSLSocket is a subclass of the standard Socket class and SSLServerSocket subclasses ServerSocket. The
accept() method of the ServerSocket class has been overridden in SSLServerSocket to return a connected
SSLSocket object. All appropriate input/output methods have been overridden in SSLSocket to enable
processing of all SSL protocol messages.
3.3
SSL High Level Design
An SSL session defines the set of cryptographic and related parameters under which any SSL connection
using that session operates. The Session class, which implements the SSLSession interface, provides the
SSL session semantics. A Session contains of a session identifier, the peer certificate, the compression
method, a number of CipherSpec objects, the master secret, and the resumable flag.
A CipherSpec object contains the negotiated cryptographic parameters. These include the selected cipher
algorithm, the cipher type, the MAC algorithm and the number of bytes in the MAC results,
cipher keys and cipher initialization vectors. Each Session object contains four CipherSpec objects: the
current read, current write, pending read and pending write objects.
The SSLSocket class is a subclass of the standard TCP Socket class. It extends the Socket class with the
following private fields:
-
A Session object.
The client and server random blocks.
The client’s write cipher keys, write MAC keys and write cipher initialization vectors. 2
The server’s write cipher keys, write MAC keys and write cipher initialization vectors. 2
The read and write message sequence numbers.
The message protocol state machine.
The underlying TCP socket’s input and output streams.
The encryption and decryption cipher objects.
The clientMode flag.
The SSLSocket class embodies the implementation of an SSL connection. During construction, the object
is assigned either the SSL client or server role and the SSL handshake protocol is executed accordingly.
Upon successful construction, the object is returned to the calling application and may be used in wherever
a standard TCP socket would be used.
In addition to the Session and SSLSocket classes, the mechanisms that provide the SSL Record Layer and
SSL Message Protocol Layer functionality also play a central design role. These will be described in the
following sections. There are also five SSLException classes used to report problems to the calling
application and a number of important auxiliary classes that manage SSL enumerations and constants.
3.4
Record Layer
Each of the possible SSL messages in the Handshake, ChangeCipherSpec and Alert protocols have a
corresponding Java class defined for it. These Msg* classes support the ExternInterface which.allows
messages to be converted to byte arrays in the transmission format defined by the SSL specification.
The record layer function is implemented in two methods of the SSLSocket class with the help of a number
of auxiliary classes. The Record class encapsulates a message header and a payload byte array. The
SSLSocket.readRecord() method reads data from the underlying TCP socket, processes the data according
to the current cipher suite and the transformations defined by the record layer (see “SSL Record Layer “on
page 3), and returns a newly created Record object. Upon completion, this Record object contains an SSL
message in externalized form.
2
The current implementation associates the keys and initialization vectors with the session instead of the connection.
The effect is the same because session re-use is not implemented.
7
The SSLSocket.writeRecord() method takes as input an SSL message object that has been externalized into
a byte array and then encapsulated in a Record object. This byte array is then appropriately fragmented and
transformed before being transmitted on the TCP socket.
3.5
Message Protocol Layer
All data transmitted over SSL connections are messages of one the four SSL protocols in externalized form.
A full SSL implementation allows session re-negotiation anytime after the initial handshake. Thus,
messages from various protocols are often intermingled. A single state machine approach was taken to
handle all message protocol layer traffic in a unified way.
The StateMachine class is initialized on SSLSocket construction based on whether the connection endpoint
is in client or server mode. Each mode has its own State/Event matrix statically initialized with its
appropriate Actions. All incoming and outgoing messages are viewed as events which, when applied to the
current state, execute a pre-configured action and return a new state. There are 11 client states, 8 server
states and 15 events defined. There are 13 concrete Action classes currently implemented to execute state
transitions. Consult the Appendix for a listing.
The state machine receives events from the user application and the TCP network transport layer. Events
received off the network are processed by the record layer and returned as Record objects to the Message
Protocol layer. The Record objects are passed to the StateMachine.processRecord() method which
deserializes them into message objects. Next, a State/Event matrix lookup returns an Action object whose
nextState() method is called to effect the state transition.
Application initiated reads are handled like any other network event. Therefore, the only event that does
not originate from the network or from within the message protocol layer itself are application initiated
writes. These events are packaged into Record objects, passed to the StateMachine.processRecord()
method for state validation, and then sent through the record layer via the SSLSocket.writeRecord() call.
Most of the SSL protocol semantics are implemented in the Action classes. Besides parameter processing
and validation, handshake related actions often send response messages to the peer and perform
cryptographic calculations. This work in performed in the nextState() methods of Action objects. All
Actions return the new connection state.
3.6
Design Rationale
The implemented CipherInputStream and CipherOutputStream classes extend the standard InputStream and
OutputStream classes and present the user with the familiar stream-based model for input/output
operations. Internally, however, our implementation manipulates byte arrays explicitly. The Message
Protocol and Record layers are not designed as a set of filters successively applied to a data stream, even
though the simplicity of such an organization is desirable.
The reason for this lies in the way SSL is specified. For example, there is a need to store previously sent
messages for later reprocessing. The Finalize message requires that all previous handshake messages,
whether sent or received, be available for hashing to complete the handshake protocol (see “Integrity and
Privacy” on page 5). Another complication arises from the fact that the SSL line protocol consists of a
cleartext header followed by a ciphertext payload. Thus, a simple cipher stream filter operating on all data
would not suffice internally. Similarly, on-the-fly compression, encryption and MAC processing do not
conveniently allow resultant length calculations to be stored in message headers using a purely streambased approach.
This non-stream approach led to the implementation of the custom ExternInterface for object serialization,
rather than using the standard, stream-oriented, Serializable/Externalizable interfaces.
8
4 Conclusions
Though simple in concept, an SSL implementation requires a fair amount of precise coding because of the
complexity of the protocol and its dynamic features. Almost every handshake message has a variable
format to accommodate the requirements of all the supported cryptographic algorithms. Thus, message
encoding and decoding involves a fair amount of semantic checking even for well-formed messages. Many
of the handshake messages themselves are optional depending on the negotiation, adding more complexity
to enforcing protocol semantics.
There are a number of design challenges that any SSL implementation must address. These include
minimizing the number of times data is copied during message processing and securely handling data
important to cryptographic algorithms. For example, once cryptographic data are no longer needed, it’s
often prudent to overwrite the data before freeing the object that contains it. This occurs at a number of
different processing stages are requires careful consideration when references to such data are passed
around.
4.1
Future Work
The availability of a free pure Java implementation of the non-proprietary parts (i.e., non-RSA) of SSL
would probably be welcome by many Java programmers. If such an implementation were reasonably fast,
dependable and supported all the advanced features of SSL (and soon, SSL’s successor, TLC), its value
would even be greater. Time permitting, this is where the current implementation should go.
In addition, an open implementation could also be designed in such a way as to allow new, non-standard
algorithms to be easily incorporated into the SSL base. Customized versions of SSL could allow
applications to define their own compression algorithms, use stronger ciphers or work with specialized
hardware.
5 References
[1] SSLeay by E.A. Young. Code and documentation found at http://psych.psy.uq.oz.au/~ftp/Crypto.
[2] SSLREF by Netscape Communications Corporation. Code and documentation found at
http://test-drive.netscape.com/tdrive-new/sslref.html.
[3] SSL Plus by Consensus Development Corporation. Product information at http://www.consensus.com.
[4] iSaSiLk by the Institute for Applied Information Processing and Communications (IAIK) at
http://jcewww.iaik.tu-graz.ac.at/index.htm.
[5] Cryptography and Network Security, Principles and Practice, William Stallings, Prentice-Hall Inc.,
1999.
[6] Applied Cryptography, Protocols Algorithms and Source Code in C, Bruce Schneier, John Wiley &
Sons, Inc., 1996.
[7] “The SSL Protocol, Version 3.0,” Alan Freier, Philip Karlton, Paul Kocher, Internet Draft, Transport
Layer Security Working Group, November 18, 1996.
6 Appendix
6.1
SSL State Machine Events
SMEVENT_START_HANDSHAKE
SMEVENT_CLT_HELLO
SMEVENT_CERTIFICATE
9
SMEVENT_CLT_KEYEXCHANGE
SMEVENT_CLT_CERTIFICATE_VER
SMEVENT_CHG_CIPHER
SMEVENT_FINISHED
SMEVENT_SVR_HELLO
SMEVENT_SVR_KEYEXCHANGE
SMEVENT_SVR_CERTIFICATE_REQ
SMEVENT_SVR_HELLO_DONE
SMEVENT_HELLO_REQ
SMEVENT_FATAL_ALERT
SMEVENT_CERTIFICATE_ALERT
SMEVENT_DATA
6.2
SSL State Machine Client States
SMSTATE_CLT_INIT
SMSTATE_CLT_HELLO_SENT
SMSTATE_CLT_HELLO_RECV
SMSTATE_CLT_CERTIFICATE_RECV
SMSTATE_CLT_KEYEXCHANGE_RECV
SMSTATE_CLT_CERTIFICATE_REQ_RECV
SMSTATE_CLT_HELLO_DONE_RECV
SMSTATE_CLT_FINISHED_SENT
SMSTATE_CLT_CHG_CIPHER_RECV
SMSTATE_CLT_FINISHED
SMSTATE_CLT_CLOSED
6.3
SSL State Machine Server States
SMSTATE_SVR_INIT
SMSTATE_SVR_HELLO_DONE_SENT
SMSTATE_SVR_CERTIFICATE_RECV
SMSTATE_SVR_KEYEXCHANGE_RECV
SMSTATE_SVR_CERTIFICATE_VER_RECV
SMSTATE_SVR_CHG_CIPHER_RECV
SMSTATE_SVR_FINISHED
SMSTATE_SVR_CLOSED
6.4
SSL Source File Listing
javax\net\ServerSocketFactory.java
javax\net\SocketFactory.java
javax\net\ssl\Action.java
javax\net\ssl\ActionCertificate.java
javax\net\ssl\ActionChangeCipher.java
javax\net\ssl\ActionCltCertificateVer.java
javax\net\ssl\ActionCltHello.java
javax\net\ssl\ActionCltKeyExchange.java
javax\net\ssl\ActionFinished.java
javax\net\ssl\ActionIgnore.java
javax\net\ssl\ActionInterface.java
javax\net\ssl\ActionInvalidEvent.java
javax\net\ssl\ActionStartHandshake.java
javax\net\ssl\ActionSvrCertificateReq.java
javax\net\ssl\ActionSvrHello.java
javax\net\ssl\ActionSvrHelloDone.java
10
javax\net\ssl\ActionSvrKeyExchange.java
javax\net\ssl\CipherSpec.java
javax\net\ssl\Constants.java
javax\net\ssl\CryptoInputStream.java
javax\net\ssl\CryptoOutputStream.java
javax\net\ssl\Enums.java
javax\net\ssl\Env.java
javax\net\ssl\ExternInterface.java
javax\net\ssl\HandshakeCompletedEvent.java
javax\net\ssl\HandshakeCompletedListener.java
javax\net\ssl\MsgAlert.java
javax\net\ssl\MsgChangeCipher.java
javax\net\ssl\MsgHdr.java
javax\net\ssl\MsgHS.java
javax\net\ssl\MsgHSCltHello.java
javax\net\ssl\MsgHSCltKeyExchange.java
javax\net\ssl\MsgHSFinished.java
javax\net\ssl\MsgHSSvrHello.java
javax\net\ssl\MsgHSSvrHelloDone.java
javax\net\ssl\MsgHSSvrKeyExchange.java
javax\net\ssl\MsgInterface.java
javax\net\ssl\RandomWithTS.java
javax\net\ssl\Record.java
javax\net\ssl\Session.java
javax\net\ssl\SessionCrypto.java
javax\net\ssl\SessionId.java
javax\net\ssl\SSLException.java
javax\net\ssl\SSLHandshakeException.java
javax\net\ssl\SSLKeyException.java
javax\net\ssl\SSLPeerUnverifiedException.java
javax\net\ssl\SSLProtocolException.java
javax\net\ssl\SSLServerSocket.java
javax\net\ssl\SSLServerSocketFactory.java
javax\net\ssl\SSLSession.java
javax\net\ssl\SSLSessionBindingEvent.java
javax\net\ssl\SSLSessionBindingListener.java
javax\net\ssl\SSLSessionContext.java
javax\net\ssl\SSLSocket.java
javax\net\ssl\SSLSocketFactory.java
javax\net\ssl\StateMachine.java
javax\net\ssl\WrappedByteArray.java
11
Download