![](/img/trans.png)
[英]REST client with TLS returns SSLHandshakeException: Received fatal alert: handshake_failure
[英]Decrypt bytes received from a websocket client on tls before the handshake
我開發了一個與 websockets 兼容的 sockets 服務器來通信用 java 和 web 制作的應用程序。 但是最新的 Chrome 和 Mozilla 更新不再允許與 websockets 的不安全連接。 然后我被迫在繼續握手和協議的其余部分之前解密我的服務器收到的字節https://www.rfc-editor.org/rfc/rfc6455
我取得了以下成績:
從 CA 簽署的證書中獲取公鑰。 還有我服務器的私鑰
使用 Java 的 Cipher 類,我設法使用這些密鑰來加密和解密測試字符串
但是我仍然不能做的是在繼續握手之前解密我從 websocket 客戶端收到的字節。
我希望你能幫助我。 謝謝
我收到的錯誤:數據不得超過 256 字節
解決了! 解密委托給 SSLSocket 類。 如果有人想在這里做這些步驟。
將CA頒發的證書和私鑰導出到p12文件
openssl pkcs12 -export -in certificate/path/certificate.crt -inkey /path/privatekey/private.key -out filep12.p12 -name your_domain -CAfile /path/ca.crt -caname your_ca
Java 密鑰庫
keytool -genkey -alias your_alias -keyalg RSA -keystore name_store.jks -keysize 2048
輸入密碼(your_password)並確認后
keytool -importkeystore -srckeystore name_store.jks -destkeystore name_store.jks -deststoretype pkcs12 -srcstorepass your_password
keytool -delete -alias your_alias -keystore name_store.jks -storepass your_password
keytool -importkeystore -deststorepass your_password -destkeypass your_password -destkeystore name_store.jks -srckeystore filep12.p12 -srcstoretype PKCS12 -srcstorepass your_password -alias your_domain
your_alias 不能與 your_domain 相同或相似,要求在每個步驟中輸入的密碼 (your_password) 始終相同,以便在解密時不會出現填充錯誤
java中的類
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
public class SServidor {
public SServidor(){
try {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
File keystrorefile = new File("/path/name_store.jks");
System.out.println(keystrorefile.getAbsolutePath());
InputStream keystoreStream = new FileInputStream(keystrorefile);
char[] passphrase="your_password".toCharArray();
keystore.load(keystoreStream, passphrase);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, passphrase);
makeSSLSocketFactory(keystore, keyManagerFactory);
} catch (KeyStoreException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (CertificateException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnrecoverableKeyException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void log(Object msj){
System.out.println(msj.toString());
}
public void makeSSLSocketFactory(KeyStore loadedKeyStore, KeyManagerFactory key){
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(loadedKeyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(key.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
SSLServerSocketFactory sslssf = ctx.getServerSocketFactory();
ServerSocket conexion = sslssf.createServerSocket(your_port);
SSLSocket cliente=(SSLSocket) conexion.accept();
cliente.startHandshake();
InputStream in = cliente.getInputStream();
OutputStream out = cliente.getOutputStream();
int byte_recibido=-1;
while(cliente.isConnected() && (byte_recibido=in.read())>-1){
Integer n=byte_recibido & 0xFF;
String s=new String(String.valueOf(Character.toChars(n)));
log(s);
}
out.close();
bin.close();
in.close();
cliente.close();
conexion.close();
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (KeyStoreException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (KeyManagementException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}`
別的,websocket 的連接應該是這樣的 wss://your_domain:port 不能在 websocket url 中輸入 IP 地址,必須使用 CA 頒發的證書中注冊的域來完成
使用解密的字節,我可以繼續使用 RFC6455 協議。 這只是我做的測試,顯然是針對sockets的應用,另外需要異步處理連接到服務器的客戶端。 我用 ExecutorService 類來做這件事,但那是另一個話題
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.