📄 ssl_with_signature.java
字号:
/****************************************************************
* 软件:Java签名协议扩展 (Java Signature Protocol Extension, JSPE)
* 版本:V1.0
* 软件功能:实现SSL签名协议
* 模块: 私有类ProtocolVersion
* 私有类SSLSignatureType
* 私有类Signature_Alert_type
* 公共类SSL_with_signature
* 私有类SSLsignature_reply
*-----------------------------------------------------------------
* 版权所有:中山大学软件研究所 2002
* Programmed by 佛山张峰岭 fszfl@21cn.com
* 2002.4 - 2002.5
*****************************************************************/
package com.zsusoft.zfl;
import java.util.*;
import java.security.*;
import java.security.KeyStore;
import java.net.*;
import javax.net.*;
import javax.net.ssl.*;
//import com.sun.net.ssl.*;
import java.io.*;
import java.lang.*;
/**
* SSL_with_signature类的私有类,定义SSL签名协议版本号。
**/
class ProtocolVersion{
/**
* 主版本号
**/
public static final byte major=1;
/**
* 次版本号
**/
public static final byte minor=0;
}
/**
* SSL_with_signature类的私有类,定义SSL签名协议中的消息类型。
**/
class SSLSignatureType{
/**
* 签名请求
**/
public static final byte signature_request=1;
/**
* 签名响应
**/
public static final byte signature_reply=2;
/**
* 签名警告
**/
public static final byte signature_alert=3;
}
/**
* SSL_with_signature类的私有类,定义SSL签名协议中的警告类型。
**/
class Signature_Alert_type{
/**
* 签名值无法通过校验,可能是非法或损坏的签名值
**/
public static final byte Illegal_Signature=1;
/**
* 签名响应方拒绝签名
**/
public static final byte Reject_To_Signature=2;
/**
* 非法随机数
**/
public static final byte Illegal_random=3;
/**
* 没有签名能力,签名响应方可能没有具备签名能力的私人数字证书
**/
public static final byte No_signature_ability=4;
/**
* 系统内部故障
**/
public static final byte System_interal_error=5;
/**
* 用户自定义的警告类型
**/
public static final byte User_define_alert=6;
/**
* 消息格式错误
**/
public static final byte Format_error=7;
}
/**********
* 使用用户指定的私钥库和证书库初始化SSL会话;
* 实现了Unix Socket API格式的通信调用方法;
* 通过创建签名回应对象(SSLsignature_reply)启动对签名请求的监听;
* 提供签名请求功能调用方法;
* 提供一些如字符串输入,记日志文件之类的功能调用方法。
* 类中的main方法实现了SSL签名协议功能的演示和调试。
**********/
public class SSL_with_signature {
//可以公共访问的成员
/**
* 自己的证书
**/
public java.security.cert.X509Certificate my_certificate;
//private javax.security.cert.Certificate my_certificate;
// 注:javax.security.cert.Certificate 是JSSE中,专用于SSL
// java.security.cert.Certificate 是Java自带的,不知为什么两者不兼容
// X509Certificate 是Certificate的子类
/**
* 用于创建服务器Socket
**/
public SSLServerSocketFactory ssf= null;
/**
* 用于创建客户机Socket
**/
public SSLSocketFactory sf= null;
/**
* SSL版本,来自SSLContext.getProtocol()
**/
public String SSL_version = null;
//public static final String BYTE_ENCODING ="8859_1"; //传送信息时的编码方式
/**
* 传送信息时的编码方式
**/
public static final String BYTE_ENCODING ="GBK";
//public static final String BYTE_ENCODING ="ASCII7"; //传送信息时的编码方式
/**
* 本人证书中的Suject Distinguished Name
**/
public String my_SubjectDN = "";
/**
* 调用Message_Box.inputString()显示输入窗口并提示用户输入信息
**/
public static Message_Box message_box = new Message_Box();
//私有成员,不能被公开访问
/**
* 签名响应方监听对方连接的端口常数定义
**/
private static final int SSLsignature_listen_port=9008;
private static boolean debug_mode = false; //调试模式
/**
* 这个对象用独立的线程监听请求签名的连接
**/
private SSLsignature_reply sslsignature_reply=null;
private PrivateKey my_privatekey; //自己的私钥
private SSLSignature_Log Log_Object=null; //用于记录日志
/**************
* 构造函数的作用:
* 1 装置自己的私钥库和对方的信任证书库
* 2 生成可以创建SSL socket的socket 工厂
* 参数说明:
* my_keystore存放自己的私钥
* alias:密钥证书库中的alias名,缺省为mykey(JKS的缺省)
* my_password为访问私钥的密码
* cert_keystore存放信任的证书
* LogFileName为保存记录日志的文件名
**/
public SSL_with_signature(KeyStore my_keystore,String alias,String my_password,KeyStore cert_keystore,String LogFileName)
throws Exception
{
//final String ALIASNAME ="mykey"; //密钥证书库中的alias名,缺省为mykey(JKS的缺省)
try {
/*本段代码用于产生SSL socket工厂*/
// kmf 为SSL使用的本方私钥和证书
// tmf 为SSL使用对方证书 ,注意 tmf 中可以保存很多证书,也就是一个SSL_with_signature对象可以同时与许多其他机器联系
// sf 为 SSL client 的socket factory
// ssf 为 SSL server 的 serversocke factory
Security.addProvider(new com.sun.rsajca.Provider());
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
if(debug_mode){
Show_Debug_Message("以下是Java安全平台SSL提供商的资料:");
ListProviderInfo(new com.sun.rsajca.Provider());
ListProviderInfo(new com.sun.net.ssl.internal.ssl.Provider());
}
TrustManagerFactory tmf;
KeyManagerFactory kmf;
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("TLS");
SSL_version = sslContext.getProtocol();
tmf=TrustManagerFactory.getInstance("SunX509");
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(my_keystore, my_password.toCharArray());
tmf.init(cert_keystore);
//使用随机数加强加密强度
SecureRandom srand=SecureRandom.getInstance("SHA1PRNG","SUN");
srand.setSeed((new Date()).getTime());
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), srand);
sf = sslContext.getSocketFactory();
ssf = sslContext.getServerSocketFactory();
if(my_keystore.isKeyEntry(alias) == false) //不是保存私钥
throw new KeyStoreException(alias+" entry is not a key entry");
/*取自己的私钥*/
my_privatekey=(PrivateKey)my_keystore.getKey(alias,my_password.toCharArray()); //装入自己私钥
/*取自己的证书和Subject distinguished name*/
my_certificate=(java.security.cert.X509Certificate)my_keystore.getCertificate(alias);
my_certificate.checkValidity(); //检查证书是否仍然有效
my_SubjectDN=my_certificate.getSubjectDN().getName();
/*设置日志对象*/
if(LogFileName == null)
{
int begin=my_SubjectDN.indexOf("CN="); //定位CN域头
int end=my_SubjectDN.indexOf(",",begin); //定位CN域尾
String my_SubjectDN_CN = null;
if(end<0){
my_SubjectDN_CN=my_SubjectDN.substring(begin+3);
}
else{
my_SubjectDN_CN=my_SubjectDN.substring(begin+3,end);
}
Log_Object=new SSLSignature_Log(my_SubjectDN_CN+"_signature.log"); //缺省使用Subject Distinguish name中的CN字段
}
else
Log_Object=new SSLSignature_Log(LogFileName);
} catch (Exception e) {
System.err.println("无法创建SSL_with_signature对象: " +
e.getMessage());
e.printStackTrace();
throw e;
//System.exit(-1);
}
}
/*
* 显示Java安全方案SSL提供商提供的Java安全类信息
**/
private static void ListProviderInfo(java.security.Provider p){
Show_Debug_Message("---------------Provider name:"+p.getName()+"-------------------");
Show_Debug_Message("Provider version:"+p.getVersion());
Show_Debug_Message("Provider information:"+p.getInfo());
}
/**
* 显示我的证书信息
**/
public void Show_My_Certificate()
{
Show_Message("个人证书信息:");
Show_Message(my_certificate.toString());
}
/**
* 显示SSL的信息
**/
public void Show_SSL_information()
{
Show_Message("SSL的信息:");
Show_Message("版本:"+SSL_version);
String[] supportedCipherSuites = sf.getSupportedCipherSuites();
Show_Message("支持的加密算法为:");
for(int i=0;i<supportedCipherSuites.length;++i)Show_Message(supportedCipherSuites[i]);
String[] defaultCipherSuites=sf.getDefaultCipherSuites();
Show_Message("缺省的加密算法为:");
for(int i=0;i<defaultCipherSuites.length;++i)Show_Message(defaultCipherSuites[i]);
}
/**
* 获取SSL会话的信息
* socket: 使用的socket
* 返回SSL会话的信息
**/
public static String getSSLsessionMessage(Socket socket)
{
String SSLMessage = null;
try{
SSLSession sslsession = ((SSLSocket)socket).getSession(); //SSL会话
SSLMessage = "SSL Session id :" + sslsession.toString() + "\r\n";
SSLMessage += " 对方主机:" + sslsession.getPeerHost() + "\r\n"; //获取对方的主机名
try{
javax.security.cert.Certificate partner_cert=(javax.security.cert.Certificate)(sslsession.getPeerCertificateChain()[0]); //对方的证书
SSLMessage += " 对方证书:\r\n";
SSLMessage += partner_cert.toString()+"\r\n";
} catch (Exception ie) {
SSLMessage += " 对方没有证书!\r\n";
}
SSLMessage += "SSL会话使用的加密算法:"+ sslsession.getCipherSuite() + "\r\n";
SSLMessage += "SSL会话创建的时间:"+ (new Date(sslsession.getCreationTime())).toString() +"\r\n";
SSLMessage += "SSL会话最近使用的时间:"+ (new Date(sslsession.getLastAccessedTime())).toString() +"\r\n";
SSLMessage += "SSL会话绑定的对象:";
String ObjectName[] = sslsession.getValueNames();
for(int i=0;i<ObjectName.length;i++)SSLMessage += ObjectName[0]+" ";
SSLMessage += "\r\n";
} catch (Exception e){
SSLMessage = "无法获取SSL信息,可能不是使用SSL连接\r\n";
SSLMessage += "出错原因:"+e.getMessage()+"\r\n";
}
return SSLMessage;
}
/**
* 创建ServerSocket,在指定端口监听SSL连接
* 参数说明:
* listen_port为监听连接的端口
* 调用返回服务器Socket
**/
public ServerSocket listen(int listen_port)
{
try {
//通讯使用SSL加密
ServerSocket ss = ssf.createServerSocket(listen_port);
((SSLServerSocket)ss).setNeedClientAuth(true); //需要认证对方
return ss;
} catch (IOException e) {
System.err.println("无法创建服务器Socket,原因: " +
e.getMessage());
e.printStackTrace();
return null;
}
}
/**
* 通过SSL的socket发送数据,本方法也通用于TCP socket
* 参数说明:
* s:使用的socket
* but:缓冲区
* length:发送字节长度
* 返回实际发送长度
* -1 表示出错
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -