一、CA知识
1 PKCS12 证书
生成命令可参考PKCS12 证书的生成及验证,执行命令
keytool -genkey -v -alias test01 -keyalg RSA -storetype PKCS12 -keystore test02.p12 -validity 7
按照java读取*.p12证书的信息,得到的信息如下
keystore type=PKCS12
alias=[test01]
is key entry=true
cert class = sun.security.x509.X509CertImpl
cert = [
[
Version: V3
Subject: CN=dzm, OU=dzm, O=dzmsoft, L=wuhan, ST=hubei, C=CN
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 2048 bits
modulus: 16865032683270763651334108715966004188238549812392439948233738192194115356601852938530790311338409358415757721999091387199044244472314830521148524738362288669007706182664781713565528419572242375258103781189600088307406868161622773585876219441315372152530539195183008392619360583339470007597366054954483874976493914759755774203982042402875136855025874648627116644454745065757315523608581122336384603957848785135715173688009139453042202460318978399831307404788643531107025646737685192783730366376644393099572704682946858037673816519944079265834037088883176601291260138756847986551311590142737125703403027699175869267409
public exponent: 65537
Validity: [From: Wed Apr 12 14:59:50 CST 2017,
To: Tue Jul 11 14:59:50 CST 2017]
Issuer: CN=dzm, OU=dzm, O=dzmsoft, L=wuhan, ST=hubei, C=CN
SerialNumber: [ 1c499a75]
Certificate Extensions: 1
[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 76 DB 36 5E A7 CB BB AC EA A1 27 9F 2B 70 D0 AE v.6^......'.+p..
0010: 92 C2 3D 55 ..=U
]
]
]
Algorithm: [SHA256withRSA]
Signature:
0000: 3C 04 F3 EE EF 8C 0D 21 52 85 F6 E3 34 55 86 17 <......!R...4U..
0010: 49 62 65 77 53 5F EC D0 45 A0 30 52 49 2C 72 A4 IbewS_..E.0RI,r.
0020: 84 10 CC CF 34 6C 39 75 56 16 A5 AA FF 65 10 EE ....4l9uV....e..
0030: 1A 47 A8 D4 98 E2 81 5C 08 D9 91 4A 69 B3 91 FB .G.....\...Ji...
0040: 49 FB 52 8E 57 6A ED 2A 4A A4 5A 23 F7 14 0E 49 I.R.Wj.*J.Z#...I
0050: 23 BA 0A 55 25 98 04 33 98 E9 61 12 A0 33 16 E6 #..U%..3..a..3..
0060: 97 2E DF A7 2E 28 52 3A AC F8 50 FE B5 07 E2 C2 .....(R:..P.....
0070: 31 1F B2 A7 75 2B 51 E6 02 A8 88 86 12 60 1E 34 1...u+Q......`.4
0080: 94 C2 0B 3B F6 2F D2 4C F2 9D B7 98 79 65 F6 AD ...;./.L....ye..
0090: 1F 63 48 19 F3 F4 35 84 8D 5F 0C F3 E3 33 9B 7B .cH...5.._...3..
00A0: 21 21 0B B9 64 D4 A1 86 73 4D 1A F7 41 11 36 B5 !!..d...sM..A.6.
00B0: 8E 35 13 AD 7B 34 11 8D 96 36 74 10 67 5C 0A 24 .5...4...6t.g\.$
00C0: 61 CD D5 41 13 7B B3 72 1D 8C 6C 36 64 92 29 95 a..A...r..l6d.).
00D0: 70 CE D2 64 CC 3C FF 74 0B 98 C4 A0 0F 20 7D DC p..d.<.t..... ..
00E0: CC 1B A5 63 18 11 3B 52 45 B5 11 1C EA 9F 6D 12 ...c..;RE.....m.
00F0: 71 95 D2 56 17 01 67 D3 80 EF 4B 11 B7 F3 7F B5 q..V..g...K.....
]
public key = Sun RSA public key, 2048 bits
modulus: 16865032683270763651334108715966004188238549812392439948233738192194115356601852938530790311338409358415757721999091387199044244472314830521148524738362288669007706182664781713565528419572242375258103781189600088307406868161622773585876219441315372152530539195183008392619360583339470007597366054954483874976493914759755774203982042402875136855025874648627116644454745065757315523608581122336384603957848785135715173688009139453042202460318978399831307404788643531107025646737685192783730366376644393099572704682946858037673816519944079265834037088883176601291260138756847986551311590142737125703403027699175869267409
public exponent: 65537
private key = sun.security.rsa.RSAPrivateCrtKeyImpl@88cf3
2 双向认证
可以参考JDK自带工具keytool生成ssl证书
3 单向认证
可以参考keytool生成keystore、truststore、证书以及SSL单向认证在服务端tomcat和客户端的配置
keytool生成的正式都是二进制 data,nginx使用的是OPENSSL标准的PEM+key文件,即ascii文本格式的密钥
4 openssl单向认证
openssl自签名证书生成与单双向验证
二、CA证书在thrift中的应用(java-to-java)
按照keytool生成keystore、truststore、证书以及SSL单向认证在服务端tomcat和客户端的配置生成keystore,和truststore后,在java的应用,按照下面的方式,验证通过
- 客户端代码
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSSLTransportFactory;
import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.junit.Test;
@Test
public void secure_test(){
TSSLTransportParameters params = new TSSLTransportParameters();
params.setTrustStore("src/test/resources/pzy.truststore", "123456", "SunX509", "JKS");
TTransport transport;
try {
transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params);
TProtocol protocol = new TBinaryProtocol(transport);
InvoiceService.Client client = new InvoiceService.Client(protocol);
perform(client);
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
- 服务端代码
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.server.TThreadedSelectorServer;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TNonblockingServerTransport;
import org.apache.thrift.transport.TSSLTransportFactory;
import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static int port = PropertiesUtil.getInteger("port");
public static void main(String[] args) {
if (args.length==0 || args[0].contains("simple")){
Runnable simple = new Runnable() {
public void run() {
simple();
}
};
new Thread(simple).start();
} else if (args[0].contains("secure")){
Runnable secure = new Runnable() {
public void run() {
secure();
}
};
new Thread(secure).start();
} else{
logger.error("启动参数不正确,选项为:simple或secure, 默认为simple");
System.exit(0);
}
}
/**
* 普通模式
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static void simple(){
try {
InvoiceService.Processor processor = new InvoiceService.Processor(new InvoiceServiceImpl());
TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(port);
TThreadedSelectorServer.Args args = new TThreadedSelectorServer.Args(serverTransport).processor(processor);
args.maxReadBufferBytes = 1024*1024;
TServer server = new TNonblockingServer(args);
logger.info("Starting the server on {}...", port);
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
/**
* 安全模式
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static void secure(){
try {
InvoiceService.Processor processor = new InvoiceService.Processor(new InvoiceServiceImpl());
TSSLTransportParameters params = new TSSLTransportParameters();
params.setKeyStore("src/main/resources/pzy.keystore", "123456");
TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params);
TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
logger.info("Starting the server on {}...", port);
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
3 keystore\truststore
trsutstore可以按照 openssl + tomcat 配置https中
keytool -keystore pzy.truststore -keypass 123456 -storepass 123456 -alias ca -import -trustcacerts -file ca-cert.pem
而keystore可以执行
keytool -importkeystore -deststorepass 123456 -destkeypass 123456 -destkeystore pzy.keystore -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass 123456
三、CA证书在thrift中的应用(c+±to-java)
c++端用的是pem格式的文件,跟java的keytool有区别,不能直接使用,
参考openssl + tomcat 配置https,生成的文件如下所示:
c++端作为客户端调用,使用到了ca-cert.pem,client-cert.pem,client-key.pem
最终java服务端代码如下:
private static void secure(){
String keyStore = Main.class.getResource("/key/server.jks").getPath();
if("\\".equals(File.separator)) {
keyStore = keyStore.substring(1);
}
try {
InvoiceService.Processor processor = new InvoiceService.Processor(new InvoiceServiceImpl());
TSSLTransportParameters params = new TSSLTransportParameters();
params.setKeyStore(keyStore, keyPass);
TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(port, timeout, null, params);
TThreadPoolServer.Args tArgs = new TThreadPoolServer.Args(serverTransport).processor(processor)
.transportFactory(new TFramedTransport.Factory())
.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TThreadPoolServer(tArgs);
logger.info("Starting the server on {}...", port);
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
c++客户端调用代码
if(g_bUseCrts)
{
shared_ptr<CSSLSocketFactoryPassEx> sslSockFactory(new CSSLSocketFactoryPassEx());
sslSockFactory->overrideDefaultPasswordCallback();
sslSockFactory->server(false);
sslSockFactory->authenticate(true);
sslSockFactory->loadCertificate(g_strCntCrt.c_str());
sslSockFactory->loadPrivateKey(g_strCntKey.c_str());
sslSockFactory->loadTrustedCertificates(g_strTrustedCrt.c_str());
sslSockFactory->ciphers("HIGH:!DSS:!aNULL@STRENGTH");
m_socket = boost::shared_ptr<TSocket>(sslSockFactory->createSocket(strip,port));
}
else
{
m_socket = boost::shared_ptr<TSocket>(new TSocket(strip,port));
}
m_socket->setConnTimeout(2*1000); //设置连接超时为2s
m_socket->setRecvTimeout(10*1000); //设置响应超时为10s
m_transport = boost::shared_ptr<TTransport>(new TFramedTransport(m_socket));
m_protocol = boost::shared_ptr<TProtocol>(new TBinaryProtocol(m_transport));