1. 配置Web服务器的SSL
本系统的Web服务运行在tomcat服务器上。配置服务器的SSL,需要为服务器申请证书,并进行一系列的设置。
(1) 生成服务器证书请求文件(CSR)
生成私钥和CSR文件需要使用keytool。Keytool.exe通常在%JAVA_HOME%/bin目录下。
使用以下命令生成keystore和keyEntry:
keytool –genkey –alias [keyEntry_name] –keyalg RSA –keystore [keystore_name]
genkey:产生密钥对。该证书链和私钥将储存于alias所标识的新密钥仓库中。
alias:密钥别名。
keyalg:用于生成密钥对的算法。
keystore:密钥仓库名称。
keytool会提示输入keystore的密码,您的名字与姓氏、单位、组织、城市、省份、国家。其中“您的名字与姓氏”要与网站的域名一致。
使用以下命令生成CSR:
keytool –certreq –alias [keyEntry_name] –file request.crs –keystore [keystore_name]
certreq:生成PKCS#10格式的证书签名请求,即CSR。
输入keystore的密码,即可在本地目录中生成request.crs。
把此CRS文件发给CA,等待CA颁发证书。
(2)导入证书
CA根据CRS颁发证书后,需要把证书导入到keystore中。使用以下命令导入服务器证书:
keytool –import –trustcacerts –alias [keyEntry_name] –file certificate.txt –keystore [keysore_name]
import:向密钥库导入证书。
trustcacerts:指定该证书链为信任链。
file:证书或pkcs7证书链文件。
使用以下命令导入CA证书:
keytool –import –trustcacerts –alias [CA_name] –file certificate.txt –keystore [keysore_name]
(3)设置Tomcat的SSL连接
编辑Tomcat的配置文件使其支持SSL。在%TCAT_HOME%/conf目录下,使用XML编辑器打开server.xml,找到这一行:
<!—Define a SSL HTTP/1.1 Connector on port 8443-->
更改以下字段:
<!—
<connector port=”8443” protocol=”HTTP/1.1” SSLEnabled=”true”
maxThreads=”150” scheme=”https”
clientAuth=”false” sslProtocol=”TLS”/>
-->
去掉两头的注释“<!--”和“-->”,使SSL配置生效。port=”8443”,代表SSL服务的端口。clientAuth=”false”表示不请求客户端证书,即单向认证。改为“true”则表示请求客户端证书,即双向认证。sslProtocol表示SSL连接的协议,这里使用TLS。同时在上述代码中添加keystoreFile文件、truststoreFile文件和crlFile文件的描述,其中crlFile是从CA下载的最新的被吊销的证书列表。完整的代码如下:
<connector port=”8443” protocol=”HTTP/1.1” SSLEnabled=”true”
maxThreads=”150” scheme=”https”
clientAuth=”true/flase” sslProtocol=”TLS”
keystoreFile=” test.keystore文件的路径”
keystorePass=”test.keystore文件的密码”
truststoreFile=” test.keystore文件的路径”
truststorePass=” test.keystore文件的密码”
crlFile="certcrl.crl文件的路径"/>
完成以上设置之后,重新启动Tomcat。
2.基于SSL双向认证的登录服务的实现
若服务器配置为双向认证(即在上述代码中设置clientAuth=”true”),当用户以所设定的端口访问该服务器时,浏览器将跳出一个对话框让用户选择要提交进行认证的证书,供选择的只有该服务器信任的CA颁发的证书。
如前所述,应用层只需要获得用户证书,查询数据库,验证证书序列号即可。
需要引入的包有: “java.security.cert”,“jdbc”。前者包含的主要类有“X509Certificate”,“X509CRL”,“CertificateFactory”;后者包含所有有关数据库操作的自编程序,其中主要的类有“DbOperation”,“UserInfo”。
核心代码如下:
X509Certificate[]ca=(X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");//获取证书链
X509Certificate x509certificate=ca[0];//获得用户证书
String StrSerialNumber;
StrSerialNumber=x509certificate.getSerialNumber().toString();//得到证书序列号
DbOperation dbOperation = new DbOperation();
UserInfo user = dbOperation.getUserInfoByname(Strname);//查询数据库,得到用户记录
if(StrSerialNumber.equals(user.getUserserial()))
{
user_IsValid="true";
}//验证证书序列号
3. 基于SSL单向认证的登录服务的实现
若服务器配置为单向认证(即设置clientAuth=”false”),当用户以所设定的端口访问该服务器时,浏览器不会自动跳出对话框让用户选择要提交进行认证的证书。为了得到证书我们需要一个控件。
在此ActiveX控件中添加了三个方法:
BSTR GetUserList();//获得证书列表
BSTR GetUserCert(BSTR sUserName);//根据证书名称获得对应证书(Base64编码)
BSTR SignData(BSTR sUserName,BSTR sDataToSign);//根据证书名称对数据签名,返回Base64编码的签名数据
用脚本调用该控件获得用户证书以及用户对随机数的签名文件,然后应用层对证书进行认证。
需要引入的包有: “java.security.cert”,“jdbc”,“java.security”。“java.security”中主要类有“Signature”。
验证用户证书的核心代码如下:
//检验证书有效期
try{
oCert.checkValidity();
}catch(Exception e){
e.printStackTrace();
request.setAttribute("ErrMsg", "没有提供有效的数字证书。");
request.getRequestDispatcher("err.jsp").forward(request, response);
return;
}
//检验签发用户证书的CA是否被信任
String issuer=oCert.getIssuerDN().toString();
if(issuer.equals("CN=TestCA"));
else verify=false;
//检验证书是否被CA吊销
InputStream inStream = new FileInputStream("D:/Program Files/jre/bin/certcrl.crl");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CRL crl = (X509CRL)cf.generateCRL(inStream);
inStream.close();
if(crl.isRevoked(oCert))
verify=false;
//查询数据库,验证证书序列号
DbOperation dbOperation = new DbOperation();
UserInfo user = dbOperation.getUserInfoByname(clientname);
if(user.getUserserial().equals(strSerialNumber));
else verify=false;
//验证随机数签名
Signature oSign = Signature.getInstance("SHA1withRSA");
oSign.initVerify(oCert);
signedBuf = oDecoder.decodeBuffer(UserSignedData);
oSign.update(rand.getBytes());
verify = oSign.verify(signedBuf);