- 浏览: 51707 次
- 性别:
- 来自: 北京
文章分类
最新评论
Java 提供了阻塞和非阻塞I/O。非阻塞的I/O,大大提高了服务器的扩展性和伸缩性。
SSLServerSocket和SSLSocket是阻塞的socket调用。这连个类分别继承自ServerSocket和Socket, 封装了SSL(Secure Socket Layer)和TLS(Transport Layer Security), 提供了安全套接字。ServerSocket和Socket是阻塞的现实, 因此SSLServerSocket和SSLSocket也是阻塞的实现。阻塞实现的套接字的好处的是编程简单,学习成本低;缺点是扩展性和并发性较差。没法满足大并发服务器的实现要求。
如果要实现非阻塞的安全套接字,需要将SSLEngine和SocketChannel结合使用。
安全通信模型包括:
1)数据一致性保护。数据一致性通过加密套件和信息摘要套件实现
2)认证。Client和Server互相认证
3)机密性。 数据被加密后传输,没有明文数据(plain text)在网络上传播。
SSLEngine负责入栈和出栈数据加密和解密以及加密解密算法的协商。加密解密的算法是通过握手协议协商完成的。
握手过程如下:
1. 客户端想服务器端发送信息。信息包括支持的最高版本的SSL和加密套件列表。
2. 服务器发送支持的SSL和加密套件。完成加密套件的协商。
3.服务器端生成密钥并用公钥加密发送给服务器,服务器用私钥解密。
4.客户端和服务器用第三步生成的密钥加密数据进行传输
客户端代码如下:
package com.net;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Authenticator.RequestorType;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.security.KeyStore;
import java.util.Iterator;
import java.util.Scanner;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
public class SSLHandshakeClient {
private static Logger logger = Logger.getLogger(SSLHandshakeClient.class.getName());
private SocketChannel sc;
private SSLEngine sslEngine;
private Selector selector;
private HandshakeStatus hsStatus;
private Status status;
private ByteBuffer myNetData;
private ByteBuffer myAppData;
private ByteBuffer peerNetData;
private ByteBuffer peerAppData;
private ByteBuffer dummy = ByteBuffer.allocate(0);
public void run() throws Exception{
char[] password = "123456".toCharArray();
KeyStore trustStore = KeyStore.getInstance("JKS");
InputStream in = this.getClass().getResourceAsStream("clienttruststore.jks");
trustStore.load(in,password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, tmf.getTrustManagers(), null);
sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(true);
SSLSession session = sslEngine.getSession();
myAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
peerNetData.clear();
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT);
channel.connect(new InetSocketAddress("localhost", 443));
sslEngine.beginHandshake();
hsStatus = sslEngine.getHandshakeStatus();
while(true){
selector.select();
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selectionKey = it.next();
it.remove();
handleSocketEvent(selectionKey);
}
}
}
private void handleSocketEvent(SelectionKey key) throws IOException{
if(key.isConnectable()){
sc = (SocketChannel)key.channel();
if(sc.isConnectionPending()){
sc.finishConnect();
}
doHandshake();
sc.register(selector, SelectionKey.OP_READ);
}
if(key.isReadable()){
sc = (SocketChannel)key.channel();
doHandshake();
if(hsStatus == HandshakeStatus.FINISHED){
logger.info("Client handshake completes... ...");
key.cancel();
sc.close();
}
}
}
private void doHandshake() throws IOException{
SSLEngineResult result;
int count = 0;
while(hsStatus != HandshakeStatus.FINISHED){
logger.info("handshake status: " + hsStatus);
switch (hsStatus) {
case NEED_TASK:
Runnable runnable;
while((runnable=sslEngine.getDelegatedTask()) != null){
runnable.run();
}
hsStatus = sslEngine.getHandshakeStatus();
break;
case NEED_UNWRAP:
count = sc.read(peerNetData);
if(count < 0){
logger.info("no data is read for unwrap.");
break;
}else{
logger.info("data read: " + count);
}
peerNetData.flip();
peerAppData.clear();
do {
result = sslEngine.unwrap(peerNetData, peerAppData);
logger.info("Unwrapping:\n" + result);
// During an handshake renegotiation we might need to perform
// several unwraps to consume the handshake data.
} while (result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
result.bytesProduced() == 0);
if (peerAppData.position() == 0 &&
result.getStatus() == SSLEngineResult.Status.OK &&
peerNetData.hasRemaining())
{
result = sslEngine.unwrap(peerNetData, peerAppData);
logger.info("Unwrapping:\n" + result);
}
hsStatus = result.getHandshakeStatus();
status = result.getStatus();
assert status != status.BUFFER_OVERFLOW : "buffer not overflow." + status.toString();
// Prepare the buffer to be written again.
peerNetData.compact();
// And the app buffer to be read.
peerAppData.flip();
break;
case NEED_WRAP:
myNetData.clear();
result = sslEngine.wrap(dummy, myNetData);
hsStatus = result.getHandshakeStatus();
status = result.getStatus();
while (status != Status.OK) {
logger.info("status: " + status);
switch (status) {
case BUFFER_OVERFLOW:
break;
case BUFFER_UNDERFLOW:
break;
}
}
myNetData.flip();
count = sc.write(myNetData);
if(count <=0){
logger.info("No data is written.");
}else{
logger.info("Written data: " + count);
}
break;
}
}
}
public static void main(String[] args) throws Exception {
new SSLHandshakeClient().run();
}
}
服务器代码:
package com.net;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.security.KeyStore;
import java.util.Iterator;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
public class SSLHandshakeServer {
private static Logger logger = Logger.getLogger(SSLHandshakeServer.class.getName());
private SocketChannel sc;
private SSLEngine sslEngine;
private Selector selector;
private ByteBuffer myNetData;
private ByteBuffer myAppData;
private ByteBuffer peerNetData;
private ByteBuffer peerAppData;
private ByteBuffer dummy = ByteBuffer.allocate(0);
private HandshakeStatus hsStatus;
private Status status;
public void run() throws Exception{
char[] password = "123456".toCharArray();
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream in = this.getClass().getResourceAsStream("serverkeystore");
keyStore.load(in, password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore, password);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), null, null);
sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
SSLSession session = sslEngine.getSession();
myAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
peerNetData.clear();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
selector = Selector.open();
ServerSocket serverSocket = serverChannel.socket();
serverSocket.bind(new InetSocketAddress(443));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
logger.info("Server listens on port 443... ...");
while (true) {
selector.select();
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selectionKey = it.next();
it.remove();
handleRequest(selectionKey);
}
}
}
private void handleRequest(SelectionKey key) throws Exception {
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel channel = ssc.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
sc = (SocketChannel) key.channel();
logger.info("Server handshake begins... ...");
sslEngine.beginHandshake();
hsStatus = sslEngine.getHandshakeStatus();
doHandshake();
if(hsStatus == HandshakeStatus.FINISHED){
key.cancel();
sc.close();
}
logger.info("Server handshake completes... ...");
}
}
private void doHandshake() throws IOException{
SSLEngineResult result;
while(hsStatus != HandshakeStatus.FINISHED){
logger.info("handshake status: " + hsStatus);
switch (hsStatus) {
case NEED_TASK:
Runnable runnable;
while((runnable=sslEngine.getDelegatedTask()) != null){
runnable.run();
}
hsStatus = sslEngine.getHandshakeStatus();
break;
case NEED_UNWRAP:
int count = sc.read(peerNetData);
if(count < 0){
logger.info("no data is read for unwrap.");
break;
}else{
logger.info("data read: " + count);
}
peerNetData.flip();
peerAppData.clear();
do {
result = sslEngine.unwrap(peerNetData, peerAppData);
logger.info("Unwrapping:\n" + result);
// During an handshake renegotiation we might need to perform
// several unwraps to consume the handshake data.
} while (result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
result.bytesProduced() == 0);
if (peerAppData.position() == 0 &&
result.getStatus() == SSLEngineResult.Status.OK &&
peerNetData.hasRemaining())
{
result = sslEngine.unwrap(peerNetData, peerAppData);
logger.info("Unwrapping:\n" + result);
}
hsStatus = result.getHandshakeStatus();
status = result.getStatus();
assert status != status.BUFFER_OVERFLOW : "buffer not overflow." + status.toString();
// Prepare the buffer to be written again.
peerNetData.compact();
// And the app buffer to be read.
peerAppData.flip();
break;
case NEED_WRAP:
myNetData.clear();
result = sslEngine.wrap(dummy, myNetData);
hsStatus = result.getHandshakeStatus();
status = result.getStatus();
while (status != Status.OK) {
logger.info("status: " + status);
switch (status) {
case BUFFER_OVERFLOW:
break;
case BUFFER_UNDERFLOW:
break;
}
}
myNetData.flip();
sc.write(myNetData);
break;
}
}
}
public static void main(String[] args) throws Exception {
new SSLHandshakeServer().run();
}
}
证书生成过程如下:
1. 生成keystore和自签名的certificate, 并生成相应公钥和私钥
%keytool -genkeypair -alias duke -keyalg RSA -validity 7 -keystore keystore
Enter keystore password: password
What is your first and last name? [Unknown]: Duke
What is the name of your organizational unit? [Unknown]: Java Software
What is the name of your organization? [Unknown]: Sun Microsystems, Inc.
What is the name of your City or Locality? [Unknown]: Palo Alto
What is the name of your State or Province? [Unknown]: CA
What is the two-letter country code for this unit? [Unknown]: US
Is CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.",
L=Palo Alto, ST=CA, C=US correct?
[no]: yes
Enter key password for <duke> (RETURN if same as keystore password): <CR>
2.查看keystore
%keytool -list -v -keystore keystore
Enter keystore password: password
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: duke
Creation date: Dec 20, 2001
Entry type: keyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.",L=Palo Alto, ST=CA, C=US
Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US
Serial number: 3c22adc1
Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001
Certificate fingerprints: MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0
SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74
3. 导出证书
%keytool -export -alias duke -keystore keystore -rfc -file duke.cer
Enter keystore password: password
Certificate stored in file <duke.cer>
% cat duke.cer
-----BEGIN CERTIFICATE-----MIICXjCCAccCBDwircEwDQYJKoZIhvcNAQEEBQAwdjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8xHzAdBgNVBAoTFlN1biBNaWNyb3N5c3RlbXMsIEluYy4xFjAUBgNVBAsTDUphdmEgU29mdHdhcmUxDTALBgNVBAMTBER1a2UwHhcNMDExMjIxMDMzNDI1WhcNMDExMjI4MDMzNDI1WjB2MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEfMB0GA1UEChMWU3VuIE1pY3Jvc3lzdGVtcywgSW5jLjEWMBQGA1UECxMNSmF2YSBTb2Z0d2FyZTENMAsGA1UEAxMERHVrZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1loObJzNXsi5aSr8N4XzDksD6GjTHFeqG9DUFXKEOQetfYXvA8F9uWtz8WInrqskLTNzwXgmNeWkoM7mrPpK6Rf5M3G1NXtYzvxyi473Gh1h9k7tjJvqSVKO7E1oFkQYeUPYifxmjbSMVirWZgvo2UmA1c76oNK+NhoHJ4qjeCUCAwEAATANBgkqhkiG9w0BAQQFAAOBgQCRPoQYw9rWWvfLPQuPXowvFmuebsTc28qI7iFWm6BJTT/qdmzti7B5MHOt9BeVEft3mMeBU0CS2guaBjDpGlf+zsK/UUi1w9C4mnwGDZzqY/NKKWtLxabZ5M+4MAKLZ92ePPKGpobM2CPLfM8ap4IgAzCbBKd8+CMp8yFmifze9Q==
-----END CERTIFICATE-----
4. 将第三步导出的证书导入到一个truststore
% keytool -import -alias dukecert -file duke.cer -keystore truststore
Enter keystore password: trustword
Owner: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US
Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US
Serial number: 3c22adc1
Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001
Certificate fingerprints:
MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0
SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74
Trust this certificate? [no]: yes
Certificate was added to keystore
5. 检查 truststore
% keytool -list -v -keystore truststore
Enter keystore password: trustword
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: dukecert
Creation date: Dec 20, 2001
Entry type: trustedCertEntry
Owner: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US
Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=USSerial number: 3c22adc1
Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001
Certificate fingerprints:
MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0
SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74
发表评论
-
javafx webview 与 javafx 控制浏览器
2017-05-16 19:21 1549想针对已有web ui 做个java 客户端,复用web ... -
jdbcdslog 是一款用来跟踪 JDBC 的全功能工具,记录带有详细参数值的SQL
2012-07-03 10:34 2046jdbcdslog 是一款用来跟踪 JDBC 的全功能工具 ... -
java ant 编译源码时 源码中的 非.java文件 无法编译到相应目录
2012-05-22 18:27 743java ant 编译源码时 源码中的 非.java文件 无法 ... -
Kerberos 介绍
2012-02-14 17:57 963Kerberos 协议: Kerberos 协议主要用于 ... -
keystore 介绍
2012-02-10 18:19 2339Keytool 是一个有效的安全钥匙和证书的管理工具. Jav ... -
java nio 示例
2012-02-09 14:47 698NIO主要原理和适用。 NIO 有一个主要的类Sel ... -
nio 简介
2012-01-24 12:11 6881. 基本 概念 IO 是主存和外部设备 ( 硬盘 ...
相关推荐
赠送jar包:jetty-sslengine-6.1.26.jar; 赠送原API文档:jetty-sslengine-6.1.26-javadoc.jar; 赠送源代码:jetty-sslengine-6.1.26-sources.jar; 赠送Maven依赖信息文件:jetty-sslengine-6.1.26.pom; 包含...
赠送jar包:jetty-sslengine-6.1.26.jar; 赠送原API文档:jetty-sslengine-6.1.26-javadoc.jar; 赠送源代码:jetty-sslengine-6.1.26-sources.jar; 赠送Maven依赖信息文件:jetty-sslengine-6.1.26.pom; 包含...
jetty-sslengine-6.1.6rc0.jar
还在为找不到jar文件烦心吗,不用了到我空间来有你想要的,持续更新。。。jetty.jar,jetty-sslengine.jar,jetty-util.jar
sslfacade 概述 ... SSLEngine还在握手过程中生成一些长时间运行的任务,这些任务应由主机应用程序通过ITaskHandler的实现来处理。 prj.sslfacade.DefaultTaskHandler提供了在同一线程上执行任务的默
TLS频道TLS通道是一个通过 (传输层安全性)连接实现接口的库。 它将所有加密操作委托给标准Java TLS实现: ; 有效地将其隐藏在易于使用的流API后面,从而可以以最小的复杂性来证券化JVM应用程序。 换句话说,一个...
管理平台SSL身份验证插件 这个 ...skip_ssl=1 跳过 SSL 身份验证并进行常规登录配置 不错的教程: 就我而言,我发现这是我想要的配置SSLEngine onSSLProtocol all SSLCipherSuite HIGH:MEDIUMSSLCertificateFile /etc/a
注:下文中的 *** 代表文件名中的组件名称。 # 包含: 中文-英文对照文档:【***-javadoc-API文档-中文(简体)-英语-对照版.zip】 jar包下载地址:【***.jar下载地址(官方地址+国内镜像地址).txt】 ...
唤醒云生产调整 环境(在检查安全性) 环境 链接 质量检查 产品 行动策略 运营状态- 生产-具有Helm图表的AWS / GCP / Ali Terraform Kubernetes(待定) 质量检查(完成)-Docker... SSLEngine on # ssl config go
使用javax.ssl.SSLEngine tls / ssl支持 没有第三方依赖 (大部分)符合RFC 6455 目标: 该库旨在使Discord聊天系统成为客户端。 我仍在进行此工作,可能需要一段时间,所以我决定现在共享websocket部分-在完成...
针对一个tomcat中有的项目需要使用ssl加密有些可以直接访问的情况,可通过修改tomcat/conf下的server.xml来实现。具体配置可参考下面这段代码,注意”Catalina1″>这个标签中的配置。 <?xml version='1.0' ...
而 SSLEngine 似乎有点矫枉过正。自签名证书有时,您在建立信任时会使用自签名证书。 但是系统存储不允许您使用它们,因为信任锚已经加载并且默认 SSLContext 在应用程序启动时已经初始化。 在这种(很常见)的情况...
jetty.jar,jetty-sslengine.jar,jetty-util.jar
Tests for SSLEngine class.
The result object describing the state of the {@code SSLEngine} produced by the {@code wrap()} and {@code unwrap()} operations.
jetty-all-9.4.47.v20220610-uber.jar
jetty-sslengine-6.1.26.jar jetty-util-6.1.26.jar jsch-0.1.54.jar json-smart-1.3.1.jar jsp-api-2.1.jar jsr305-3.0.0.jar junit-4.11.jar LIST.bat LIST.TXT log4j-1.2.17.jar mockito-all-1.8.5.jar netty-...
NEWS for OpenSC -- History of user visible changes Complete change history is available online: ... New in 0.12.0; 2010-12-22 * OpenSC uses a single reader driver, specified at compile time. ...