自建keystore 再下载网页证书,导入自建keystore,最后用此keystore 读取https网页(java读取https的4种方法和详细认证网页证书)

keystore  truststore 本质是一样的,我们就用自建的keystore作为truststore.

1:在我的java工作目录/home/wzpad/java下运行,生成keystore文件:keystore.jks

keytool -genkey -alias  mydomain   -keyalg RSA  -keystore keystore.jks -storepass 123456

2:打开chrome浏览器,导出想要的网页的证书,并存储,比如我导出https://cn.bing.com的证书取名为bing.crt  复制此文件到工作目录。

3:将 bing.crt 文件导入刚建的keystore.jks.

keytool -import -alias bing   -keystore keystore.jks  -file  bing.crt

好了,现在可以用此 keystore.jks 来读取https://cn.bing.com网页了。经验证,这个证书可以打开所有微软bing搜索的网页。

命令行运行java 程序时,必须要指明此keystore.jks 文件的路径:

-Djavax.net.ssl.trustStore=/home/wzpad/java/keystore.jks  -Djavax.net.ssl.trustStorePassword=123456注意最二个-D参数前要有空格

经验证,完美打开网页,如删掉keystore.jks中bing证书,则程序报错。或者用此证书打开除bing外的其他网页,如百度网页则报错。

删除命令:keytool  -delete -alias bing  -keystore keystore.jks

因为java  和eclipse 预置了cacerts 文件,它里面内置了很多著名网页的根证书,就包括www.bing.com 网页的。

特别要注意,在linux系统中使用命令行java 和使用eclipse程序两者使用不同的 JDK,所以它们使用的cacerts 也不同。如要验证,根据使用的程序的不同必须屏敝掉相应的cacerts. 千万不要删掉,可改名。这个问题困挠了我好久,否则对程序怎样加执行参数,它都会去找cacerts 来验证。只有把原版的 cacerts屏敝掉后,加参数才能执行我们的 keystore.jks  .java命令行的cacerts 可用java -verbose 找  到,eclipse 中的在/opt/apps/ 下面,可以在网上查一下。补充一下, macbook 中java命令行和eclipse 使用的是同一个JDK,所以只要用java -verbose 查到cacerts 改名一下eclipse也不影响了。windows没有用,不清楚情况。

看JDK文档,SSLSocketFactory 中封装了握手协议和认证方法等。

以下是我的理解:认证https网页有两种方法,一种是用SSLSocketFactory类工厂化的认证,就是我们现在用的方法。如没加载自编的keystore.jks ,它就自动去加载预置的cacerts 库比对验证证书。

SocketFactory sf=SSLSocketFactory.getDefault();

第二种就是用户自定义认证:SSLContext引用各种接口。

SSLSocketFactory  sslf=SSLContext.getSocketFactory(); 这里面有一个X509TrustManager接口,它有一重要的方法函数,checkServerTrusted() 如果不操作的话,程序对外来网页不作任何认证的。连最基本的证书都不检查,因为程序是把认证环节交给用户的。如用户不写检查代码则没有任何反馈,程序就认为证书合法通过放行了。

第一个程序是采用socket 和SSLSocketFactory 的工厂化认证方法读取https网页

66b9a0c4ce914aa4b016bb07e7d164b0.png

import java.io.*;
import java.net.*;
import javax.net.*;
import javax.net.ssl.*;
 
public class Sslclient {
	public static void main(String[] args) {
		try {
		    SocketFactory ssf=SSLSocketFactory.getDefault();
	    	Socket sc=ssf.createSocket("cn.bing.com",443);
	
		
			//sc.startHandshake();
			
			OutputStream os=sc.getOutputStream();
			InputStream is=sc.getInputStream();
			
  			os.write("GET / HTTP/1.1\r\n".getBytes());
			os.write("Host:cn.bing.com\r\n".getBytes());
			os.write("Connection:close\r\n\r\n".getBytes());
			os.flush();
		    
			InputStreamReader isr=new InputStreamReader(is,"UTF-8");
			int k;
			String s="";
			do{
				
				k=isr.read();
				s=s+(char)k;
			}while(k!=-1);
			System.out.print(s);
	     	
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

下面的程序是采用HttpsURLConnection类和   SSLSocketFactory的工厂化认证方法读取https网页

import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import javax.net.*;
public class Sslsocket {
	public static void main(String[] args) {
		try {
			URL url=new URL("https://cn.bing.com");
			HttpsURLConnection surl = (HttpsURLConnection)url.openConnection();
		//	surl.setDoInput(true);
		
		    SSLSocketFactory ssf=(SSLSocketFactory)SSLSocketFactory.getDefault();
		    surl.setSSLSocketFactory(ssf);
		   
		    InputStream is1=surl.getInputStream();
		    InputStreamReader is=new InputStreamReader(is1,"UTF-8");
		    int k;
		    String s="";
		    do {
		    	k=is.read();
		    	s=s+(char)k;
		    }while(k!=-1);
		    System.out.print(s);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
		
		
	}
}

eclipse run指令加上参数-Djavax.net.ssl.trustStore=/home/wzpad/java/keystore.jks  -Djavax.net.ssl.trustStorePassword=123456 后,如果删除bing证书此二个程序都报错,加上读出网页。

学到这里突然发现,我们可以通过Socket SeverSocket 利用SSLSocketFactory的工厂化方法加密传送文件了。其实所有的网络通信编程都归到Socket上,只不过是加上了各种网络协议而已。都是Socket 和ServerSocket的应答交互模式。

RFC5280 中文翻译 中文RFC RFC文档 RFC翻译 RFC中文版

先试试水,用证书的数字签名(指纹)来判断。getSignature() 提取证书数字签名。

说一下我对接口这个概念的理解:接口就是java封装的类与编程者之间沟通的桥梁,接口的参数是封装程序已经得到的数据,这个数据是供编程者使用的,而类正好相反,是编程者向程序提供的方法,告诉程序怎样办。这样就好理解接口X509TrustManager 了。封装类SSLContext和 SSLSocketFactory 经过一系列交互取得证书,就用X509这接口把已取得的证书提供给编程者使用。

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
				char[] password = {'1','2','3','4','5','6'};
				FileInputStream fis = new FileInputStream("/home/wjs/java/mycert");	
				ks.load(fis, password);
			// System.out.println(ks.size());
				                                                             //上面四条是JDK文档标准加载密钥库代码
			    var cert=ks.getCertificate("business");
			    System.out.print(cert.toString());

 //上面四条是JDK文档说明中加载密钥库的标准代码,这样就可以加载cacerts.

 var is=new FileInputStream("证书文件名");
			    var cf=CertificateFactory.getInstance("X.509");
			    var cer=(X509Certificate)cf.generateCertificate(is);

这三句是加载证书的标准代码

证书签名,在JDK的文档中又叫公钥签名。在证书的第三版国际标准中的扩展部份才加入了域名,这说明早期的证书签名只是为了公钥这个目标的。

keytool -genkeypair -dname "cn=Mark Jones, ou=Java, o=Oracle, c=US"  -alias business -keypass 123456 -keystore mycert     -storepass 123456 -validity 180
这是JDK 文档中用keytool 生成自签名证书的命令行。最开始生成的是公钥私钥密码对。生成的mycert 是一个密码库,里面有一条business 。用keytool -list打开如下:

9c4e5ae248eb4aacabb82628fed08e4f.png

 所有者和发布者相同,说明是自签名。

公钥私钥交互介绍 - 新手娃娃菜 - 博客园

推荐一好文,把证书的细节说清楚了

//-------------------------------------------------------------------------------------------------------------------------------

学到此,想搞懂ssl .https  ,又要去学Base64  RSA编码解码,正好换一下思路。

先看看Base64:

import java.security.*;
import java.util.Base64;
public class Rsa {
	public static void main(String[] args) {
	
		String s="12wjs";
		byte[] a=s.getBytes();
		Base64.Encoder be=Base64.getEncoder();
		byte[] b=be.encode(a);
		for(byte k:b) {
			System.out.print((char)k);
		}
	
	    System.out.println();	
		Base64.Decoder bd=Base64.getDecoder();
		byte[] c=bd.decode(b);
		for(byte k1:c) {
			System.out.print((char)k1);
		}
		

这个Base64用处很大实用。用它可以简单加密一下你的文档。

因为Base64是针对字节加解密,下面程序我改进对中文操作

5a0186a821c147929266ae57e349eb54.png

import java.security.*;
import java.util.Base64;
import java.io.*;
public class Rsa {
	public static void main(String[] args) {
	
		String s="我爱你老婆,哈哈哈";
		byte[] a=s.getBytes();
		Base64.Encoder be=Base64.getEncoder();
		byte[] b=be.encode(a);
		for(byte k:b) {
			System.out.print((char)k);
		}
	
	    System.out.println();	
		Base64.Decoder bd=Base64.getDecoder();
		byte[] c=bd.decode(b);
	    var ou=new ByteArrayInputStream(c);
	    try {
			var ou1=new InputStreamReader(ou,"UTF-8");
			
			try {
				for(int t=0;t<c.length/2;t++) {
				System.out.print((char)ou1.read());
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    

为什么要使用此编码,是因为生成的密钥很多是不可显示的字符,或者显示为乱码,所以要把它们转化为可见状态。比如生成的公钥数值很多就不可见,要让它可见就必须转换。

------------------------------------------

判断证书是否被信任从四方面入手:

1. 签名能不能被公钥解密。如能,则证明对方是服务器。

2. 证书的根证书是否在cacerts中,如在则被信任。

3.证书的内容的哈希值是否与本证书中的指纹相符,是被信住,否则内容被修改过。一般情况下一个网页至少要对应两张证书,那就要验两次,验根证书时可能是先调用cacerts中的证书比对一下接收的根证书?用equals()?

4 被访问主页域名,证书期限,是否被吊销

这几天正找验证证书内容哈希值的方法,突然想到传入的证书应该不只一张,经查baidu的chain长度为3,真有三张。最后第三张是根证书,应该在cacerts 中,是不是用根证书的公钥去解密第二张的加密指纹,验证第二张,再用第二张的公钥去解第一张的加密指纹,验证第一张。chain[0] 是baidu证书。现在的难点是不清楚证书内容怎样提取,摘要方法有了,没有准确的摘要内容也比对不了指纹。试了Certificate类和x509certificate 类中几个get函数方法得到的内容,摘要后去比对都不相符。还有用get提取的指纹要经过多少次解密。对于每一张证书又怎样解密。查遍了网络,没有一篇文章说清楚。怪不得著名的浏览器就只有3,4个。

我现在的理解:证书所有者申请证书的文件里至少有公钥,所有者名,申请者网站域名,不会有颁发者名字,证书串号,有效期。所以申请者提交的文件肯定没有指纹。此申请文件到了颁发者手里,再加入串号,有效期等内容后组成证书的明文内容,颁发者对明文内容进行摘要哈希计算得到指纹。此指纹是不可能被申请者私钥加密的。因为申请者只提供了公钥,好了,颁发者用自己的私钥给此证书的指纹加密,又叫签名。现在得到的签名又叫加密指纹是只加密了一次的指纹。所以chain[0]证书的指纹是没有被chain[0]证书所有者用私钥加密的?就不会被它的公钥解密了?现在正用这种思路验证根证书chain[0]。

再次发现,这个接收证书的数组是变化的,比如百度是三个,bing是两个。使用前要搜一下长度。

import java.io.*;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.net.ssl.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import java.util.Arrays;

public class Hs {
	  
	   public static void main(String[] args)throws Exception{
	     try {
			SSLContext sslc = SSLContext.getInstance("TLSv1.2");
			TrustManager[] tm = {new X509()};
			sslc.init(null, tm, new SecureRandom());
          SSLSocketFactory sc = sslc.getSocketFactory();
          Socket in=sc.createSocket("www.baidu.com",443);
          
          InputStream isr=in.getInputStream();
          OutputStream os=in.getOutputStream();
          os.write("GET / HTTP/1.1\r\n".getBytes());
          os.write(("Host:www.baidu.com\r\n").getBytes());
          os.write("Connection:close\r\n\r\n".getBytes());
          os.flush();
          InputStreamReader is=new InputStreamReader(isr,"UTF-8");
          String s="";
          int k;
          k=is.read();
          while(k!=-1) {
       	   s=s+(char)k;
       	   k=is.read();
          }
          System.out.print(s);
       /*   File fl=new File("/home/wzpad/java/1.html");
	       FileOutputStream os1=new FileOutputStream(fl);
	       os1.write(s.getBytes());  
	       os1.close();*/
		} catch (KeyManagementException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	 }   
     
  public static class X509 implements X509TrustManager {
     public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

     }
      public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
   	//   System.out.println(chain.length);
		
				/*	var is=new FileInputStream("/home/wzpad/java/bing.crt");
						CertificateFactory cf=CertificateFactory.getInstance("X.509");
						X509Certificate cert = (X509Certificate)cf.generateCertificate(is);   //引入下载bing证书
						byte[] a=cert.getSignature();                                        //读取bing证书数字签名
					//	PublicKey pub=cert.getPublicKey();
               //		System.out.println(cert.)*/
//-------------------------------------------------------------------		
	//* 1. 验证证书明文是否被修改,就是明文的哈希值是否与签名相互		
						X509Certificate cert1=chain[0];
			    		X509Certificate cert2=chain[1];

			    		//  	X509Certificate cert3=chain[2];
		                
			    		try {
							MessageDigest md=MessageDigest.getInstance("SHA-256");     
							md.update(cert1.getTBSCertificate());                                  
							//MessageDigest tc1= md.clone();
							byte[] tomd1=md.digest();              //证书明文取指纹,哈希算法
							int z;
							String sout="";
							for(int n=0;n<tomd1.length;n++) {
								if((z=tomd1[n])<0) {               //大于127的数加256
									z=z+256;
								}
								sout=sout+Integer.toHexString(z);   //转为字符串形式
							}
			      	       System.out.println(sout);
					//		sout="ff2341";                      //验证用
							PublicKey pub2=cert2.getPublicKey();
							PublicKey pub1=cert1.getPublicKey();
							byte[] sign1=cert1.getSignature();

							Cipher cipher3=Cipher.getInstance("RSA");
							cipher3.init(Cipher.PRIVATE_KEY, pub2);
							byte[] design1=cipher3.doFinal(sign1);      //证书签名解密
					
							
							int z1;
							String sout2="";
							for(int n1=0;n1<design1.length;n1++) {
								if((z1=design1[n1])<0) {               //大于127的数加256
									z1=z1+256;
								}
								sout2=sout2+Integer.toHexString(z1);   //转为字符串形式
							}
					    System.out.println(sout2);
							int zk=sout2.indexOf(sout); //  //如包含关系:相等 zk>0
							if(zk<0) {                  
							
								System.out.println("certificate no ok");
								throw  new CertificateException();   //抛出异常
							}
							
						} catch (CertificateEncodingException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (InvalidKeyException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (NoSuchAlgorithmException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (NoSuchPaddingException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IllegalBlockSizeException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (BadPaddingException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
//1. 明文判断结束  现在只判断了二级证书,根证书还没有判断
      }
      
    public X509Certificate[] getAcceptedIssuers() {
         return null;
     }
  }
  
  
}

上面的程序提取的www.baidu.com网页。已加上异常报错功能.

细想,RSA解密部份没有报错,说明用公钥解密是正确的。那说明提取加密指纹的方法和思路是正确的。试验了一下用pub1解密,则报错。正好说明证书1的指纹是加密的,必须用证书二的公钥解密。而证书二是根证书。正好证明根证书验证环节是正确的。

b84d6824ac53423c8c6fb9783b78b3d6.png

 解密指纹长度是51位,明文的摘要为32位. 输出发现明文摘要包含在解密签名指纹中.试了一下,cn.bing.com    www.baidu.com 都成立.为了严谨,还是要搞清加密指纹还包含什么,但现在应该可以这样判断明文和签名的关系了.如果包含,就相符.

到现在,我们就清楚证书是什么玩意了。如果只收到一张,则有两种可能,一种是根证书,包含在cacerts中那种,另一种就是自签名的证书,自己用私钥加密明文的证书,此证书不包含在cacerts 中,所以浏览器不信任这种证书。如收到两张证书,如cn.bing.com这种网页,一张是微软的,另一张是根证书对微软签发认证的,最后是收到三张证书,如百度网页。 现在理一下认证的顺序。首先查收到几张证书,一张的简单,查一下证书发行方在不在cacerts 中,如在再检验一下明文与指纹相符不,如相等则通过,收到两张的,也是首先查根证书在不在cacerts 中,如在,首先检查收到的根证书明文与签名的哈希值加符不。如相等则检查第二张证书,正好是上面的程序,有第三张的检查和第二张相同。至此,证书明文部份验证就完成了。

我推测,同理,服务器认证客户端,首先是为客户端颁发一张服务器私钥认证签名的证书。就象网银给客户的U盾一样。∪盾里面我想就是一银行签名的数字证书。再在服务器端验证客发端发来的证书是否可靠。这种使用场景可以用在安全性要求高的公司服务器上。为每一个员工配一张数字证书。不通过则上不了内网。下一步计划就是在公网上配置好https服务器再折腾一下,把这个https搞明白。最后的理想是用原生Socket java 写一个https握手交互认证的程序。彻底理解这个交互握手过程。接下来先详细完善客户端对服务器认证的所有代码。

发现我现在明文的摘要和浏览器网页上的SHA256指纹值不同。不知道这两个值是不是该相同,网络上有的说这个值只是作为证书接收方与发证方人工核对之用,程序上不会用,程序核对只要证书签名。没有一个权威的说法。

现在又拦在对根证书的核对上。keystore类上的封装函数站在我的思路上,除了提取公钥和签名两个方法外,剩下的都没有用处。网络上又讲,这个根证书的发证方是变动的,比如破产,被收购。所以签名也会变动,不变的只有它们的公钥,所以准备用它们的公钥作比对。

这几天看JDK,看得云里雾里的。国内的大佬有谁能写一本详细的用法指南就好了。绝对大卖。

我现在认为真正的认证可能不是走的我现在的路线,看jdk上有一几个PKI类,可能是用这几个类来认证的。这都是封装好的,如用封装类肯定简单,但具体细节又不清楚了。

考虑了一下,试着全面学一遍JDK中与https有关的包,回来再继续写https认证。接下来把学习的过程和想法写下来。目前知道的有:

java.security

java.security.cert

javax.crypto

javax.security.cert

这4个包已占了java.base 模块的三分之一。可见这几部份的重要性。可这几部份在java书中很少分析介绍。很多是几句带过。慢慢学慢慢理解。感觉这几个包的实用性非常强,如理解清楚了,就能写出安全方面的程序。

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class Sb {
     public static void main(String[] args) throws CertificateException {

						try {
							URL url=new URL("https://cn.bing.com");
							HttpsURLConnection hurl=(HttpsURLConnection)url.openConnection();
						
							SSLContext sslc=SSLContext.getInstance("TLSv1.2");
							TrustManager[] tm= {new X509()};
							sslc.init(null,tm, null);
							SSLSocketFactory ssc = sslc.getSocketFactory();
							hurl.setSSLSocketFactory(ssc);
						
							InputStream is=hurl.getInputStream();
							InputStreamReader isr=new InputStreamReader(is,"UTF-8");
							int k;
							String s="";
							k=isr.read();
							while (k!=-1) {
								s=s+(char)k;
								k=isr.read();	
							}
					//		System.out.println(s);                   //输出bing网页文件
						} catch (KeyManagementException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (MalformedURLException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (NoSuchAlgorithmException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}				
     }
}
class X509 implements X509TrustManager{
	  public void checkClientTrusted(X509Certificate[] chain,String authType)throws CertificateException{
		  
	  }
	  public void checkServerTrusted(X509Certificate[] chain,String anthType)throws CertificateException{
		  	    
				try {
					var Pub1=chain[1].getPublicKey();       //微软二级证书公钥
					var Pub0=chain[0].getPublicKey();       //bing网页证书公钥    此公钥对于验证没有用
					chain[0].verify(Pub1);                  //JDK 中的方法:用二级证书公钥验证bing证书
					
					//------------------------------------------
					KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
					char[] password = {'c','h','a','n','g','e','i','t'};            //cacerts 密码"changeit"    
					FileInputStream fis = new FileInputStream("/opt/apps/org.eclipse.java-ee/files/plugins/org.eclipse.justj.openjdk.hotspot.jre.full.linux.x86_64_17.0.1.v20211116-1657/jre/lib/security/cacerts");
					ks.load(fis, password);                     //deepin 系统中cacerts路径
					
					var iss1=chain[1].getIssuerX500Principal().getName();    //取得微软二级证书的颁发签名方,装化为String类型
				//	System.out.println(iss1);              //CN=Baltimore CyberTrust Root,OU=CyberTrust,O=Baltimore,C=IE
					iss1=iss1.toLowerCase(); 
				//	System.out.println(iss1);            //装化为小写字母  cn=baltimore cybertrust root,ou=cybertrust,o=baltimore,c=ie
					String[] string1=iss1.split(",");    //和cacerts中的别名比对,从网络得到的别名顺序是反向的,所以把iss1分解为字符串数组,分别比较cn ou o c;
	
					Enumeration<String> enumeration = ks.aliases();       //cacerts全部证书的别名
				    while(enumeration.hasMoreElements()) {
				            String alias = enumeration.nextElement();
				            alias=alias.toLowerCase();                   //转换为小写
				     
				            int zz=0;
				            for(int n=0;n<string1.length;n++) {
				            	if(alias.contains(string1[n])) {         //验证iss1的cn ou o c 4项是不是在alias中,如全在就相等
				                zz=zz+1;                                 //如一项相等,就加一
				            }
				            if(zz==string1.length) {                     //如string1数组全比对完,就等于数组长度
				            	var gcert=ks.getCertificate(alias);	     //取得cacerts中比对正确的证书
				                PublicKey gpub=gcert.getPublicKey();      //取得公钥
				                chain[1].verify(gpub);                    //用cacerts根证书的公钥验证二级微软二级证书签名
				                System.out.println("ok");
				                }
				            }    
				    }

				} catch (InvalidKeyException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (CertificateException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (NoSuchAlgorithmException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (NoSuchProviderException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SignatureException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (KeyStoreException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	
	  }
	  public X509Certificate[] getAcceptedIssuers() {
		  return null;
	  }
}

用jdk的方法验证: 用微软的二级证书公钥验证bing 证书,用cacerts根证书公钥验证微软二级证书

经过一段时间的学习,写的读取https网页的程序,不验证:

import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class Http {
    public static void main(String[] args) throws IOException {
        URL url=new URL("https://cn.bing.com");
        HttpsURLConnection hc= (HttpsURLConnection) url.openConnection();
        InputStream is=hc.getInputStream();
        byte[] b=is.readAllBytes();
        String s=new String(b);
        System.out.println(s);
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要使用Java实现读取证书访问HTTPS接口,需要遵循以下步骤: 1. 获取证书:首先,需要获取要访问的HTTPS服务器证书。可以使用浏览器访问该服务器,并导出证书为一个文件(一般为.crt或.pem格式)。 2. 将证书导入Java密钥库:将第一步获得的证书导入Java密钥库中。可以使用Java提供的keytool工具,执行类似以下命令: ``` keytool -import -file /path/to/certificate.crt -alias servercert -keystore /path/to/keystore.jks ``` 这将把证书导入到指定的密钥库中,并为证书指定一个别名。 3. 创建SSLContext:使用JavaKeyStore类加载密钥库,并创建一个包含需要的信任管理器的SSLContext实例。可以使用以下代码实现: ```java KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); FileInputStream trustStoreFile = new FileInputStream("/path/to/keystore.jks"); trustStore.load(trustStoreFile, "keystorepassword".toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagerFactory.getTrustManagers(), null); ``` 4. 创建HttpClient:使用Apache HttpClient库创建一个HttpClient对象,并指定使用刚才创建的SSLContext实例来进行HTTPS连接。可以使用以下代码实现: ```java HttpClient client = HttpClients.custom().setSSLContext(sslContext).build(); ``` 5. 发送HTTPS请求:使用HttpClient对象发送HTTPS请求到目标接口。可以使用HttpGet或HttpPost等请求类型,并执行execute方法,如下所示: ```java HttpGet request = new HttpGet("https://api.example.com"); HttpResponse response = client.execute(request); ``` 以上步骤完成后,即可通过Java程序读取证书并访问HTTPS接口。需要注意的是,从第3步开始的代码需要进行异常处理,同时确保路径和密码等参数正确配置。 ### 回答2: 要用Java实现读取证书访问HTTPS接口,可以按照以下步骤进行操作: 1. 确保你已经获取到了HTTPS接口所需的证书文件,一般为以.crt、.pem或.jks为扩展名的文件。 2. 首先,需要创建一个HttpClient对象,用于发送HTTP请求。可以使用Apache HttpClient库来实现,该库提供了丰富的HTTP客户端功能。 3. 创建SSLContext对象,用于在发送HTTPS请求时验证服务器证书的有效性。可以使用KeyStore类加载证书文件,并通过TrustManagerFactory初始化SSLContext。 4. 创建一个HostnameVerifier对象,用于验证服务器主机名的有效性。可以使用自定义的实现类,也可以使用默认的实现类。 5. 创建一个HttpClientBuilder对象,并将SSLContext和HostnameVerifier对象设置给它。 6. 使用HttpClientBuilder对象创建HttpClient对象,同时设置代理、超时等相关参数。 7. 创建一个HttpGet或HttpPost对象,设置请求的URL和相关参数。 8. 调用HttpClient对象的execute方法发送请求,并获取返回的HttpResponse对象。 9. 从HttpResponse对象中获取服务器返回的数据,并进行后续处理。 示例代码如下: ```java import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.security.KeyStore; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustManagerFactoryBuilder; public class HttpsClientExample { public static void main(String[] args) { try { // 加载证书 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(HttpsClientExample.class.getResourceAsStream("client-truststore.crt"), "password".toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactoryBuilder.newBuilder() .withDefaultAlgorithm() .withKeystore(trustStore) .build(); SSLContext sslContext = SSLContextBuilder.create() .loadTrustMaterial(trustManagerFactory) .build(); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext)) .build(); HttpGet httpGet = new HttpGet("https://example.com/api"); HttpResponse response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); // 读取返回的数据 InputStream inputStream = entity.getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } httpClient.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 以上就是使用Java实现读取证书访问HTTPS接口的基本步骤,根据具体的证书和接口要求,可能需要进行一些额外的配置和参数设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值