赞
踩
JDK文档指出,SSLSocket扩展Socket并提供使用SSL或TLS协议的安全套接字。
这种套接字是正常的流套接字,但是它们在基础网络传输协议(如TCP)上添加了安全保护层。
具体安全方面的讨论见下一篇。本篇重点关注SSLSocket及相关几个类的使用。
SSLSocket来自jsse(Java Secure Socket Extension)。
(1)SSLContext: 此类的实例表示安全套接字协议的实现, 它是SSLSocketFactory、SSLServerSocketFactory和SSLEngine的工厂。
(2)SSLSocket: 扩展自Socket
(3)SSLServerSocket: 扩展自ServerSocket
(4)SSLSocketFactory: 抽象类,扩展自SocketFactory, SSLSocket的工厂
(5)SSLServerSocketFactory: 抽象类,扩展自ServerSocketFactory, SSLServerSocket的工厂
(6)KeyStore: 表示密钥和证书的存储设施
(7)KeyManager: 接口,JSSE密钥管理器
(8)TrustManager: 接口,信任管理器(?翻译得很拗口)
(9)X590TrustedManager:TrustManager的子接口,管理X509证书,验证远程安全套接字
publicstaticvoidmain(String[]args)throwsException{ X509TrustManagerx509m=newX509TrustManager(){ @Override publicX509Certificate[]getAcceptedIssuers(){ returnnull; } @Override publicvoidcheckServerTrusted(X509Certificate[]chain, StringauthType)throwsCertificateException{ } @Override publicvoidcheckClientTrusted(X509Certificate[]chain, StringauthType)throwsCertificateException{ } }; //获取一个SSLContext实例 SSLContexts=SSLContext.getInstance("SSL"); //初始化SSLContext实例 s.init(null,newTrustManager[]{x509m}, newjava.security.SecureRandom()); //打印这个SSLContext实例使用的协议 System.out.println("缺省安全套接字使用的协议:"+s.getProtocol()); //获取SSLContext实例相关的SSLEngine SSLEnginee=s.createSSLEngine(); System.out .println("支持的协议:"+Arrays.asList(e.getSupportedProtocols())); System.out.println("启用的协议:"+Arrays.asList(e.getEnabledProtocols())); System.out.println("支持的加密套件:" +Arrays.asList(e.getSupportedCipherSuites())); System.out.println("启用的加密套件:" +Arrays.asList(e.getEnabledCipherSuites())); }
运行结果如下:
SSLContext.getProtocol(): 返回当前SSLContext对象的协议名称
SSLContext.init(): 初始化当前SSLContext对象。 三个参数均可以为null。 详见JDK文档。
SSLEngine.getSupportedProtocols()等几个方法可以返回些 Engine上支持/已启用的协议、支持/已启用的加密套件
这两个类的用法跟Socket/ServerSocket的用法比较类似。看下面的例子(主要为了验证SSLSocket的用法 ,I/O和多线程处理比较随意)
4.1 SSLServerSocket
(1)新建一个SSLServerSocket,并开始监听来自客户端的连接
//抛出异常
//javax.net.ssl.SSLException:Noavailablecertificateorkeycorresponds
//totheSSLciphersuiteswhichareenabled.
publicstaticvoidnotOk()throwsIOException{
SSLServerSocketFactoryfactory=(SSLServerSocketFactory)SSLServerSocketFactory
.getDefault();
SSLServerSocketserver=(SSLServerSocket)factory
.createServerSocket(10000);
System.out.println("ok");
server.accept();
}
server.accept()处抛出异常, 提示缺少证书。与ServerSocket不同, SSLServerSocket需要证书来进行安全验证。
使用keytool工具生成一个证书。 步骤如下, 得到一个名为cmkey的证书文件
(2)重新完善上面的代码。 主要增加两个功能:使用名为cmkey的证书初始化SSLContext, echo客户端的消息。 代码如下
//启动一个sslserversocket //配置了证书,所以不会抛出异常 publicstaticvoidsslSocketServer()throwsException{ //keystore相关信息 StringkeyName="cmkey"; char[]keyStorePwd="123456".toCharArray(); char[]keyPwd="123456".toCharArray(); KeyStorekeyStore=KeyStore.getInstance(KeyStore.getDefaultType()); //装载当前目录下的keystore.可用jdk中的keytool工具生成keystore InputStreamin=null; keyStore.load(in=Test2.class.getClassLoader().getResourceAsStream( keyName),keyPwd); in.close(); //初始化keymanagerfactory KeyManagerFactorykmf=KeyManagerFactory.getInstance(KeyManagerFactory .getDefaultAlgorithm()); kmf.init(keyStore,keyPwd); //初始化sslcontext SSLContextcontext=SSLContext.getInstance("SSL"); context.init(kmf.getKeyManagers(), newTrustManager[]{newMyX509TrustManager()}, newSecureRandom()); //监听和接收客户端连接 SSLServerSocketFactoryfactory=context.getServerSocketFactory(); SSLServerSocketserver=(SSLServerSocket)factory .createServerSocket(10002); System.out.println("ok"); Socketclient=server.accept(); System.out.println(client.getRemoteSocketAddress()); //向客户端发送接收到的字节序列 OutputStreamoutput=client.getOutputStream(); //当一个普通socket连接上来,这里会抛出异常 //Exceptioninthread"main"javax.net.ssl.SSLException:Unrecognized //SSLmessage,plaintextconnection? InputStreaminput=client.getInputStream(); byte[]buf=newbyte[1024]; intlen=input.read(buf); System.out.println("received:"+newString(buf,0,len)); output.write(buf,0,len); output.flush(); output.close(); input.close(); //关闭socket连接 client.close(); server.close(); }
4.2 SSLSocket
(1)我们先使用一个普通的Socket尝试连接服务器端
//通过socket连接服务器
publicstaticvoidsocket()throwsUnknownHostException,IOException{
Sockets=newSocket("localhost",10002);
System.out.println(s);
System.out.println("ok");
OutputStreamoutput=s.getOutputStream();
InputStreaminput=s.getInputStream();
output.write("alert".getBytes());
System.out.println("sent:alert");
output.flush();
byte[]buf=newbyte[1024];
intlen=input.read(buf);
System.out.println("received:"+newString(buf,0,len));
}
结果客户端和服务器端都出错。客户端的错误是接收到乱码。
服务器则抛出异常
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
(2)改成SSLSocket, 但是不使用证书。客户端抛出sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
//不使用证书,通过sslsocket连接服务器 //抛出异常,提示找不到证书 publicstaticvoidsslSocket()throwsUnknownHostException,IOException{ SSLSocketFactoryfactory=(SSLSocketFactory)SSLSocketFactory .getDefault(); SSLSockets=(SSLSocket)factory.createSocket("localhost",10002); System.out.println("ok"); OutputStreamoutput=s.getOutputStream(); InputStreaminput=s.getInputStream(); output.write("alert".getBytes()); System.out.println("sent:alert"); output.flush(); byte[]buf=newbyte[1024]; intlen=input.read(buf); System.out.println("received:"+newString(buf,0,len)); }
程序客户在不持有证书的情况下直接进行连接,服务器端会产生运行时异常javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown,不允许进行连接。 我们可以指定像下面这样执行客户端,服务器端可以成功echo客户端的发出的字符串”alert”
java -Djavax.net.ssl.trustStore=cmkeyClient
这里的cmkey即前面生成的证书文件。
(3)改成SSLSocket, 对SSLContext进行如下初始化。
publicstaticvoidsslSocket2()throwsException{ SSLContextcontext=SSLContext.getInstance("SSL"); //初始化 context.init(null, newTrustManager[]{newTest2.MyX509TrustManager()}, newSecureRandom()); SSLSocketFactoryfactory=context.getSocketFactory(); SSLSockets=(SSLSocket)factory.createSocket("localhost",10002); System.out.println("ok"); OutputStreamoutput=s.getOutputStream(); InputStreaminput=s.getInputStream(); output.write("alert".getBytes()); System.out.println("sent:alert"); output.flush(); byte[]buf=newbyte[1024]; intlen=input.read(buf); System.out.println("received:"+newString(buf,0,len)); }
来自 https://blog.csdn.net/qq_31694651/article/details/52372341
Okhttp3
tcp三次握手建立连接,判断是否要ssl
调用到framework中
调用的是native函数NativeCrypto.SSL_do_handshake()
来自 https://blog.csdn.net/u010144805/article/details/80449333
retroit是对okhttp3的封装
握手失败日志:【属于No peer certificate问题】
D/FeatureProxyBase(5446): FeatureProxyBase class constructor D/FeatureProxyBase(5446): getService(), serviceName = multiwindow_service_v1 D/Surface(5446): Surface::setBuffersDimensions(this=0x7faba42600,w=720,h=1280) V/SettingsInterface(5446): from settings cache , name = sound_effects_enabled , value = 0 I/SSLTest(5446): ----------start init https connection------ V/SSLTest(5446): params:null V/SSLTest(5446): urlPath:https://192.168.137.1:8443 D/libc-netbsd(5446): [getaddrinfo]: mtk hostname=192.168.137.1; servname=(null); cache_mode=(null), netid=0; mark=0 D/libc-netbsd(5446): getaddrinfo( app_uid:10206 D/libc-netbsd(5446): getaddrinfo() uid prop: D/libc-netbsd(5446): getaddrinfo() getuid():10206 D/libc-netbsd(5446): [getaddrinfo]: mtk ai_addrlen=0; ai_canonname=(null); ai_flags=4; ai_family=0 I/System.out(5446): isEmailSend:POST I/System.out(5446): getAllHeaders:POST I/System.out(5446): this.mCheckHandler:android.net.Proxy$DefaultHttpRequestCheckHandler@25d0bd72 D/libc-netbsd(5446): [getaddrinfo]: mtk hostname=192.168.137.1; servname=(null); cache_mode=(null), netid=0; mark=0 D/libc-netbsd(5446): getaddrinfo( app_uid:10206 D/libc-netbsd(5446): getaddrinfo() uid prop: D/libc-netbsd(5446): getaddrinfo() getuid():10206 D/libc-netbsd(5446): [getaddrinfo]: mtk ai_addrlen=0; ai_canonname=(null); ai_flags=4; ai_family=0 I/System.out(5446): [CDS][DNS] getAllByNameImpl netId = 0 D/libc-netbsd(5446): [getaddrinfo]: mtk hostname=192.168.137.1; servname=(null); cache_mode=(null), netid=0; mark=0 D/libc-netbsd(5446): getaddrinfo( app_uid:10206 D/libc-netbsd(5446): getaddrinfo() uid prop: D/libc-netbsd(5446): getaddrinfo() getuid():10206 D/libc-netbsd(5446): [getaddrinfo]: mtk ai_addrlen=0; ai_canonname=(null); ai_flags=4; ai_family=0 I/System.out(5446): openConnection:1 I/System.out(5446): [CDS][DNS] getAllByNameImpl netId = 0 D/libc-netbsd(5446): [getaddrinfo]: mtk hostname=192.168.137.1; servname=(null); cache_mode=(null), netid=0; mark=0 D/libc-netbsd(5446): getaddrinfo( app_uid:10206 D/libc-netbsd(5446): getaddrinfo() uid prop: D/libc-netbsd(5446): getaddrinfo() getuid():10206 D/libc-netbsd(5446): [getaddrinfo]: mtk ai_addrlen=0; ai_canonname=(null); ai_flags=4; ai_family=0 I/System.out(5446): [socket][1] connection /192.168.137.1:8443;LocalPort=38084(120000) I/System.out(5446): [CDS]connect[/192.168.137.1:8443] tm:120 D/Posix(5446): [Posix_connect Debug]Process com.up.testjavasdkdemo :8443 D/Surface(5446): Surface::setBuffersDimensions(this=0x7faba42600,w=720,h=1280) I/System.out(5446): [socket][/192.168.137.217:38084] connected I/System.out(5446): [CDS]rx timeout:120000 I/System.out(5446): [CDS]SO_SND_TIMEOUT:0 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 NativeCrypto_SSL_do_handshake fd=0x7f95efae04 shc=0x7f95efae08 timeout_millis=120000 client_mode=1 npn=0x0 D/NativeCrypto(5446): doing handshake ++ D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x10 ret=1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 handshake start in UNKWN before/connect initialization D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback calling handshakeCompleted D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback completed D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x1001 ret=1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL_connect:UNKWN before/connect initialization D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x1001 ret=1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL_connect:23WCHA SSLv2/v3 write client hello A D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x1002 ret=-1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL_connect:error exit in 23RSHA SSLv2/v3 read server hello A D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): doing handshake -- ret=-1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 NativeCrypto_SSL_do_handshake ret=-1 errno=11 sslError=2 timeout_millis=120000 D/NativeCrypto(5446): doing handshake ++ D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x1001 ret=1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL_connect:3RSH_A SSLv3 read server hello A D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x1002 ret=-1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL_connect:error exit in 3RSC_A SSLv3 read server certificate A D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x1002 ret=-1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL_connect:error exit in 3RSC_A SSLv3 read server certificate A D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): doing handshake -- ret=-1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 NativeCrypto_SSL_do_handshake ret=-1 errno=11 sslError=2 timeout_millis=120000 D/NativeCrypto(5446): doing handshake ++ E/NativeCrypto(5446): ssl=0x7fa5e5ec80 cert_verify_callback x509_store_ctx=0x7f95efab18 arg=0x0 E/NativeCrypto(5446): ssl=0x7fa5e5ec80 cert_verify_callback calling verifyCertificateChain authMethod=ECDHE_RSA D/NativeCrypto(5446): ssl=0x7fa5e5ec80 cert_verify_callback => 0 D/OpenSSLLib(5446): OpensslErr:Module:20(144:134); file:external/openssl/ssl/s3_clnt.c ;Line:1260;Function:ssl3_get_server_certificate D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x4008 ret=558 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL3 alert write:F:CU fatal certificate unknown D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback where=0x1002 ret=-1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 SSL_connect:error exit in 3RSC_B SSLv3 read server certificate B D/NativeCrypto(5446): ssl=0x7fa5e5ec80 info_callback ignored D/NativeCrypto(5446): doing handshake -- ret=-1 D/NativeCrypto(5446): ssl=0x7fa5e5ec80 NativeCrypto_SSL_do_handshake exception => 0 I/System.out(5446): [CDS]close[38084] I/SSLTest(5446): onFailure:javax.net.ssl.SSLPeerUnverifiedException: No peer certificate strMsg:No peer certificate I/SSLTest(5446): onFailure:javax.net.ssl.SSLPeerUnverifiedException: No peer certificate strMsg:No peer certificate D/Surface(5446): Surface::setBuffersDimensions(this=0x7faba42600,w=720,h=1280)
分析:
1. ssl=0x7fa5e5ec80 info_callback where=0x1001 ret=1 ssl=0x7fa5e5ec80 SSL_connect:3RSH_A SSLv3 read server hello A
日志由info_callback中的info_callback_LOG发出
回调中打印状态
#define SSL_ST_CONNECT0x1000
#define SSL_ST_ACCEPT0x2000
#define SSL_ST_MASK0x0FFF
根据where判断哪个阶段
SSL_state_string_long调用的是openssl中的转化函数
SSL_connect:23WCHA SSLv2/v3 write client hello A
2. ssl=0x7fa5e5ec80 info_callback ignored
日志由info_callback发出
3. onFailure:javax.net.ssl.SSLPeerUnverifiedException: No peer certificate strMsg:No peer certificate
4. df
云pos的调用
privatevoidinitHttpsConnect(){
LogCat.i("----------startinithttpsconnection------");
System.setProperty("javax.net.ssl.keyStoreProvider","SunPKCS11-wizarpos");
System.setProperty("javax.net.ssl.certAlias","client2048");
}
yunpos中最终调用org.apache.http.impl.client.AbstractHttpClient发送请求
AbstractHttpClient调用流程
public abstract class AbstractHttpClient implements HttpClient
createClientRequestDirector创建DefaultRequestDirector
Ditector是interface RequestDirector
DefaultRequestDirector implements RequestDirector
请求由HttpRequestExecutor执行exectue方法
通过interface HttpClientConnection extends HttpConnection发送请求conn.sendRequestEntity((HttpEntityEnclosingRequest) request);
最终,
DefaultClientConnection实现了HttpClientConnection【java版的】
public abstract class AbstractHttpClientConnection implements HttpClientConnection
public class SocketHttpClientConnection extends AbstractHttpClientConnection implements HttpInetConnection
public class DefaultClientConnection extends SocketHttpClientConnection implements OperatedClientConnection
AndroidHttpClientConnection实现了HttpClientConnection【Android版的】
public class AndroidHttpClientConnection implements HttpInetConnection, HttpConnection
Yunpos中传入的实际是DefaultHttpClient
其他
public class DefaultHttpClient extends AbstractHttpClient
public final class DefaultSSLContextImpl extends OpenSSLContextImpl
参考:
android httpClient 支持HTTPS的2种处理方式【解决了No peer certificate问题】
来自 https://my.oschina.net/blackylin/blog/144136
百度搜【安卓 DefaultHttpClient tls】搜出来的帖子
解决问题:
红框替换掉蓝框
SSL多种方式
双向认证javax
public final void init(KeyManager[] km, TrustManager[] tm, SecureRandom sr) throws KeyManagementException { spiImpl.engineInit(km, tm, sr); } Apache public final void load(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException { implSpi.engineLoad(stream, password); isInit = true; } public final void setCertificateEntry(String alias, Certificate cert) throws KeyStoreException { if (!isInit) { throwNotInitialized(); } implSpi.engineSetCertificateEntry(alias, cert); }
双向认证需要在前面(验证服务端证书和主机名称)的基础上加上客户端密钥库
//参数1:KeyManager[] km,管理客户端密钥库,可以为空
//参数2:TrustManager[] tm,管理信任证书(服务端),可以为空
//参数3:SecureRandom sr,随机数,可以为空
//因为这里是单向认证,所以参数1置为NULL
context.init(null, TrustManager[] tm, new SecureRandom());
来自 https://blog.csdn.net/ONS_cukuyo/article/details/79172355
原理:
Apache httpd设置HTTPS双向认证
来自 https://blog.csdn.net/agonie201218/article/details/54866268
单向认证,只使用CA验证服务器的证书是不是CA机构签发的;
双向认证,
第二种,就用刚才服务端的CA根证书,签发一个客户端证书,发给用户,用户每次用这个证书来发请求,像银行,支付宝等等,用的是这种方式
服务器会验证客户端是不是自己CA再签发的证书
apache+openssl设置https单向认证和双向认证以及反向代理
来自 https://blog.csdn.net/m13826429208/article/details/50239149
apache实现双向认证
关键是看SSLSocketFactory的构造函数
BUG:
java.io.IOException: Wrong version of key store.
Surface::setBuffersDimensions(this=0x7f93642600,w=720,h=1280)
at com.android.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi.engineLoad(BcKeyStoreSpi.java:805)
at java.security.KeyStore.load(KeyStore.java:590)
at com.up.testjavasdkdemo.RetrofittService2.getSSLCertifcation(RetrofittService2.java:50)
at com.up.testjavasdkdemo.RetrofittService2.fetchData(RetrofittService2.java:82)
at com.up.testjavasdkdemo.MainActivity$2$1.run(MainActivity.java:234)
at java.lang.Thread.run(Thread.java:818)
跟Java版本无关,import java.security.KeyStore; java版本1.7降到1.6后没有效果
证书本身的问题
I/SSLTest(3444): ----------start init https connection------
D/OpenSSLLib(3444): OpensslErr:Module:13(114:155); file:external/openssl/crypto/asn1/asn1_lib.c ;Line:145;Function:ASN1_get_object
D/OpenSSLLib(3444): OpensslErr:Module:13(104:168); file:external/openssl/crypto/asn1/tasn_dec.c ;Line:1319;Function:asn1_check_tlen
D/OpenSSLLib(3444): OpensslErr:Module:13(120:58); file:external/openssl/crypto/asn1/tasn_dec.c ;Line:381;Function:ASN1_item_ex_d2i
D/Surface(3444): Surface::setBuffersDimensions(this=0x7f97242600,w=720,h=1280)
发现报错位置:
CertificateFactory cerFactory = CertificateFactory.getInstance(“X.509”);
Certificate cer = cerFactory.generateCertificate(ins);//注释掉
javax.net.ssl.SSLException: hostname in certificate didn't match: <192.168.137.1> != <server>
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:190)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:59)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:119)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:100)
at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:393)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:189)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:365)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:602)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:522)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:500)
at com.up.testjavasdkdemo.MainActivity$2$1.run(MainActivity.java:198)
at java.lang.Thread.run(Thread.java:818)
解决办法:
Android 链接https出现 javax.net.ssl.SSLException: hostname in certificate didn’t match
来自 https://blog.csdn.net/trbbadboy/article/details/11562511
最终解决办法:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。