SSLEngine 在解包服务器 hello done 后给出 NEED_UNWRAP
SSLEngine giving NEED_UNWRAP after unwrapping server hello done
我正在使用 java 9 提供的 DTLS1.0
。它成功生成 Client Hello
并且服务器响应返回
1. Server Hello
2. Certificate
3. Server Key Exchange
4. Certificate Request
5. Server Hello Done
然后 SSLEngine 给出 NEED_UNWRAP
。在打开包含 Server Hello Done
的数据包后,它再次给出 NEED_UNWRAP
。在展开下一个重新传输的 Server Hello Done
后,它再次给出 NEED_UNWRAP
。它一次又一次地发生。但我认为它应该通过给出 NEED_WRAP
来生成下一个握手信号。
如果我错了,请指正。否则为什么会这样?
信任经理:
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
}
};
SSLEngine:
char[] passphrase = "123456".toCharArray();//This is the password
// First initialize the key and trust material
KeyStore ksKeys = KeyStore.getInstance("JKS");
ksKeys.load(new FileInputStream("keystore"), passphrase);
// KeyManagers decide which key material to use
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ksKeys, passphrase);
SSLContext sslContext = SSLContext.getInstance("DTLSv1.0");
sslContext.init(kmf.getKeyManagers(), trustAllCerts, null);
int port2 = Queuemanager.switchMediaHandler.get("192.168.19.148").realPort;
// Create the engine
engine = sslContext.createSSLEngine("192.168.19.148", port2);
// Use as client
engine.setUseClientMode(true);
engine.setEnableSessionCreation(true);
握手:
void doHandshake(){
engine.beginHandshake();
SSLEngineResult result;
HandshakeStatus handshakeStatus;
int appBufferSize = engine.getSession().getApplicationBufferSize();
ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize);
ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize);
myNetData.clear();
peerNetData.clear();
handshakeStatus = engine.getHandshakeStatus();
while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
switch (handshakeStatus) {
case NEED_UNWRAP_AGAIN:
logger.debug("NEED_UNWRAP_AGAIN");
case NEED_UNWRAP:
logger.debug("NEED_UNWRAP");
DatagramPacket packet = null;
if(handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ) {
try {
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
peerNetData = ByteBuffer.wrap(buf, 0, packet.getLength());
peerAppData = ByteBuffer.allocate(appBufferSize);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}else{
peerNetData = ByteBuffer.allocate(0);
peerAppData = ByteBuffer.allocate(appBufferSize);
}
SSLEngineResult.Status rs;
result = null;
try {
handshakeStatus = engine.getHandshakeStatus();
while(handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP || handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
result = engine.unwrap(peerNetData, peerAppData);
peerNetData.compact();
handshakeStatus = result.getHandshakeStatus();
}
handshakeStatus = result.getHandshakeStatus();
rs = result.getStatus();
} catch (SSLException sslException) {
engine.closeOutbound();
break;
}
switch (rs) {
case OK:
break;
case BUFFER_OVERFLOW:
break;
case BUFFER_UNDERFLOW:
break;
case CLOSED:
default:
throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
}
break;
case NEED_WRAP:
logger.debug("NEED_WRAP");
myNetData.clear();
try {
result = engine.wrap(myAppData, myNetData);
handshakeStatus = result.getHandshakeStatus();
} catch (SSLException sslException) {
engine.closeOutbound();
handshakeStatus = engine.getHandshakeStatus();
break;
}
switch (result.getStatus()) {
case OK :
while (myNetData.hasRemaining()) {
//String str = myNetData.toString();
byte[] arr = new byte[myNetData.remaining()];
myNetData.get(arr);
recvPacket = new DatagramPacket(arr, arr.length);
recvPacket.setData(arr);
try {
int port2 = Queuemanager.switchMediaHandler.get("192.168.19.148").realPort;
InetAddress ip = InetAddress.getByName("192.168.19.148");
recvPacket.setAddress(ip);
recvPacket.setPort(port2);
socket.send(recvPacket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//socketChannel.write(myNetData);
}
case BUFFER_OVERFLOW:
case BUFFER_UNDERFLOW:
case CLOSED:
case NEED_TASK:
Runnable task;
while ((task = engine.getDelegatedTask()) != null) {
new Thread(task).start();
}
handshakeStatus = engine.getHandshakeStatus();
break;
}
}
你正在做这个从前到后。当引擎说 NEED_UNWRAP, 展开。 然后,if that returns BUFFER_UNDERFLOW,做阅读并再次尝试展开。不要只是假设您需要再阅读 NEED_UNWRAP。您可能会丢失来自 peerNetData
的数据。并且不要通过 ByteBuffer.wrap()
或 .allocate()
创建新的 peerNetData
:继续使用相同的,并使用 put()
将数据报数据 放入它。然后 compact()
在每次成功的引擎解包后它。
换句话说,严格按照它告诉你的去做。
SSLEngine
是一件很难做到的事情。许多人尝试过,但很少有人成功。对于一个成功的工作,这是商业产品的基础,请参阅我的书 Fundamental Networking Java[=29= 中的源代码中的 SSLEngineManager
class ], 施普林格 2006, here.
我正在使用 java 9 提供的 DTLS1.0
。它成功生成 Client Hello
并且服务器响应返回
1. Server Hello
2. Certificate
3. Server Key Exchange
4. Certificate Request
5. Server Hello Done
然后 SSLEngine 给出 NEED_UNWRAP
。在打开包含 Server Hello Done
的数据包后,它再次给出 NEED_UNWRAP
。在展开下一个重新传输的 Server Hello Done
后,它再次给出 NEED_UNWRAP
。它一次又一次地发生。但我认为它应该通过给出 NEED_WRAP
来生成下一个握手信号。
如果我错了,请指正。否则为什么会这样?
信任经理:
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
}
};
SSLEngine:
char[] passphrase = "123456".toCharArray();//This is the password
// First initialize the key and trust material
KeyStore ksKeys = KeyStore.getInstance("JKS");
ksKeys.load(new FileInputStream("keystore"), passphrase);
// KeyManagers decide which key material to use
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ksKeys, passphrase);
SSLContext sslContext = SSLContext.getInstance("DTLSv1.0");
sslContext.init(kmf.getKeyManagers(), trustAllCerts, null);
int port2 = Queuemanager.switchMediaHandler.get("192.168.19.148").realPort;
// Create the engine
engine = sslContext.createSSLEngine("192.168.19.148", port2);
// Use as client
engine.setUseClientMode(true);
engine.setEnableSessionCreation(true);
握手:
void doHandshake(){
engine.beginHandshake();
SSLEngineResult result;
HandshakeStatus handshakeStatus;
int appBufferSize = engine.getSession().getApplicationBufferSize();
ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize);
ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize);
myNetData.clear();
peerNetData.clear();
handshakeStatus = engine.getHandshakeStatus();
while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
switch (handshakeStatus) {
case NEED_UNWRAP_AGAIN:
logger.debug("NEED_UNWRAP_AGAIN");
case NEED_UNWRAP:
logger.debug("NEED_UNWRAP");
DatagramPacket packet = null;
if(handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ) {
try {
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
peerNetData = ByteBuffer.wrap(buf, 0, packet.getLength());
peerAppData = ByteBuffer.allocate(appBufferSize);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}else{
peerNetData = ByteBuffer.allocate(0);
peerAppData = ByteBuffer.allocate(appBufferSize);
}
SSLEngineResult.Status rs;
result = null;
try {
handshakeStatus = engine.getHandshakeStatus();
while(handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP || handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
result = engine.unwrap(peerNetData, peerAppData);
peerNetData.compact();
handshakeStatus = result.getHandshakeStatus();
}
handshakeStatus = result.getHandshakeStatus();
rs = result.getStatus();
} catch (SSLException sslException) {
engine.closeOutbound();
break;
}
switch (rs) {
case OK:
break;
case BUFFER_OVERFLOW:
break;
case BUFFER_UNDERFLOW:
break;
case CLOSED:
default:
throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
}
break;
case NEED_WRAP:
logger.debug("NEED_WRAP");
myNetData.clear();
try {
result = engine.wrap(myAppData, myNetData);
handshakeStatus = result.getHandshakeStatus();
} catch (SSLException sslException) {
engine.closeOutbound();
handshakeStatus = engine.getHandshakeStatus();
break;
}
switch (result.getStatus()) {
case OK :
while (myNetData.hasRemaining()) {
//String str = myNetData.toString();
byte[] arr = new byte[myNetData.remaining()];
myNetData.get(arr);
recvPacket = new DatagramPacket(arr, arr.length);
recvPacket.setData(arr);
try {
int port2 = Queuemanager.switchMediaHandler.get("192.168.19.148").realPort;
InetAddress ip = InetAddress.getByName("192.168.19.148");
recvPacket.setAddress(ip);
recvPacket.setPort(port2);
socket.send(recvPacket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//socketChannel.write(myNetData);
}
case BUFFER_OVERFLOW:
case BUFFER_UNDERFLOW:
case CLOSED:
case NEED_TASK:
Runnable task;
while ((task = engine.getDelegatedTask()) != null) {
new Thread(task).start();
}
handshakeStatus = engine.getHandshakeStatus();
break;
}
}
你正在做这个从前到后。当引擎说 NEED_UNWRAP, 展开。 然后,if that returns BUFFER_UNDERFLOW,做阅读并再次尝试展开。不要只是假设您需要再阅读 NEED_UNWRAP。您可能会丢失来自 peerNetData
的数据。并且不要通过 ByteBuffer.wrap()
或 .allocate()
创建新的 peerNetData
:继续使用相同的,并使用 put()
将数据报数据 放入它。然后 compact()
在每次成功的引擎解包后它。
换句话说,严格按照它告诉你的去做。
SSLEngine
是一件很难做到的事情。许多人尝试过,但很少有人成功。对于一个成功的工作,这是商业产品的基础,请参阅我的书 Fundamental Networking Java[=29= 中的源代码中的 SSLEngineManager
class ], 施普林格 2006, here.