/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Many data structures are involved in the handshake messages. These
* classes are used as structures, with public data members. They are
* not visible outside the SSL package.
*
* Handshake messages all have a common header format, and they are all
* encoded in a "handshake data" SSL record substream. The base class
* here (HandshakeMessage) provides a common framework and records the
* SSL record type of the particular handshake message.
*
* This file contains subclasses for all the basic handshake messages.
* All handshake messages know how to encode and decode themselves on
* SSL streams; this facilitates using the same code on SSL client and
* server sides, although they don't send and receive the same messages.
*
* Messages also know how to print themselves, which is quite handy
* for debugging. They always identify their type, and can optionally
* dump all of their content.
*
* @author David Brownell
*/
public abstract class HandshakeMessage {
HandshakeMessage() { }
// enum HandshakeType:
/* Class and subclass dynamic debugging support */
/**
* Utility method to convert a BigInteger to a byte array in unsigned
* format as needed in the handshake messages. BigInteger uses
* 2's complement format, i.e. it prepends an extra zero if the MSB
* is set. We remove that.
*/
byte[] b = bi.toByteArray();
int n = b.length - 1;
byte[] newarray = new byte[n];
b = newarray;
}
return b;
}
/*
* SSL 3.0 MAC padding constants.
* Also used by CertificateVerify and Finished during the handshake.
*/
return padding;
}
/*
* Write a handshake message on the (handshake) output stream.
* This is just a four byte header followed by the data.
*
* NOTE that huge messages -- notably, ones with huge cert
* chains -- are handled correctly.
*/
int len = messageLength();
throw new SSLException("Handshake message too big"
}
s.write(messageType());
send(s);
}
/*
* Subclasses implement these methods so those kinds of
* messages can be emitted. Base class delegates to subclass.
*/
abstract int messageType();
abstract int messageLength();
/*
* Write a descriptive message on the output stream; for debugging.
*/
//
// NOTE: the rest of these classes are nested within this one, and are
// imported by other classes in this package. There are a few other
// handshake message classes, not neatly nested here because of current
// licensing requirement for native (RSA) methods. They belong here,
// but those native methods complicate things a lot!
//
/*
* HelloRequest ... SERVER --> CLIENT
*
* Server can ask the client to initiate a new handshake, e.g. to change
* session parameters after a connection has been (re)established.
*/
HelloRequest() { }
{
// nothing in this message
}
{
// nothing in this messaage
}
{
}
}
/*
* ClientHello ... CLIENT --> SERVER
*
* Client initiates handshake by telling server what it wants, and what it
* can support (prioritized by what's first in the ciphe suite list).
*
* By RFC2246:7.4.1.2 it's explicitly anticipated that this message
* will have more data added at the end ... e.g. what CAs the client trusts.
* Until we know how to parse it, we will just read what we know
* about, and let our caller handle the jumps over unknown data.
*/
byte[] compression_methods;
this.protocolVersion = protocolVersion;
this.cipherSuites = cipherSuites;
if (cipherSuites.containsEC()) {
}
}
clnt_random = new RandomCookie(s);
cipherSuites = new CipherSuiteList(s);
compression_methods = s.getBytes8();
if (messageLength() != messageLength) {
extensions = new HelloExtensions(s);
}
}
return cipherSuites;
}
// add renegotiation_info extension
clientVerifyData, new byte[0]);
}
// add server_name extension
// We would have checked that the hostname ia a FQDN.
try {
} catch (IOException ioe) {
// ignore the exception and return
}
}
// add signature_algorithm extension
}
int messageLength() {
/*
* Add fixed size parts of each field...
* version + random + session + cipher + compress
*/
return (2 + 32 + 1 + 2 + 1
+ extensions.length();
}
clnt_random.send(s);
cipherSuites.send(s);
extensions.send(s);
}
s.print("RandomCookie: ");
clnt_random.print(s);
s.print("Session ID: ");
extensions.print(s);
s.println("***");
}
}
}
/*
* ServerHello ... SERVER --> CLIENT
*
* Server chooses protocol options from among those it supports and the
* client supports. Then it sends the basic session descriptive parameters
* back to the client.
*/
static final
{
byte compression_method;
ServerHello() {
// empty
}
throws IOException {
if (messageLength() != messageLength) {
}
}
int messageLength()
{
// almost fixed size, except session ID and extensions:
// major + minor = 2
// random = 32
// session ID len field = 1
// cipher suite + compression = 3
// extensions: if present, 2 + length of extensions
}
{
svr_random.send(s);
extensions.send(s);
}
{
s.print("RandomCookie: ");
svr_random.print(s);
int i;
s.print("Session ID: ");
extensions.print(s);
s.println("***");
}
}
}
/*
* CertificateMsg ... send by both CLIENT and SERVER
*
* Each end of a connection may need to pass its certificate chain to
* the other end. Such chains are intended to validate an identity with
* reference to some certifying authority. Examples include companies
* like Verisign, or financial institutions. There's some control over
* the certifying authorities which are sent.
*
* NOTE: that these messages might be huge, taking many handshake records.
* Up to 2^48 bytes of certificate may be sent, in records of at most 2^14
* bytes each ... up to 2^32 records sent on the output stream.
*/
static final
{
private int messageLength;
}
while (chainLen > 0) {
try {
}
} catch (CertificateException e) {
throw (SSLProtocolException)new SSLProtocolException(
e.getMessage()).initCause(e);
}
}
}
int messageLength() {
if (encodedChain == null) {
messageLength = 3;
try {
byte[] b = cert.getEncoded();
encodedChain.add(b);
}
} catch (CertificateEncodingException e) {
encodedChain = null;
throw new RuntimeException("Could not encode certificates", e);
}
}
return messageLength;
}
for (byte[] b : encodedChain) {
s.putBytes24(b);
}
}
s.println("*** Certificate chain");
s.println("***");
}
}
}
}
/*
* ServerKeyExchange ... SERVER --> CLIENT
*
* The cipher suite selected, when combined with the certificate exchanged,
* implies one of several different kinds of key exchange. Most current
* cipher suites require the server to send more than its certificate.
*
* The primary exceptions are when a server sends an encryption-capable
* RSA public key in its cert, to be used with RSA (or RSA_export) key
* exchange; and when a server sends its Diffie-Hellman cert. Those kinds
* of key exchange do not require a ServerKeyExchange message.
*
* Key exchange can be viewed as having three modes, which are explicit
* for the Diffie-Hellman flavors and poorly specified for RSA ones:
*
* - "Ephemeral" keys. Here, a "temporary" key is allocated by the
* server, and signed. Diffie-Hellman keys signed using RSA or
* DSS are ephemeral (DHE flavor). RSA keys get used to do the same
* thing, to cut the key size down to 512 bits (export restrictions)
* or for signing-only RSA certificates.
*
* - Anonymity. Here no server certificate is sent, only the public
* key of the server. This case is subject to man-in-the-middle
* attacks. This can be done with Diffie-Hellman keys (DH_anon) or
* with RSA keys, but is only used in SSLv3 for DH_anon.
*
* - "Normal" case. Here a server certificate is sent, and the public
* key there is used directly in exchanging the premaster secret.
* For example, Diffie-Hellman "DH" flavor, and any RSA flavor with
* only 512 bit keys.
*
* If a server certificate is sent, there is no anonymity. However,
* when a certificate is sent, ephemeral keys may still be used to
* exchange the premaster secret. That's how RSA_EXPORT often works,
* as well as how the DHE_* flavors work.
*/
{
}
/*
* Using RSA for Key Exchange: exchange a session key that's not as big
* as the signing-only key. Used for export applications, since exported
* RSA encryption keys can't be bigger than 512 bytes.
*
* This is never used when keys are 512 bits or smaller, and isn't used
* on "US Domestic" ciphers in any case.
*/
static final
{
private byte[] signatureBytes;
/*
* Hash the nonces and the ephemeral RSA public key.
*/
throws SignatureException {
int tmp;
}
/*
* Construct an RSA server key exchange message, using data
* known _only_ to the server.
*
* The client knows the public key corresponding to this private
* key, from the Certificate message sent previously. To comply
* with US export regulations we use short RSA keys ... either
* long term ones in the server's X509 cert, or else ephemeral
* ones sent using this message.
*/
throws GeneralSecurityException {
}
/*
* Parse an RSA server key exchange message, using data known
* to the client (and, in some situations, eavesdroppers).
*/
throws IOException, NoSuchAlgorithmException {
}
/*
* Get the ephemeral RSA public key that will be used in this
* SSL connection.
*/
try {
// modulus and exponent are always positive
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/*
* Verify the signed temporary key using the hashes computed
* from it and the two nonces. This is called by clients
* with "exportable" RSA flavors.
*/
}
int messageLength() {
}
}
s.println("*** RSA ServerKeyExchange");
}
}
}
/*
* Using Diffie-Hellman algorithm for key exchange. All we really need to
* do is securely get Diffie-Hellman keys (using the same P, G parameters)
* to our peer, then we automatically have a shared secret without need
* to exchange any more data. (D-H only solutions, such as SKIP, could
* eliminate key exchange negotiations and get faster connection setup.
* trusted distribution of keys without relying on unscalable physical
* key distribution systems.)
*
* This class supports several DH-based key exchange algorithms, though
* perhaps eventually each deserves its own class. Notably, this has
* basic support for DH_anon and its DHE_DSS and DHE_RSA signed variants.
*/
static final
{
// Fix message encoding, see 4348279
private final static boolean dhKeyExchangeFix =
private byte signature [];
// protocol version being established using this ServerKeyExchange message
// the preferable signature algorithm used by this ServerKeyExchange message
/*
* Construct from initialized DH key object, for DH_anon
* key exchange.
*/
this.protocolVersion = protocolVersion;
this.preferableSignatureAlgorithm = null;
// The DH key has been validated in the constructor of DHCrypt.
}
/*
* Construct from initialized DH key object and the key associated
* with the cert chain which was sent ... for DHE_DSS and DHE_RSA
* key exchange. (Constructor called by server.)
*/
this.protocolVersion = protocolVersion;
// The DH key has been validated in the constructor of DHCrypt.
} else {
this.preferableSignatureAlgorithm = null;
} else {
}
}
}
/*
* Construct a DH_ServerKeyExchange message from an input
* stream, as if sent from server to client for use with
* DH_anon key exchange
*/
throws IOException, GeneralSecurityException {
this.protocolVersion = protocolVersion;
this.preferableSignatureAlgorithm = null;
}
/*
* Construct a DH_ServerKeyExchange message from an input stream
* and a certificate, as if sent from server to client for use with
* DHE_DSS or DHE_RSA key exchange. (Called by client.)
*/
throws IOException, GeneralSecurityException {
this.protocolVersion = protocolVersion;
// read params: ServerDHParams
// read the signature and hash algorithm
// Is it a local supported signature algorithm?
throw new SSLHandshakeException(
"Unsupported SignatureAndHashAlgorithm in " +
"ServerKeyExchange message");
}
} else {
this.preferableSignatureAlgorithm = null;
}
// read the signature
byte signature[];
if (dhKeyExchangeFix) {
} else {
signature = new byte[messageSize];
}
} else {
} else {
throw new SSLKeyException("neither an RSA or a DSA key");
}
}
throw new SSLKeyException("Server D-H key verification failed");
}
}
/* Return the Diffie-Hellman modulus */
}
}
/* Return the server's Diffie-Hellman public key */
}
/*
* Update sig with nonces and Diffie-Hellman public key.
*/
byte svrNonce[]) throws SignatureException {
int tmp;
}
}
int messageLength() {
}
if (dhKeyExchangeFix) {
temp += 2;
}
}
return temp;
}
s.putBytes16(dh_p);
s.putBytes16(dh_g);
s.putBytes16(dh_Ys);
}
if (dhKeyExchangeFix) {
s.putBytes16(signature);
} else {
}
}
}
s.println("*** Diffie-Hellman ServerKeyExchange");
s.println("Anonymous");
} else {
s.println("Signature Algorithm " +
}
s.println("Signed with a DSA or RSA public key");
}
}
}
}
/*
* ECDH server key exchange message. Sent by the server for ECDHE and ECDH_anon
* ciphersuites to communicate its ephemeral public key (including the
* EC domain parameters).
*
* We support named curves only, no explicitly encoded curves.
*/
static final
// constants for ECCurveType
// id of the curve we are using
private int curveId;
// encoded public point
private byte[] pointBytes;
// signature bytes (or null if anonymous)
private byte[] signatureBytes;
// public key object encapsulated in this message
// protocol version being established using this ServerKeyExchange message
// the preferable signature algorithm used by this ServerKeyExchange message
this.protocolVersion = protocolVersion;
if (privateKey == null) {
// ECDH_anon
return;
}
} else {
}
}
/*
* Parse an ECDH server key exchange message.
*/
throws IOException, GeneralSecurityException {
this.protocolVersion = protocolVersion;
// read params: ServerECDHParams
// These parsing errors should never occur as we negotiated
// the supported curves during the exchange of the Hello messages.
if (curveType == CURVE_NAMED_CURVE) {
== false) {
throw new SSLHandshakeException(
"Unsupported curveId: " + curveId);
}
throw new SSLHandshakeException(
"Unknown named curve: " + curveId);
}
if (parameters == null) {
throw new SSLHandshakeException(
"Unsupported curve: " + curveOid);
}
} else {
throw new SSLHandshakeException(
"Unsupported ECCurveType: " + curveType);
}
if (signingKey == null) {
// ECDH_anon
return;
}
// read the signature and hash algorithm
// Is it a local supported signature algorithm?
throw new SSLHandshakeException(
"Unsupported SignatureAndHashAlgorithm in " +
"ServerKeyExchange message");
}
}
// read the signature
// verify the signature
} else {
}
throw new SSLKeyException(
"Invalid signature on ECDH server key exchange message");
}
}
/*
* Get the ephemeral EC public key encapsulated in this message.
*/
return publicKey;
}
throws NoSuchAlgorithmException {
return RSASignature.getInstance();
} else {
throw new NoSuchAlgorithmException("neither an RSA or a EC key");
}
}
byte svrNonce[]) throws SignatureException {
}
int messageLength() {
int sigLen = 0;
if (signatureBytes != null) {
}
}
}
s.putBytes8(pointBytes);
if (signatureBytes != null) {
}
}
}
s.println("*** ECDH ServerKeyExchange");
if (signatureBytes == null) {
s.println("Anonymous");
} else {
s.println("Signature Algorithm " +
}
}
}
}
}
static final class DistinguishedName {
/*
* DER encoded distinguished name.
* TLS requires that its not longer than 65535 bytes.
*/
byte name[];
}
}
try {
return new X500Principal(name);
} catch (IllegalArgumentException e) {
throw (SSLProtocolException)new SSLProtocolException(
e.getMessage()).initCause(e);
}
}
int length() {
}
}
}
}
/*
* CertificateRequest ... SERVER --> CLIENT
*
* Authenticated servers may ask clients to authenticate themselves
* in turn, using this message.
*
* Prior to TLS 1.2, the structure of the message is defined as:
* struct {
* ClientCertificateType certificate_types<1..2^8-1>;
* DistinguishedName certificate_authorities<0..2^16-1>;
* } CertificateRequest;
*
* In TLS 1.2, the structure is changed to:
* struct {
* ClientCertificateType certificate_types<1..2^8-1>;
* SignatureAndHashAlgorithm
* supported_signature_algorithms<2^16-1>;
* DistinguishedName certificate_authorities<0..2^16-1>;
* } CertificateRequest;
*
*/
static final
{
// enum ClientCertificateType
// The existance of these two values is a bug in the SSL specification.
// They are never used in the protocol.
// From RFC 4492 (ECC)
private final static byte[] TYPES_ECC =
// ... "3" because that's the smallest DER-encoded X500 DN
// protocol version being established using this CertificateRequest message
// supported_signature_algorithms for TLS 1.2 or later
// length of supported_signature_algorithms
private int algorithmsLen;
this.protocolVersion = protocolVersion;
// always use X500Principal
}
// we support RSA, DSS, and ECDSA client authentication and they
// can be used with all ciphersuites. If this changes, the code
// needs to be adapted to take keyExchange into account.
// We only request ECDSA client auth if we have ECC crypto available.
// Use supported_signature_algorithms for TLS 1.2 or later.
throw new SSLProtocolException(
"No supported signature algorithms");
}
} else {
algorithmsLen = 0;
}
}
this.protocolVersion = protocolVersion;
// Read the certificate_types.
// Read the supported_signature_algorithms for TLS 1.2 or later.
if (algorithmsLen < 2) {
throw new SSLProtocolException(
"Invalid supported_signature_algorithms field");
}
int remains = algorithmsLen;
int sequence = 0;
++sequence);
}
if (remains != 0) {
throw new SSLProtocolException(
"Invalid supported_signature_algorithms field");
}
} else {
algorithmsLen = 0;
}
// read the certificate_authorities
while (len >= 3) {
}
if (len != 0) {
throw new SSLProtocolException("Bad CertificateRequest DN length");
}
}
}
return ret;
}
return algorithms;
}
int messageType() {
return ht_certificate_request;
}
int messageLength() {
}
}
return len;
}
// put certificate_types
// put supported_signature_algorithms
}
}
// put certificate_authorities
int len = 0;
}
}
}
s.println("*** CertificateRequest");
s.print("Cert Types: ");
switch (types[i]) {
case cct_rsa_sign:
s.print("RSA"); break;
case cct_dss_sign:
s.print("DSS"); break;
case cct_rsa_fixed_dh:
s.print("Fixed DH (RSA sig)"); break;
case cct_dss_fixed_dh:
s.print("Fixed DH (DSS sig)"); break;
case cct_rsa_ephemeral_dh:
s.print("Ephemeral DH (RSA sig)"); break;
case cct_dss_ephemeral_dh:
s.print("Ephemeral DH (DSS sig)"); break;
case cct_ecdsa_sign:
s.print("ECDSA"); break;
case cct_rsa_fixed_ecdh:
s.print("Fixed ECDH (RSA sig)"); break;
case cct_ecdsa_fixed_ecdh:
s.print("Fixed ECDH (ECDSA sig)"); break;
default:
}
s.print(", ");
}
}
s.println();
boolean opened = false;
if (opened) {
} else {
opened = true;
}
}
}
s.println("Cert Authorities:");
s.println("<Empty>");
} else {
authorities[i].print(s);
}
}
}
}
}
/*
* ServerHelloDone ... SERVER --> CLIENT
*
* When server's done sending its messages in response to the client's
* "hello" (e.g. its own hello, certificate, key exchange message, perhaps
* client certificate request) it sends this message to flag that it's
* done that part of the handshake.
*/
static final
{
ServerHelloDone() { }
{
// nothing to do
}
int messageLength()
{
return 0;
}
{
// nothing to send
}
{
s.println("*** ServerHelloDone");
}
}
/*
* CertificateVerify ... CLIENT --> SERVER
*
* Sent after client sends signature-capable certificates (e.g. not
* Diffie-Hellman) to verify.
*/
// the signature bytes
private byte[] signature;
// protocol version being established using this ServerKeyExchange message
// the preferable signature algorithm used by this CertificateVerify message
/*
* Create an RSA or DSA signed certificate verify message.
*/
throws GeneralSecurityException {
this.protocolVersion = protocolVersion;
} else {
}
}
//
// Unmarshal the signed data from the input stream.
//
this.protocolVersion = protocolVersion;
// read the signature and hash algorithm
// Is it a local supported signature algorithm?
throw new SSLHandshakeException(
"Unsupported SignatureAndHashAlgorithm in " +
"ServerKeyExchange message");
}
}
// read the signature
}
/*
* Get the preferable signature algorithm used by this message
*/
return preferableSignatureAlgorithm;
}
/*
* Verify a certificate verify message. Return the result of verification,
* if there is a problem throw a GeneralSecurityException.
*/
} else {
}
}
/*
* Get the Signature object appropriate for verification using the
* given signature algorithm and protocol version.
*/
return RSASignature.getInternalInstance();
} else {
throw new SignatureException("Unrecognized algorithm: "
+ algorithm);
}
}
/*
* Update the Signature with the data appropriate for the given
* signature algorithm and protocol version so that the object is
* ready for signing or verifying.
*/
throws SignatureException {
}
// The signature must be an instance of RSASignature, need
// to use these hashes directly.
} else { // TLS1.2+
}
} else { // DSA, ECDSA
}
} else { // TLS1.2+
}
}
}
/*
* Update the MessageDigest for SSLv3 certificate verify or finished
* message calculation. The digest must already have been updated with
* all preceding handshake messages.
* Used by the Finished class as well.
*/
// Digest the key bytes if available.
// Otherwise (sensitive key), try digesting the key directly.
// That is currently only implemented in SunPKCS11 using a private
// reflection API, so we avoid that if possible.
} else {
}
} else {
}
}
static {
try {
} catch (Exception e) {
throw new RuntimeException("Reflection failed", e);
}
}
o.setAccessible(true);
return null;
}
});
}
// ConcurrentHashMap does not allow null values, use this marker object
// cache Method objects per Spi class
// Note that this will prevent the Spi classes from being GC'd. We assume
// that is not a problem.
new ConcurrentHashMap<>();
try {
// Verify that md is implemented via MessageDigestSpi, not
// via JDK 1.1 style MessageDigest subclassing.
throw new Exception("Digest is not a MessageDigestSpi");
}
if (r == null) {
try {
makeAccessible((Method)r);
} catch (NoSuchMethodException e) {
r = NULL_OBJECT;
}
}
if (r == NULL_OBJECT) {
throw new Exception(
"Digest does not support implUpdate(SecretKey)");
}
} catch (Exception e) {
throw new RuntimeException(
"Could not obtain encoded key and "
+ "MessageDigest cannot digest key", e);
}
}
int messageType() {
return ht_certificate_verify;
}
int messageLength() {
int temp = 2;
}
}
}
s.putBytes16(signature);
}
s.println("*** CertificateVerify");
s.println("Signature Algorithm " +
}
}
}
}
/*
* FINISHED ... sent by both CLIENT and SERVER
*
* This is the FINISHED message as defined in the SSL and TLS protocols.
* Both protocols define this handshake message slightly differently.
* This class supports both formats.
*
* When handshaking is finished, each side sends a "change_cipher_spec"
* record, then immediately sends a "finished" handshake message prepared
* according to the newly adopted cipher spec.
*
* NOTE that until this is sent, no application data may be passed, unless
* some non-default cipher suite has already been set up on this connection
* connection (e.g. a previous handshake arranged one).
*/
// constant for a Finished message sent by the client
// constant for a Finished message sent by the server
// enum Sender: "CLNT" and "SRVR"
/*
* Contents of the finished message ("checksum"). For TLS, it
* is 12 bytes long, for SSLv3 36 bytes.
*/
private byte[] verifyData;
/*
* Current cipher suite we are negotiating. TLS 1.2 has
* ciphersuite-defined PRF algorithms.
*/
/*
* Create a finished message to send to the remote peer.
*/
this.protocolVersion = protocolVersion;
this.cipherSuite = cipherSuite;
}
/*
* Constructor that reads FINISHED message from stream.
*/
this.protocolVersion = protocolVersion;
this.cipherSuite = cipherSuite;
verifyData = new byte[msgLen];
}
/*
* Verify that the hashes here are what would have been produced
* according to a given set of inputs. This is used to ensure that
* both client and server are fully in sync, and that the handshake
* computations have been successful.
*/
}
/*
* Perform the actual finished message calculation.
*/
byte[] sslLabel;
tlsLabel = "client finished";
tlsLabel = "server finished";
} else {
}
// TLS 1.0+
try {
byte [] seed;
// Get the KeyGenerator alg and calculate the seed.
// TLS 1.2
prfAlg = "SunTls12Prf";
} else {
// TLS 1.0/1.1
seed = new byte[36];
prfAlg = "SunTlsPrf";
}
/*
* RFC 5246/7.4.9 says that finished messages can
* algorithm. If we ever run across a different
* length, this call will need to be updated.
*/
throw new ProviderException(
"Invalid PRF output, format must be RAW");
}
return finished;
} catch (GeneralSecurityException e) {
throw new RuntimeException("PRF failed", e);
}
} else {
// SSLv3
byte[] finished = new byte[36];
try {
} catch (DigestException e) {
// cannot occur
throw new RuntimeException("Digest failed", e);
}
return finished;
}
}
/*
* Update the MessageDigest for SSLv3 finished message calculation.
* The digest must already have been updated with all preceding handshake
* messages. This operation is almost identical to the certificate verify
* hash, reuse that code.
*/
}
// get the verify_data of the finished message
byte[] getVerifyData() {
return verifyData;
}
int messageLength() {
return verifyData.length;
}
}
s.println("*** Finished");
s.println("***");
}
}
}
//
// END of nested classes
//
}