显示标签为“ssl”的博文。显示所有博文
显示标签为“ssl”的博文。显示所有博文

2008年7月10日星期四

考完高数的郁闷和听说RSA破解理论的惊奇

今天某熊考高数啊……2个星期以前就结课,一直没看……结果自然是……郁闷。
回来以后遇到一位来自德国的仁兄,问我那个SSL证书的事情,但是他要求的目的很奇怪:不要求验证证书的有效性,而且还要收集证书。
某熊好奇的问了一句收集证书做什么用。得到了一个意想不到的回答:通过大量的收集SSL证书,然后根据某个理论,找出可能出错的那个证书,从而逆退出根ca的私钥?
某熊不是搞加密的,也不是很懂。这位仁兄的原话在这里:

***** 22:51:57
我收集证书用来探测其中RSA算法的漏洞
***** 22:52:43
虽然其概率很小,但是可能比如一万份里或者十万份里会有一个带着错误RSA算法的证书
***** 22:53:20
根据他里面的错误的签名,就可以破解整个CA的私钥
***** 22:54:09
理论基础是中国剩余定理,RSA是基于这个方法制作签名的。
IcyBear 22:54:06
根据签名和明文逆推私钥么?
***** 22:55:19
对,是的。前提是,RSA是基于中国剩余定理,并在特定的环境,比如温度高或者磁场因素等等,会偶然的生成错误的签名
***** 22:55:35
那这个签名就是攻破整个CA系统的钥匙
IcyBear 22:56:01
祝你成功~~
IcyBear 22:56:16
这样需要的运算量大么?
开放式互联 22:57:12
呵呵,谢谢,现在才是万里长征的第一步,运算量蛮大的,但首先须收集到足够的证书,及错误的签名

具体是不是真的可行,我就不知道了。作为位仁兄给出了一个参考资料的地址,有兴趣的童鞋们可以去看看,英文的哦。
http://www.geocities.com/marcjoye/papers/chinese99.pdf

2008年7月5日星期六

使用Java进行双向认证的SSL链接以及使用OpenSSL生产证书链

这几天被SSL和证书搞得头昏脑胀的。不过还好终于把这个SSL搞定了。

用SSL进行双向身份验证意思就是在客户机连接服务器时,链接双方都要对彼此的数字证书进行验证,保证这是经过授权的才能够连接(我们链接一般的SSL时采用的是单向验证,客户机只验证服务器的证书,服务器不验证客户机的证书。而连接网上银行时使用的U盾就是用来存储进行双向验证所需要的客户端证书的)。

JDK里面内置了一个数字证书生产工具:keytool。但是这个工具只能生成自签名的数字证书。所谓自签名就是指证书只能保证自己是完整的,没有经过非法修改的。但是无法保证这个证书是属于谁的。其实用这种自签名的证书也是可以进行双向验证的(用keytool生成的自签名证书进行双向验证请看这里,向这位仁兄致意~:http://www.blogjava.net/stone2083/archive/2007/12/20/169015.html),但是这种验证有一个缺点:对于每一个要链接的服务器,都要保存一个证书的验证副本。而且一旦服务器更换证书,所有客户端就需要重新部署这些副本。对于比较大型的应用来说,这一点是不可接受的。所以就需要证书链进行双向认证。证书链是指对证书的签名又一个预先部署的,众所周知的签名方签名完成,这样每次需要验证证书时只要用这个公用的签名方的公钥进行验证就可以了。比如我们使用的浏览器就保存了几个常用的CA_ROOT。每次连接到网站时只要这个网站的证书是经过这些CA_ROOT签名过的。就可以通过验证了。

但是这些共用的CA_ROOT的服务不是免费的。而且价格不菲。所以我们有必要自己生成一个CA_ROOT的密钥对,然后部署应用时,只要把这个CA_ROOT的私钥部署在所有节点就可以完成验证了。要进行CA_ROOT的生成,需要OpenSSL(http://www.openssl.org/)。你也可以在http://www.slproweb.com/products/Win32OpenSSL.html找到Windows下的版本

安装好OpenSSL以后就可以生成证书链了,我写了一个BAT解决这些东西:



@echo off
:OpenSSL配置文件路径(如果出现“The organizationName field needed to be the same in the”之类的错误,请编辑此文件,修改CA_default节中的policy = policy_match为policy = policy_anything
set CONFIG="D:\OpenSSL\bin\openssl.cfg"
:服务器证书库密码
set PWD_SERVER_KS=serverks
:服务器证书密码
set PWD_SERVER_KEY=serverkey
:客户端证书库密码
set PWD_CLIENT_KS=clientks
:客户端证书密码
set PWD_CLIENT_KEY=clientkey
:有效期(天)
set VALIDITY=365
:服务器证书名
set SERVER_CERT_NAME=logon_server_private_key
:客户端证书名
set CLIENT_CERT_NAME=ipclient_private_key
:服务器证书库文件名
set SERVER_KEYSTORE_NAME=server.keystore
:客户端证书库文件名
set CLIENT_KEYSTORE_NAME=client.keystore

if not exist DemoCA (
mkdir DemoCA
mkdir DemoCA\certs
mkdir DemoCA\newcerts
echo CAFEBABE>DemoCA\serial
copy nul DemoCA\index.txt
)

if not exist ca.key (
echo Generating a ca root key file...
openssl req -new -x509 -keyout ca.key -out ca.crt -config %CONFIG%
) else (
echo ca.key already exists...
)

if not exist server.keystore (
echo Generating server's private key...
keytool -genkey -alias %SERVER_CERT_NAME% -validity %VALIDITY% -keyalg RSA -keysize 1024 -keystore %SERVER_KEYSTORE_NAME% -keypass %PWD_SERVER_KEY% -storepass %PWD_SERVER_KS%
) else (
echo server.keystore already exits...
)

if not exist client.keystore (
echo Generating client's private key...
keytool -genkey -alias %CLIENT_CERT_NAME% -validity %VALIDITY% -keyalg RSA -keysize 1024 -keystore %CLIENT_KEYSTORE_NAME% -keypass %PWD_CLIENT_KEY% -storepass %PWD_CLIENT_KS%
) else (
echo client.keystore already exits...
)

echo ========Finished key generation=========

if not exist %SERVER_CERT_NAME%.csr (
echo Generating server's singature request file...
keytool -certreq -alias %SERVER_CERT_NAME% -sigalg MD5withRSA -file %SERVER_CERT_NAME%.csr -keypass %PWD_SERVER_KEY% -storepass %PWD_SERVER_KS% -keystore %SERVER_KEYSTORE_NAME%
) else (
echo %SERVER_CERT_NAME%.csr already exits...
)

if not exist %CLIENT_CERT_NAME%.csr (
echo Generating client's singature request file...
keytool -certreq -alias %CLIENT_CERT_NAME% -sigalg MD5withRSA -file %CLIENT_CERT_NAME%.csr -keypass %PWD_CLIENT_KEY% -storepass %PWD_CLIENT_KS% -keystore %CLIENT_KEYSTORE_NAME%
) else (
echo %CLIENT_CERT_NAME%.csr already exits...
)

if not exist %SERVER_CERT_NAME%.crt (
openssl ca -in %SERVER_CERT_NAME%.csr -out %SERVER_CERT_NAME%.crt -cert ca.crt -keyfile ca.key -notext -config %CONFIG%
) else (
echo %SERVER_CERT_NAME%.crt already exits...
)

if not exist %CLIENT_CERT_NAME%.crt (
openssl ca -in %CLIENT_CERT_NAME%.csr -out %CLIENT_CERT_NAME%.crt -cert ca.crt -keyfile ca.key -notext -config %CONFIG%
) else (
echo %CLIENT_CERT_NAME%.crt already exits...
)

echo =========Finished ca root signaturing==========

echo Importing ca root certs into keystore...

keytool -import -v -trustcacerts -alias ca_root -file ca.crt -storepass %PWD_SERVER_KS% -keystore %SERVER_KEYSTORE_NAME%

keytool -import -v -trustcacerts -alias ca_root -file ca.crt -storepass %PWD_CLIENT_KS% -keystore %CLIENT_KEYSTORE_NAME%

echo Importing signatured keys...

keytool -import -v -alias %SERVER_CERT_NAME% -file %SERVER_CERT_NAME%.crt -keypass %PWD_SERVER_KEY% -storepass %PWD_SERVER_KS% -keystore %SERVER_KEYSTORE_NAME%

keytool -import -v -alias %CLIENT_CERT_NAME% -file %CLIENT_CERT_NAME%.crt -keypass %PWD_CLIENT_KEY% -storepass %PWD_CLIENT_KS% -keystore %CLIENT_KEYSTORE_NAME%

echo All done!

运行这个批处理,期间需要回答一些问题,然后就可以得到一些文件其中client.keystore是需要在客户端部署的,server.keystore是在服务器部署的。ca.*是root_ca的密钥文件。
然后可以用下面的代码测试:

/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

/**
*
* @author Bearice
*/
public class NewClass extends Thread {

@Override
public void run() {
try {
sleep(100);
SSLContext ctx = SSLContext.getInstance("SSL");

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

KeyStore ks = KeyStore.getInstance("JKS");
//KeyStore tks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream("e:/certs/client.keystore"), "clientks".toCharArray());
//tks.load(new FileInputStream("e:/certs/tclient.keystore"), "clientks".toCharArray());

kmf.init(ks, "clientkey".toCharArray());
tmf.init(ks);

ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory factory = ctx.getSocketFactory();

SSLSocket socket = (SSLSocket) factory.createSocket("127.0.0.1", 4433);

showCerts(socket.getSession());

PrintWriter pw = new PrintWriter(socket.getOutputStream());
pw.println("GET /index.html HTTP/1.0");
pw.println("Server: mail.google.com");
pw.println("Connection: close");
pw.println();
pw.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String ln;
while ((ln = in.readLine()) != null) {
System.err.println(ln);
}
} catch (Exception ex) {
Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
}
}

public static void showCerts(SSLSession session) {
X509Certificate cert = null;
try {
cert = (X509Certificate) session.getPeerCertificates()[0];
} catch (SSLPeerUnverifiedException e) {
e.printStackTrace();
System.err.println(session.getPeerHost() + " did not present a valid certificate");
//System.exit(1);
return;
}
System.out.println(session.getPeerHost() + " has presented a certificate belonging to" + "[" + cert.getSubjectDN() + "]\n" + "The certificate was issued by: \t" + "[" + cert.getIssuerDN() + "]");

}

public static void main(String[] args) throws Exception {
SSLContext ctx = SSLContext.getInstance("SSL");

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

KeyStore ks = KeyStore.getInstance("JKS");
//KeyStore tks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream("e:/certs/server.keystore"), "serverks".toCharArray());
//tks.load(new FileInputStream("e:/certs/tserver.keystore"), "serverks".toCharArray());

kmf.init(ks, "serverkey".toCharArray());
tmf.init(ks);

ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

SSLServerSocketFactory factory = ctx.getServerSocketFactory();
SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(4433);

serverSocket.setNeedClientAuth(true);

new NewClass().start();

SSLSocket socket = (SSLSocket) serverSocket.accept();
try {
socket.startHandshake();
} catch (Exception ex) {
System.out.println("Handshake failed: " + ex);
}

showCerts(socket.getSession());
socket.startHandshake();
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String ln;
while ((ln = in.readLine()) != null) {
System.out.println(ln);
if (ln.equals("")) {
break;
}
}
out.println("HTTP/1.1 200 OK");
out.println("Cache-Control: no-cache");
out.println("Pragma: no-cache");
out.println("Expires: Fri, 01 Jan 1990 00:00:00 GMT");
out.println("Content-Type: text/html; charset=UTF-8");
out.println("Date: Tue, 01 Jul 2008 11:56:42 GMT");
out.println("Server: BWS");
out.println("X-Powered-By: BWS");
out.println();
out.println("

hello world

");
out.close();
socket.close();
}
}


其他参考链接:
SSL-用Keytool和OpenSSL生成和签发数字证书
为高级 JSSE 开发人员定制 SSL

2008年7月3日星期四

Java在处理SSL时证书无效的问题,以及解决方法

Java内置了对HTTPS和SSL的支持,但是我在写客户端时遇到了一些问题,比如最大的问题就是在连接的服务器没有一个有效的(也就是经过根CA认证的)SSL证书时会报错。Google了一下,说有两种方式:一种是事先把目标证书导入Java的证书管理器里,另一种是强制忽略证书合法性检查。第一种方法不用对代码进行什么更改,只要运行一个命令就行了,但是缺点是每次服务器更换证书都要进行一次导入。
第二种方法需要更改一下代码,优点是可以应用于任何SSL证书,而且不用重复导入,缺点也很明显,降低了系统的安全性。
下面是第二钟方法的实例代码


try {
final SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {

public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}

public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
//这里进行有效性检查,不抛出异常就算检查成功
}

public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}, null);
sleep(100);
SSLSocketFactory factory = sslContext.getSocketFactory();
final SSLSocket socket = (SSLSocket) factory.createSocket("127.0.0.1", 4433);
SSLSession session = socket.getSession();
X509Certificate cert = null;
try {
cert = (X509Certificate) session.getPeerCertificates()[0];
} catch (SSLPeerUnverifiedException e) {
e.printStackTrace();
System.err.println(session.getPeerHost() + " did not present a valid certificate");
return;
}
System.out.println(session.getPeerHost() + " has presented a certificate belonging to" + "[" + cert.getSubjectDN() + "]\n" + "The certificate was issued by: \t" + "[" + cert.getIssuerDN() + "]");
PrintWriter pw = new PrintWriter(socket.getOutputStream());
pw.println("GET /index.html HTTP/1.0");
pw.println("Server: mail.google.com");
pw.println("Connection: close");
pw.println();
pw.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String ln;
while ((ln = in.readLine()) != null) {
System.err.println(ln);
}
} catch (Exception ex) {
Logger.getLogger(ServerLauncher.class.getName()).log(Level.SEVERE, null, ex);
}