📄 sslhandshakeprotocol.java
字号:
/*
* SSL-Explorer
*
* Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package com.maverick.ssl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
/* DEBUG */ import org.apache.commons.logging.*;
import com.maverick.crypto.asn1.ASN1Sequence;
import com.maverick.crypto.asn1.DERInputStream;
import com.maverick.crypto.asn1.x509.CertificateException;
import com.maverick.crypto.asn1.x509.X509Certificate;
import com.maverick.crypto.asn1.x509.X509CertificateStructure;
import com.maverick.crypto.digests.MD5Digest;
import com.maverick.crypto.digests.SHA1Digest;
import com.maverick.crypto.publickey.PublicKey;
import com.maverick.crypto.publickey.Rsa;
import com.maverick.crypto.publickey.RsaPublicKey;
class SSLHandshakeProtocol {
final static int HANDSHAKE_PROTOCOL_MSG = 22;
final static int HELLO_REQUEST_MSG = 0;
final static int CLIENT_HELLO_MSG = 1;
final static int SERVER_HELLO_MSG = 2;
final static int CERTIFICATE_MSG = 11;
final static int KEY_EXCHANGE_MSG = 12;
final static int CERTIFICATE_REQUEST_MSG = 13;
final static int SERVER_HELLO_DONE_MSG = 14;
final static int CERTIFICATE_VERIFY_MSG = 15;
final static int CLIENT_KEY_EXCHANGE_MSG = 16;
final static int FINISHED_MSG = 20;
final static int HANDSHAKE_PENDING_OR_COMPLETE = -1;
SSLContext context;
SSLTransport socket;
MD5Digest handshakeMD5 = new MD5Digest();
SHA1Digest handshakeSHA1 = new SHA1Digest();
// The session components as selected by the server
SSLCipherSuiteID cipherSuiteID;
int compressionID;
byte[] sessionID;
int majorVersion;
int minorVersion;
byte[] clientRandom;
byte[] serverRandom;
byte[] premasterSecret;
byte[] masterSecret;
X509Certificate x509;
SSLCipherSuite pendingCipherSuite;
boolean wantsClientAuth = false;
int currentHandshakeStep = HANDSHAKE_PENDING_OR_COMPLETE;
/* DEBUG */ Log log = LogFactory.getLog(SSLHandshakeProtocol.class);
public SSLHandshakeProtocol(SSLTransport socket, SSLContext context) throws
IOException {
this.socket = socket;
this.context = context;
}
boolean isComplete() {
return currentHandshakeStep == HANDSHAKE_PENDING_OR_COMPLETE;
}
void processMessage(byte[] fragment, int off, int len) throws SSLException {
ByteArrayInputStream reader = new ByteArrayInputStream(fragment, off, len);
// Update the handshake hashes
updateHandshakeHashes(fragment);
while (reader.available() > 0 && !isComplete()) {
int type = reader.read();
int length = (reader.read() & 0xFF) << 16
| (reader.read() & 0xFF) << 8
| (reader.read() & 0xFF);
/* DEBUG */ log.debug("Handshake protocol is processing type "
/* DEBUG */ + type + " with " + length + " bytes of message data");
byte[] msg = new byte[length];
try {
reader.read(msg);
}
catch (IOException ex) {
throw new SSLException(SSLException.INTERNAL_ERROR,
ex.getMessage() == null ? ex.getClass().getName() :
ex.getMessage());
}
switch (type) {
case HELLO_REQUEST_MSG:
/* DEBUG */ log.debug("Received HELLO request");
/**
* If we receive a hello request then a handshake must be
* re-negotiated. But ignore it if were already performing
* a handshake operation
*/
if (currentHandshakeStep == HANDSHAKE_PENDING_OR_COMPLETE) {
startHandshake();
}
break;
case SERVER_HELLO_MSG:
/* DEBUG */ log.debug("Received server HELLO message");
if (currentHandshakeStep != CLIENT_HELLO_MSG) {
throw new SSLException(SSLException.PROTOCOL_VIOLATION,
"Server HELLO message received but not expected ("
+ currentHandshakeStep + ")");
}
onServerHelloMsg(msg);
break;
case CERTIFICATE_MSG:
/* DEBUG */ log.debug("Received server certificate");
if (currentHandshakeStep != SERVER_HELLO_MSG) {
throw new SSLException(SSLException.PROTOCOL_VIOLATION,
"Certificate message received but not expected ("
+ currentHandshakeStep + ")");
}
onCertificateMsg(msg);
break;
case KEY_EXCHANGE_MSG:
/* DEBUG */ log.debug(
/* DEBUG */ "Received server key exchange [Unsupported operation]");
throw new SSLException(SSLException.UNSUPPORTED_OPERATION,
"We currently dont support server key exchange!");
case CERTIFICATE_REQUEST_MSG:
/* DEBUG */ log.debug(
/* DEBUG */ "Received client certificate request [Unsupported operation]");
wantsClientAuth = true;
break;
case SERVER_HELLO_DONE_MSG:
/* DEBUG */ log.debug("Received server HELLO DONE");
if (currentHandshakeStep != CERTIFICATE_MSG) {
throw new SSLException(SSLException.PROTOCOL_VIOLATION,
"Server HELLO DONE message received but not expected ("
+ currentHandshakeStep + ")");
}
if(wantsClientAuth) {
/* DEBUG */log.debug("Sending no certificate alert");
socket.sendMessage(SSLTransport.ALERT_PROTOCOL,
new byte[] { (byte) SSLTransport.WARNING_ALERT,
(byte) SSLException.NO_CERTIFICATE});
}
onServerHelloDoneMsg();
break;
case FINISHED_MSG:
/* DEBUG */ log.debug("Received server FINISHED");
if (currentHandshakeStep != FINISHED_MSG) {
throw new SSLException(SSLException.PROTOCOL_VIOLATION);
}
currentHandshakeStep = HANDSHAKE_PENDING_OR_COMPLETE;
break;
default:
}
}
}
private void sendMessage(int type, byte[] data) throws SSLException {
ByteArrayOutputStream msg = new ByteArrayOutputStream();
try {
msg.write(type);
msg.write( (data.length >> 16) & 0xFF);
msg.write( (data.length >> 8) & 0xFF);
msg.write(data.length);
msg.write(data);
}
catch (IOException ex) {
throw new SSLException(SSLException.INTERNAL_ERROR,
ex.getMessage() == null ? ex.getClass().getName() :
ex.getMessage());
}
byte[] m = msg.toByteArray();
// Update the handshake hashes if its anything but the FINISHED_MSG
if (type != FINISHED_MSG) {
updateHandshakeHashes(m);
}
socket.sendMessage(HANDSHAKE_PROTOCOL_MSG, m);
}
public void startHandshake() throws SSLException {
if (currentHandshakeStep != HANDSHAKE_PENDING_OR_COMPLETE) {
throw new SSLException(
SSLException.PROTOCOL_VIOLATION,
"Handshake cannot be started as a handshake operation is in progress");
}
/* DEBUG */ log.debug("Starting SSL Handshake");
sendClientHello();
}
private void calculateMasterSecret() throws SSLException {
/* DEBUG */ log.debug("Calculating master secret");
try {
MD5Digest md5 = new MD5Digest();
SHA1Digest sha1 = new SHA1Digest();
ByteArrayOutputStream out = new ByteArrayOutputStream();
String[] mixers = new String[] {
"A", "BB", "CCC"};
for (int i = 0; i < mixers.length; i++) {
md5.reset();
sha1.reset();
sha1.update(mixers[i].getBytes(), 0, mixers[i].getBytes().length);
sha1.update(premasterSecret, 0, premasterSecret.length);
sha1.update(clientRandom, 0, clientRandom.length);
sha1.update(serverRandom, 0, serverRandom.length);
md5.update(premasterSecret, 0, premasterSecret.length);
byte[] tmp = new byte[sha1.getDigestSize()];
sha1.doFinal(tmp, 0);
md5.update(tmp, 0, tmp.length);
tmp = new byte[md5.getDigestSize()];
md5.doFinal(tmp, 0);
out.write(tmp);
}
masterSecret = out.toByteArray();
}
catch (IOException ex) {
throw new SSLException(SSLException.INTERNAL_ERROR,
ex.getMessage() == null ? ex.getClass().getName() :
ex.getMessage());
}
}
private void calculatePreMasterSecret() {
/* DEBUG */ log.debug("Generating pre-master secret");
premasterSecret = new byte[48];
context.getRND().nextBytes(premasterSecret);
premasterSecret[0] = (byte) SSLTransport.VERSION_MAJOR;
premasterSecret[1] = (byte) SSLTransport.VERSION_MINOR;
}
private void debugBytes(byte[] b, String s) {
System.out.print(s + ": ");
for (int i = 0; i < b.length; i++) {
System.out.print(Integer.toHexString( (int) (b[i] & 0xFF)));
}
System.out.println();
}
private void onServerHelloDoneMsg() throws SSLException {
// Generate the premaster secret
calculatePreMasterSecret();
byte[] secret = null;
try {
// Encrypt the premaster secret
BigInteger input = new BigInteger(1, premasterSecret);
PublicKey key = x509.getPublicKey();
if (key instanceof RsaPublicKey) {
BigInteger padded = Rsa.padPKCS1(input, 0x02, 128,
new com.maverick.crypto.security.
SecureRandom());
BigInteger s = Rsa.doPublic(padded, ( (RsaPublicKey) key).getModulus(),
( (RsaPublicKey) key).getPublicExponent());
secret = s.toByteArray();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -