peer not authenticated和Could not generate DH keypair解决方法

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
网上基本上都是信任所有证书来解决 SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER

这个方法的代码如下:

public static String httpsPostInvoke(String url,Map<String, Object> map) throws IOException, ServiceException {
		
    	HttpClient client = new DefaultHttpClient();
    	String str = "";
    	
        try { 
        	X509TrustManager xtm = new X509TrustManager(){   //创建TrustManager 
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} 
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} 
                public X509Certificate[] getAcceptedIssuers() { return null; }
            };
            SSLContext ctx = SSLContext.getInstance("TLS"); 
            ctx.init(null, new TrustManager[]{xtm}, null); 
            SSLSocketFactory socketFactory = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
            client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, socketFactory)); 

            List<NameValuePair> params = new ArrayList<NameValuePair>();//构建POST请求的参数
    		for (String key : map.keySet()) {
    			String value = null;
    			Object obj = null;
    			if((obj = map.get(key)) != null){
    				value = obj.toString();
    			}
    			params.add(new BasicNameValuePair(key, value));
    		}
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
    		HttpPost post = new HttpPost(url);//创建HttpPost 
    		post.setEntity(entity);
            
             
    		HttpResponse response = client.execute(post);
			if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
				throw new ServiceException("Http接口状态出错("
						+ response.getStatusLine().getStatusCode() + ")");
			}
			str = EntityUtils.toString(response.getEntity());
        } catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}finally { 
        	client.getConnectionManager().shutdown(); 
        	return str;
        } 
    } 
执行,ok,没报javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

但是,信任所有的证书,对于强迫症的我和程序猿绝对不能写死的一贯原则,我...又TM花了很长时间,脑补了很多ssl、https的知识,结合网上的代码,发现是可以信任指定证书的,如下代码:

public static String httpsPostInvoke(String url,Map<String, Object> map) throws IOException, ServiceException {
    	
    	InputStream inputStream = null;
    	HttpClient httpClient = new DefaultHttpClient();
    	String result = "";
    	
    	try{
    		//从 inputStream 加载 CA 证书
    		inputStream = NetworkUtil.class.getResourceAsStream("/testCa.cer");
    		CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    		Certificate certificate = certificateFactory.generateCertificate(inputStream);
    		
    		//构造含有信任 CA 证书的 KeyStore
        	KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        	trustStore.load(null, null);
        	trustStore.setCertificateEntry("myalias", certificate);
        	
        	SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
            httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, socketFactory));
        	
            List<NameValuePair> params = new ArrayList<NameValuePair>();//构建POST请求的参数
    		for (String key : map.keySet()) {
    			String value = null;
    			Object obj = null;
    			if((obj = map.get(key)) != null){
    				value = obj.toString();
    			}
    			params.add(new BasicNameValuePair(key, value));
    		}
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
    		HttpPost post = new HttpPost(url);
    		post.setEntity(entity);
    		
    		HttpResponse response = httpClient.execute(post);
			if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
				throw new ServiceException("Http接口状态出错("
						+ response.getStatusLine().getStatusCode() + ")");
			}
			result = EntityUtils.toString(response.getEntity());
    	} catch (CertificateException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (UnrecoverableKeyException e) {
			e.printStackTrace();
		} finally {
    		
    		if(null != inputStream){
    			inputStream.close();
    		}
    		
    		httpClient.getConnectionManager().shutdown(); 
    	}
    	
    	return result;
    	
    }

执行......还是javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
想死的心都有了,继续度娘...没有啥进展...又过了一段时间,在stackoverflow(英语渣渣的我遇到问题,顿时感觉自己英语可以达到了8级!!)找到如下说明和命令

要把证书导入到jdk的KeyStore中,如下命令(相信聪明的你看路径和文件名知道怎么修改相应的参数了吧):

keytool -importcert -alias myalias -file "C:\Users\zhangxiaoning\Desktop\testCa.cer" -keystore "D:\Java\jdk1.6.0_45\jre\lib\security\cacerts" -storepass changeit

另外,骚年们想看命令的说明可以参考一下blog,传送门:
http://www.cnblogs.com/benio/archive/2010/09/15/1826990.html

继续执行代码...javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated,我已挂了......
继续百度、实验、验证,排除一系列可能性,发现...好像导出的证书有问题...
我居然把接口的URL在浏览器输入错了,原先导出的证书不是接口url的证书,是两个不同的url!不同的域名!该死的供应商,给了我错误的URL,我也没注意,怪我!
好吧重新导出证书.顺便记录chrome怎么导出。如图:



其他默认就行了。

运行程序...
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated


我也不知道怎么表述我的心情了。
找资料,看到了一个blog说好像是jdk版本问题,把jdk1.6.0_45\jre\lib\security下的两个jar包换成jdk1.6以上的jar包,换了后执行直接报了classnotfound
算了,先用jdk1.7的执行,调用成功 = =
但是公司的很多系统都是用jdk1.6的,用jdk1.7的话,可能会有问题,所以继续找资料。

在无意中,百度到了一句,java ssl网络的debug log打印,在你要调用接口前加入以下一句:

System.setProperty("javax.net.debug", "ssl,handshake");

调用https接口前会打印一系列log,前面一堆的可以忽略,直接看最下面的,比如我的:


知道了问题,搜索的范围变小了很多了,直接百度:javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair

查看了很多资料,终于找到了原因,jdk1.6只支持1024字节的DH,我发现我证书的公钥是2048字节的,所以报错了,jdk1.7以上支持,所以成功。


可以查看详细的说明:

传送门:https://stackoverflow.com/questions/6851461/java-why-does-ssl-handshake-give-could-not-generate-dh-keypair-exception

https://github.com/syncany/syncany/issues/483

所以解决方法是:

1.下载jar包:传送门:http://download.csdn.net/detail/nk_tf/9609842   (先前在csdn上下载了一份,发现是坏的jar包,我的1分没了,气死我了~~)

2.复制这两个jar包到: $JAVA_HOME/jre/lib/ext 

3.编辑$JAVA_HOME/jre/lib/security/java.security,在9下面加入这句:

security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider

security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=com.sun.net.ssl.internal.ssl.Provider
security.provider.4=com.sun.crypto.provider.SunJCE
security.provider.5=sun.security.jgss.SunProvider
security.provider.6=com.sun.security.sasl.Provider
security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.8=sun.security.smartcardio.SunPCSC
security.provider.9=sun.security.mscapi.SunMSCAPI
security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider
重新调用,没报错,OK!!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值