in modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java [102:313]
public void unwrap(byte[] bytes) {
io_stream.append(bytes);
while (io_stream.available() > 0) {
int handshakeType;
int length;
io_stream.mark();
try {
handshakeType = io_stream.read();
length = io_stream.readUint24();
if (io_stream.available() < length) {
io_stream.reset();
return;
}
switch (handshakeType) {
case 1: // CLIENT_HELLO
if (clientHello != null && this.status != FINISHED) {
// Client hello has been received during handshake
unexpectedMessage();
return;
}
// if protocol planed to send Hello Request message
// - cancel this demand.
needSendHelloRequest = false;
clientHello = new ClientHello(io_stream, length);
if (nonBlocking) {
delegatedTasks.add(new DelegatedTask(new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
processClientHello();
return null;
}
}, this, AccessController.getContext()));
return;
}
processClientHello();
break;
case 11: // CLIENT CERTIFICATE
if (isResuming || certificateRequest == null
|| serverHelloDone == null || clientCert != null) {
unexpectedMessage();
return;
}
clientCert = new CertificateMessage(io_stream, length);
if (clientCert.certs.length == 0) {
if (parameters.getNeedClientAuth()) {
fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
"HANDSHAKE FAILURE: no client certificate received");
}
} else {
String authType = clientCert.certs[0].getPublicKey()
.getAlgorithm();
try {
parameters.getTrustManager().checkClientTrusted(
clientCert.certs, authType);
} catch (CertificateException e) {
fatalAlert(AlertProtocol.BAD_CERTIFICATE,
"Untrusted Client Certificate ", e);
}
session.peerCertificates = clientCert.certs;
}
break;
case 15: // CERTIFICATE_VERIFY
if (isResuming
|| clientKeyExchange == null
|| clientCert == null
|| clientKeyExchange.isEmpty() //client certificate
// contains fixed DH
// parameters
|| certificateVerify != null
|| changeCipherSpecReceived) {
unexpectedMessage();
return;
}
certificateVerify = new CertificateVerify(io_stream, length);
DigitalSignature ds = new DigitalSignature(session.cipherSuite.keyExchange);
ds.init(serverCert.certs[0]);
byte[] md5_hash = null;
byte[] sha_hash = null;
if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT
|| session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA
|| session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_RSA
|| session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
md5_hash = io_stream.getDigestMD5withoutLast();
sha_hash = io_stream.getDigestSHAwithoutLast();
} else if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_DSS
|| session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
sha_hash = io_stream.getDigestSHAwithoutLast();
} else if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon
|| session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon_EXPORT) {
}
ds.setMD5(md5_hash);
ds.setSHA(sha_hash);
if (!ds.verifySignature(certificateVerify.signedHash)) {
fatalAlert(AlertProtocol.DECRYPT_ERROR,
"DECRYPT ERROR: CERTIFICATE_VERIFY incorrect signature");
}
break;
case 16: // CLIENT_KEY_EXCHANGE
if (isResuming
|| serverHelloDone == null
|| clientKeyExchange != null
|| (clientCert == null && parameters
.getNeedClientAuth())) {
unexpectedMessage();
return;
}
if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA
|| session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT) {
clientKeyExchange = new ClientKeyExchange(io_stream,
length, serverHello.server_version[1] == 1,
true);
Cipher c = null;
try {
c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
c.init(Cipher.DECRYPT_MODE, privKey);
preMasterSecret = c
.doFinal(clientKeyExchange.exchange_keys);
// check preMasterSecret:
if (preMasterSecret.length != 48
|| preMasterSecret[0] != clientHello.client_version[0]
|| preMasterSecret[1] != clientHello.client_version[1]) {
// incorrect preMasterSecret
// prevent an attack (see TLS 1.0 spec., 7.4.7.1.)
preMasterSecret = new byte[48];
parameters.getSecureRandom().nextBytes(
preMasterSecret);
}
} catch (Exception e) {
fatalAlert(AlertProtocol.INTERNAL_ERROR,
"INTERNAL ERROR", e);
}
} else { // diffie hellman key exchange
clientKeyExchange = new ClientKeyExchange(io_stream,
length, serverHello.server_version[1] == 1,
false);
if (clientKeyExchange.isEmpty()) {
// TODO check that client cert. DH params
// matched server cert. DH params
// client cert. contains fixed DH parameters
preMasterSecret = ((DHPublicKey) clientCert.certs[0]
.getPublicKey()).getY().toByteArray();
} else {
PublicKey clientPublic;
KeyAgreement agreement;
try {
KeyFactory kf = null;
try {
kf = KeyFactory.getInstance("DH");
} catch (NoSuchAlgorithmException ee) {
kf = KeyFactory
.getInstance("DiffieHellman");
}
try {
agreement = KeyAgreement.getInstance("DH");
} catch (NoSuchAlgorithmException ee) {
agreement = KeyAgreement
.getInstance("DiffieHellman");
}
clientPublic = kf
.generatePublic(new DHPublicKeySpec(
new BigInteger(
1,
clientKeyExchange.exchange_keys),
serverKeyExchange.par1,
serverKeyExchange.par2));
agreement.init(privKey);
agreement.doPhase(clientPublic, true);
preMasterSecret = agreement.generateSecret();
} catch (Exception e) {
fatalAlert(AlertProtocol.INTERNAL_ERROR,
"INTERNAL ERROR", e);
return;
}
}
}
computerMasterSecret();
break;
case 20: // FINISHED
if (!isResuming && !changeCipherSpecReceived) {
unexpectedMessage();
return;
}
clientFinished = new Finished(io_stream, length);
verifyFinished(clientFinished.getData());
parameters.getServerSessionContext().putSession(session);
if (!isResuming) {
sendChangeCipherSpec();
} else {
session.lastAccessedTime = System.currentTimeMillis();
status = FINISHED;
}
break;
default:
unexpectedMessage();
return;
}
} catch (IOException e) {
// io stream dosn't contain complete handshake message
io_stream.reset();
return;
}
}
}