尽管从未手动关闭套接字,但由于 SocketException 而导致 DTLS 握手失败
DTLS handshaking failure due to SocketException though the socket was never closed menually
抱歉,问题可能有点含糊。
尝试与 webrtc 网关建立 webrtc 连接。使用 accept 或 connect 函数执行 dtls 握手时,抛出 SocketException。
这里是错误:
java.net.SocketException: Socket is closed
at java.net.DatagramSocket.send(DatagramSocket.java:658)
at org.bouncycastle.crypto.tls.UDPTransport.send(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSRecordLayer.sendRecord(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSRecordLayer.send(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake$RecordLayerBuffer.sendToRecordLayer(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.writeHandshakeFragment(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.writeMessage(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.resendOutboundFlight(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.receiveMessage(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSServerProtocol.serverHandshake(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSServerProtocol.accept(Unknown Source)
at callProcessor.DTLSManager.startDTLS(DTLSManager.java:421)
at callProcessor.DTLSManager.processSTUNResponse(DTLSManager.java:554)
多次检查是否有任何其他线程正在关闭套接字,但 none 并在传递套接字之前检查它是否已关闭,得到 false。(SoTimeOut 为 60000)
代码片段:
tlsServer = new DefaultTlsServer2() {
public void notifyClientCertificate(org.bouncycastle.crypto.tls.Certificate clientCertificate) throws IOException {
org.bouncycastle.asn1.x509.Certificate[] chain = clientCertificate.getCertificateList();
logger.debug("notifyClientCertificate: " + chain[0].getSignature());
/*// JFLog.log("Received client certificate chain of length " + chain.length);
for (int i = 0; i != chain.length; i++) {
org.bouncycastle.asn1.x509.Certificate entry = chain[i];
// JFLog.log("fingerprint:SHA-256 " + KeyMgmt.fingerprintSHA256(entry.getEncoded()) + " (" + entry.getSubject() + ")");
// JFLog.log("cert length=" + entry.getEncoded().length);
}*/
}
protected ProtocolVersion getMaximumVersion() {
logger.debug("getMaximumVersion: " + ProtocolVersion.DTLSv10);
return ProtocolVersion.DTLSv10;
}
protected ProtocolVersion getMinimumVersion() {
logger.debug("getMinimumVersion: " + ProtocolVersion.DTLSv10);
return ProtocolVersion.DTLSv10;
}
protected TlsEncryptionCredentials getRSAEncryptionCredentials() throws IOException {
logger.debug("getRSAEncryptionCredentials");
return new DefaultTlsEncryptionCredentials(context, dtlsInfo.getCertChain(), dtlsInfo.getPrivateKey());
}
@SuppressWarnings("rawtypes")
protected TlsSignerCredentials getRSASignerCredentials() throws IOException {
SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
Vector sigAlgs = supportedSignatureAlgorithms;
if (sigAlgs != null) {
for (int i = 0; i < sigAlgs.size(); ++i) {
SignatureAndHashAlgorithm sigAlg = (SignatureAndHashAlgorithm) sigAlgs.elementAt(i);
if (sigAlg.getSignature() == SignatureAlgorithm.rsa) {
signatureAndHashAlgorithm = sigAlg;
break;
}
}
if (signatureAndHashAlgorithm == null) {
return null;
}
}
logger.debug("getRSASignerCredentials");
return new DefaultTlsSignerCredentials(context, dtlsInfo.getCertChain(), dtlsInfo.getPrivateKey(), signatureAndHashAlgorithm);
}
@SuppressWarnings("rawtypes")
public Hashtable getServerExtensions() throws IOException {
//see : http://bouncy-castle.1462172.n4.nabble.com/DTLS-SRTP-with-bouncycastle-1-49-td4656286.html
Hashtable table = super.getServerExtensions();
if (table == null) table = new Hashtable();
int[] protectionProfiles = {
// TODO : need to pick ONE that client offers
SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_80 //this is the only one supported for now
// SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_32
// SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_32
// SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_80
};
byte mki[] = new byte[0]; //should match client or use nothing
UseSRTPData srtpData = new UseSRTPData(protectionProfiles, mki);
TlsSRTPUtils.addUseSRTPExtension(table, srtpData);
logger.debug("getServerExtensions: " + table.size());
return table;
}
public void notifyHandshakeComplete() throws IOException {
logger.debug("SRTPChannel:DTLS:Server:Handshake complete");
super.notifyHandshakeComplete();
getKeys();
remoteKey = tlsServer.getRemoteKey();
remoteSalt = tlsServer.getRemoteSalt();
localKey = tlsServer.getLocalKey();
localSalt = tlsServer.getLocalSalt();
logger.debug("keys got here server");
isHandshakeComplete = 1;
logger.debug("isHandshakeComplete: " + isHandshakeComplete);
}
};
try {
logger.debug("SRTPChannel: accept dtlsCLient by DTLS server");
logger.debug("DTLS before accept:socket state:Socket is closed ?"+socket.isClosed()+socket.isConnected());
dtlsServer.accept(tlsServer, new UDPTransport(socket, 1500 - 20 - 8));
udp_started = true;
} catch (Exception e) {
logger.fatal("Exception: ",e);
}
使用来自 bcprov-ext-jdkon-159.jar 和 bcprov-jdk15on-160b04.jar
的 bouncycastle.crypto.tls 库
注意:此系统已启动,运行现在遇到此问题,无法确定触发此问题的原因。
问题在于它使用的是已从浏览器中删除的 DTLSv10。
将 DTLSv10 升级到 DTLS12 解决了套接字关闭问题,但在同一 DTLSServerProtocol.accept 函数中引入了一个 interal_error,这是由 bouncyCastle 库 bcprov-ext-jdkon 的内部库错误引起的-159.jar.
将库 jar 升级到 bcprov-ext-jdk15on-1。61.jar 解决了这个问题,现在服务器成功地与浏览器握手以使用 webrtc 进行 VoIP 呼叫。
抱歉,问题可能有点含糊。 尝试与 webrtc 网关建立 webrtc 连接。使用 accept 或 connect 函数执行 dtls 握手时,抛出 SocketException。
这里是错误:
java.net.SocketException: Socket is closed
at java.net.DatagramSocket.send(DatagramSocket.java:658)
at org.bouncycastle.crypto.tls.UDPTransport.send(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSRecordLayer.sendRecord(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSRecordLayer.send(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake$RecordLayerBuffer.sendToRecordLayer(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.writeHandshakeFragment(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.writeMessage(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.resendOutboundFlight(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSReliableHandshake.receiveMessage(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSServerProtocol.serverHandshake(Unknown Source)
at org.bouncycastle.crypto.tls.DTLSServerProtocol.accept(Unknown Source)
at callProcessor.DTLSManager.startDTLS(DTLSManager.java:421)
at callProcessor.DTLSManager.processSTUNResponse(DTLSManager.java:554)
多次检查是否有任何其他线程正在关闭套接字,但 none 并在传递套接字之前检查它是否已关闭,得到 false。(SoTimeOut 为 60000)
代码片段:
tlsServer = new DefaultTlsServer2() {
public void notifyClientCertificate(org.bouncycastle.crypto.tls.Certificate clientCertificate) throws IOException {
org.bouncycastle.asn1.x509.Certificate[] chain = clientCertificate.getCertificateList();
logger.debug("notifyClientCertificate: " + chain[0].getSignature());
/*// JFLog.log("Received client certificate chain of length " + chain.length);
for (int i = 0; i != chain.length; i++) {
org.bouncycastle.asn1.x509.Certificate entry = chain[i];
// JFLog.log("fingerprint:SHA-256 " + KeyMgmt.fingerprintSHA256(entry.getEncoded()) + " (" + entry.getSubject() + ")");
// JFLog.log("cert length=" + entry.getEncoded().length);
}*/
}
protected ProtocolVersion getMaximumVersion() {
logger.debug("getMaximumVersion: " + ProtocolVersion.DTLSv10);
return ProtocolVersion.DTLSv10;
}
protected ProtocolVersion getMinimumVersion() {
logger.debug("getMinimumVersion: " + ProtocolVersion.DTLSv10);
return ProtocolVersion.DTLSv10;
}
protected TlsEncryptionCredentials getRSAEncryptionCredentials() throws IOException {
logger.debug("getRSAEncryptionCredentials");
return new DefaultTlsEncryptionCredentials(context, dtlsInfo.getCertChain(), dtlsInfo.getPrivateKey());
}
@SuppressWarnings("rawtypes")
protected TlsSignerCredentials getRSASignerCredentials() throws IOException {
SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
Vector sigAlgs = supportedSignatureAlgorithms;
if (sigAlgs != null) {
for (int i = 0; i < sigAlgs.size(); ++i) {
SignatureAndHashAlgorithm sigAlg = (SignatureAndHashAlgorithm) sigAlgs.elementAt(i);
if (sigAlg.getSignature() == SignatureAlgorithm.rsa) {
signatureAndHashAlgorithm = sigAlg;
break;
}
}
if (signatureAndHashAlgorithm == null) {
return null;
}
}
logger.debug("getRSASignerCredentials");
return new DefaultTlsSignerCredentials(context, dtlsInfo.getCertChain(), dtlsInfo.getPrivateKey(), signatureAndHashAlgorithm);
}
@SuppressWarnings("rawtypes")
public Hashtable getServerExtensions() throws IOException {
//see : http://bouncy-castle.1462172.n4.nabble.com/DTLS-SRTP-with-bouncycastle-1-49-td4656286.html
Hashtable table = super.getServerExtensions();
if (table == null) table = new Hashtable();
int[] protectionProfiles = {
// TODO : need to pick ONE that client offers
SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_80 //this is the only one supported for now
// SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_32
// SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_32
// SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_80
};
byte mki[] = new byte[0]; //should match client or use nothing
UseSRTPData srtpData = new UseSRTPData(protectionProfiles, mki);
TlsSRTPUtils.addUseSRTPExtension(table, srtpData);
logger.debug("getServerExtensions: " + table.size());
return table;
}
public void notifyHandshakeComplete() throws IOException {
logger.debug("SRTPChannel:DTLS:Server:Handshake complete");
super.notifyHandshakeComplete();
getKeys();
remoteKey = tlsServer.getRemoteKey();
remoteSalt = tlsServer.getRemoteSalt();
localKey = tlsServer.getLocalKey();
localSalt = tlsServer.getLocalSalt();
logger.debug("keys got here server");
isHandshakeComplete = 1;
logger.debug("isHandshakeComplete: " + isHandshakeComplete);
}
};
try {
logger.debug("SRTPChannel: accept dtlsCLient by DTLS server");
logger.debug("DTLS before accept:socket state:Socket is closed ?"+socket.isClosed()+socket.isConnected());
dtlsServer.accept(tlsServer, new UDPTransport(socket, 1500 - 20 - 8));
udp_started = true;
} catch (Exception e) {
logger.fatal("Exception: ",e);
}
使用来自 bcprov-ext-jdkon-159.jar 和 bcprov-jdk15on-160b04.jar
的 bouncycastle.crypto.tls 库注意:此系统已启动,运行现在遇到此问题,无法确定触发此问题的原因。
问题在于它使用的是已从浏览器中删除的 DTLSv10。
将 DTLSv10 升级到 DTLS12 解决了套接字关闭问题,但在同一 DTLSServerProtocol.accept 函数中引入了一个 interal_error,这是由 bouncyCastle 库 bcprov-ext-jdkon 的内部库错误引起的-159.jar.
将库 jar 升级到 bcprov-ext-jdk15on-1。61.jar 解决了这个问题,现在服务器成功地与浏览器握手以使用 webrtc 进行 VoIP 呼叫。