*
* Prepare an PKCS1Encoding with good random
* padding.
*/
RSABlindedEngine rsa = new RSABlindedEngine();
PKCS1Encoding encoding = new PKCS1Encoding(rsa);
encoding.init(true, new ParametersWithRandom(this.serverRsaKey, this.random));
byte[] encrypted = null;
try
{
encrypted = encoding.processBlock(pms, 0, pms.length);
}
catch (InvalidCipherTextException e)
{
/*
* This should never happen, only during decryption.
*/
this.failWithError(AL_fatal, AP_internal_error);
}
/*
* Send the encrypted pms.
*/
ByteArrayOutputStream bos = new ByteArrayOutputStream();
TlsUtils.writeUint8(HP_CLIENT_KEY_EXCHANGE, bos);
TlsUtils.writeUint24(encrypted.length + 2, bos);
TlsUtils.writeUint16(encrypted.length, bos);
bos.write(encrypted);
byte[] message = bos.toByteArray();
rs.writeMessage((short)RL_HANDSHAKE, message, 0, message.length);
break;
case TlsCipherSuite.KE_DHE_RSA:
/*
* Send the Client Key Exchange message for
* DHE key exchange.
*/
byte[] YcByte = this.Yc.toByteArray();
ByteArrayOutputStream DHbos = new ByteArrayOutputStream();
TlsUtils.writeUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);
TlsUtils.writeUint24(YcByte.length + 2, DHbos);
TlsUtils.writeUint16(YcByte.length, DHbos);
DHbos.write(YcByte);
byte[] DHmessage = DHbos.toByteArray();
rs.writeMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.length);
break;
default:
/*
* Problem during handshake, we don't know
* how to handle this key exchange method.
*/
this.failWithError(AL_fatal, AP_unexpected_message);
}
connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;
/*
* Now, we send change cipher state
*/
byte[] cmessage = new byte[1];
cmessage[0] = 1;
rs.writeMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.length);
connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;
/*
* Calculate the ms
*/
this.ms = new byte[48];
byte[] random = new byte[clientRandom.length + serverRandom.length];
System.arraycopy(clientRandom, 0, random, 0, clientRandom.length);
System.arraycopy(serverRandom, 0, random, clientRandom.length, serverRandom.length);
TlsUtils.PRF(pms, TlsUtils.toByteArray("master secret"), random, this.ms);
/*
* Initialize our cipher suite
*/
rs.writeSuite = this.choosenCipherSuite;
rs.writeSuite.init(this.ms, clientRandom, serverRandom);
/*
* Send our finished message.
*/
byte[] checksum = new byte[12];
byte[] md5andsha1 = new byte[16 + 20];
rs.hash1.doFinal(md5andsha1, 0);
TlsUtils.PRF(this.ms, TlsUtils.toByteArray("client finished"), md5andsha1, checksum);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
TlsUtils.writeUint8(HP_FINISHED, bos);
TlsUtils.writeUint24(12, bos);
bos.write(checksum);
byte[] message = bos.toByteArray();
rs.writeMessage((short)RL_HANDSHAKE, message, 0, message.length);
this.connection_state = CS_CLIENT_FINISHED_SEND;
read = true;
break;
default:
this.failWithError(AL_fatal, AP_handshake_failure);
}
break;
case HP_SERVER_KEY_EXCHANGE:
switch (connection_state)
{
case CS_SERVER_CERTIFICATE_RECEIVED:
/*
* Check that we are doing DHE key exchange
*/
if (this.choosenCipherSuite.getKeyExchangeAlgorithm() != TlsCipherSuite.KE_DHE_RSA)
{
this.failWithError(AL_fatal, AP_unexpected_message);
}
/*
* Parse the Structure
*/
int pLength = TlsUtils.readUint16(is);
byte[] pByte = new byte[pLength];
TlsUtils.readFully(pByte, is);
int gLength = TlsUtils.readUint16(is);
byte[] gByte = new byte[gLength];
TlsUtils.readFully(gByte, is);
int YsLength = TlsUtils.readUint16(is);
byte[] YsByte = new byte[YsLength];
TlsUtils.readFully(YsByte, is);
int sigLength = TlsUtils.readUint16(is);
byte[] sigByte = new byte[sigLength];
TlsUtils.readFully(sigByte, is);
this.assertEmpty(is);
/*
* Verify the Signature.
*
* First, calculate the hash.
*/
CombinedHash sigDigest = new CombinedHash();
ByteArrayOutputStream signedData = new ByteArrayOutputStream();
TlsUtils.writeUint16(pLength, signedData);
signedData.write(pByte);
TlsUtils.writeUint16(gLength, signedData);
signedData.write(gByte);
TlsUtils.writeUint16(YsLength, signedData);
signedData.write(YsByte);
byte[] signed = signedData.toByteArray();
sigDigest.update(this.clientRandom, 0, this.clientRandom.length);
sigDigest.update(this.serverRandom, 0, this.serverRandom.length);
sigDigest.update(signed, 0, signed.length);
byte[] hash = new byte[sigDigest.getDigestSize()];
sigDigest.doFinal(hash, 0);
/*
* Now, do the RSA operation
*/
RSABlindedEngine rsa = new RSABlindedEngine();
PKCS1Encoding encoding = new PKCS1Encoding(rsa);
encoding.init(false, this.serverRsaKey);
/*
* The data which was signed
*/
byte[] sigHash = null;
try
{
sigHash = encoding.processBlock(sigByte, 0, sigByte.length);
}
catch (InvalidCipherTextException e)
{
this.failWithError(AL_fatal, AP_bad_certificate);
}