赞
踩
PEM (Privacy Enhancement Message),定义见 RFC1421
是一种基于 base64 的编码格式,常见于 linux/unix 下的证书编码
结构组成 == {header} body {tail}
示例
- -----BEGIN PUBLIC KEY-----
- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMYfnvWtC8Id5bPKae5yXSxQTt
- +Zpul6AnnZWfI2TtIarvjHBFUtXRo96y7hoL4VWOPKGCsRqMFDkrbeUjRrx8iL91
- 4/srnyf6sh9c8Zk04xEOpK1ypvBz+Ks4uZObtjnnitf0NBGdjMKxveTq+VE7BWUI
- yQjtQ8mbDOsiLLvh7wIDAQAB
- -----END PUBLIC KEY-----
DER (Distinguished Encoding Rules) , 定义见维基百科-ASN.1.DER
是来自ASN.1 体系的一种二进制编码格式,常用于 windows/mac 的证书编码
编码方式 == DER uses a pattern of type-length-value triplets
PKCS (Public Key Cryptography Standards),定义见维基百科-PKCS
是一套公钥密码学标准,其定义范围涵盖了证书签名、加密算法、填充模式及校验流程等。
常见PKCS标准
版本 | 里程碑 |
---|---|
PKCS#1 | RFC8017,定义了公钥私钥的编码格式(ASN.1编码),包括基础算法及编码/填充模式、签名校验,openssl的默认标准格式 |
PKCS#3 | DiffieHellman Key Agreement,定义了DH 密钥交换标准 |
PKCS#5 | RFC8018,基于密码的加密标准,定义了PBKDF2算法 |
PKCS#7 | RFC2315,定义密钥信息语法标准,PKI体系下的信息签名及加密标准,是S/MIME的一部分 |
PKCS#8 | RFC5958,定义私钥信息语法标准,用于描述证书密钥对的通用格式(不限RSA) |
PKCS#11 | 定义了密钥 Token接口,常用于单点登录/公钥算法/磁盘加密系统.(硬件加密) |
PKCS#12 | RFC7292,个人信息交换语法标准,定义了私钥和公钥证书的存储方式(支持密码),常用PFX简称,Java Key Store的编码格式 |
PublicKey-PKCS#1-PEM
- -----BEGIN RSA PUBLIC KEY-----
- BASE64 ENCODED DATA
- -----END RSA PUBLIC KEY-----
PublicKey-PKCS#1-DER
- RSAPublicKey ::= SEQUENCE {
- modulus INTEGER, -- n
- publicExponent INTEGER -- e
- }
PublicKey-PKCS#8-PEM
- -----BEGIN PUBLIC KEY-----
- BASE64 ENCODED DATA
- -----END PUBLIC KEY-----
PublicKey-PKCS#8-DER
- PublicKeyInfo ::= SEQUENCE {
- algorithm AlgorithmIdentifier,
- PublicKey BIT STRING
- }
-
- AlgorithmIdentifier ::= SEQUENCE {
- algorithm OBJECT IDENTIFIER,
- parameters ANY DEFINED BY algorithm OPTIONAL
- }
PrivateKey-PKCS#1-PEM
- -----BEGIN RSA PRIVATE KEY-----
- BASE64 ENCODED DATA
- -----END RSA PRIVATE KEY-----
PrivateKey-PKCS#1-DER
- RSAPrivateKey ::= SEQUENCE {
- version Version,
- modulus INTEGER, -- n
- publicExponent INTEGER, -- e
- privateExponent INTEGER, -- d
- prime1 INTEGER, -- p
- prime2 INTEGER, -- q
- exponent1 INTEGER, -- d mod (p-1)
- exponent2 INTEGER, -- d mod (q-1)
- coefficient INTEGER, -- (inverse of q) mod p
- otherPrimeInfos OtherPrimeInfos OPTIONAL
- }
PrivateKey-PKCS#8-PEM
- -----BEGIN PRIVATE KEY-----
- BASE64 ENCODED DATA
- -----END PRIVATE KEY-----
PrivateKey-PKCS#8-DER
- PrivateKeyInfo ::= SEQUENCE {
- version Version,
- algorithm AlgorithmIdentifier,
- PrivateKey OCTET STRING
- }
-
- AlgorithmIdentifier ::= SEQUENCE {
- algorithm OBJECT IDENTIFIER,
- parameters ANY DEFINED BY algorithm OPTIONAL
- }
私钥文件可采用加密方式存储,加密后的格式:
EncryptedPrivateKey-PKCS#8-PEM
- -----BEGIN ENCRYPTED PRIVATE KEY-----
- BASE64 ENCODED DATA
- -----END ENCRYPTED PRIVATE KEY-----
Encrypted-PrivateKey-PKCS#8-DER
- EncryptedPrivateKeyInfo ::= SEQUENCE {
- encryptionAlgorithm EncryptionAlgorithmIdentifier,
- encryptedData EncryptedData
- }
-
- EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-
- EncryptedData ::= OCTET STRING
RSA 密钥 文件如何读取?
公钥文件 都可以在获取二进制字节数组后,用 X509EncodedKeySpec 初始化,使用KeyFactory 转化成 publickey 对象
- //入参为base64 编码的公钥字符串,这个字符串可以是从公钥文件里获取的,也可以是直接手动拼接的
- public static PublicKey getPublicKey(String publicKeyStr)
- throws GeneralSecurityException {
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");//
- byte[] encodedKey = Base64.decodeBase64(publicKeyStr);
- return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
- }
私钥文件都可以在获取二进制字节数组后,用PKCS8EncodedKeySpec初始化,然后使用KeyFactory转化成 privateKey对象。
- /**
- * 获取私钥
- * 入参出的私钥字符串,可以是自己生成的,也可以是从文件里读取的,总之通过私钥字符串生成私钥就可以这样用
- * @param privateKeyStr
- * @return
- * @throws NoSuchAlgorithmException
- * @throws InvalidKeySpecException
- */
- public static PrivateKey getPrivateKey(String privateKeyStr)
- throws GeneralSecurityException {
- PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
- Base64.decodeBase64(privateKeyStr));
- KeyFactory keyf = KeyFactory.getInstance("RSA");
- return keyf.generatePrivate(priPKCS8);
- }
X.509 证书,维基百科-X.509,是目前流行的公钥证书标准。
一个 X.509 证书包含了一个公钥和对应的实体名(hostname/organization/individual);证书通常由证书认证机构签名或自签名;当证书持有者被另外一方信任时(通过公钥签名验证),两者便可以基于公钥算法建立安全传输通道。
- Certificate
- Version Number
- Serial Number
- Signature Algorithm ID
- Issuer Name
- Validity period
- Not Before
- Not After
- Subject name
- Subject Public Key Info
- Public Key Algorithm
- Subject Public Key
- Issuer Unique Identifier (optional)
- Subject Unique Identifier (optional)
- Extensions (optional)
- ...
- Certificate Signature Algorithm
- Certificate Signature
主要字段
字段 | 描述 |
---|---|
版本号 | 指出该证书使用了哪种版本的X.509标准(版本1、版本2或是版本3),版本号会影响证书中的一些特定信息 |
序列号 | 标识证书的唯一整数,由证书颁发者分配的本证书的唯一标识符 |
签名算法标识符 | 用于签证书的算法标识,由对象标识符加上相关的参数组成,用于说明本证书所用的数字签名算法。例如,SHA-1-RSA |
颁发者名称 | 证书颁发者的可识别名(DN),是签发该证书的实体唯一的CA的X.500名字 |
有效期限 | 证书起始日期和时间以及终止日期和时间 |
主体名 | 证书持有人的唯一标识符(或称DN-distinguished name) |
公钥信息 | 包括证书持有人的公钥、算法 |
颁发者唯一标识符 | 标识符—证书颁发者的唯一标识符,仅在版本2和版本3中有要求,属于可选项 |
主体唯一标识符 | 标识符—证书颁发者的唯一标识符,仅在版本2和版本3中有要求,属于可选项 |
颁发者的数字签名 | 这是使用颁发者私钥生成的签名,以确保这个证书在发放之后没有被撰改过 |
扩展信息 | .. |
扩展字段
字段 | 描述 |
---|---|
发行者密钥标识符 | 证书所含密钥的唯一标识符,用来区分同一证书拥有者的多对密钥 |
密钥使用 | 一个比特串,指明(限定)证书的公钥可以完成的功能或服务,如:证书签名、数据加密等。如果某一证书将 KeyUsage 扩展标记为“极重要”,而且设置为“keyCertSign”,则在 SSL 通信期间该证书出现时将被拒绝,因为该证书扩展表示相关私钥应只用于签写证书,而不应该用于 SSL |
CRL分布点 | 指明CRL的分布地点 |
私钥的使用期 | 指明证书中与公钥相联系的私钥的使用期限,它也有Not Before和Not After组成。若此项不存在时,公私钥的使用期是一样的 |
证书策略 | 由对象标识符和限定符组成,这些对象标识符说明证书的颁发和使用策略有关 |
策略映射 | 表明两个CA域之间的一个或多个策略对象标识符的等价关系,仅在CA证书里存在 |
主体别名 | 指出证书拥有者的别名,如电子邮件地址、IP地址等,别名是和DN绑定在一起的 |
颁发者别名 | 指出证书颁发者的别名,如电子邮件地址、IP地址等,但颁发者的DN必须出现在证书的颁发者字段 |
主体目录属性 | 指出证书拥有者的一系列属性。可以使用这一项来传递访问控制信息 |
- Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 10:e6:fc:62:b7:41:8a:d5:00:5e:45:b6
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2
- Validity
- Not Before: Nov 21 08:00:00 2016 GMT
- Not After : Nov 22 07:59:59 2017 GMT
- Subject: C=US, ST=California, L=San Francisco, O=Wikimedia Foundation, Inc., CN=*.wikipedia.org
- Subject Public Key Info:
- Public Key Algorithm: id-ecPublicKey
- Public-Key: (256 bit)
- pub:
- 04:c9:22:69:31:8a:d6:6c:ea:da:c3:7f:2c:ac:a5:
- af:c0:02:ea:81:cb:65:b9:fd:0c:6d:46:5b:c9:1e:
- ed:b2:ac:2a:1b:4a:ec:80:7b:e7:1a:51:e0:df:f7:
- c7:4a:20:7b:91:4b:20:07:21:ce:cf:68:65:8c:c6:
- 9d:3b:ef:d5:c1
- ASN1 OID: prime256v1
- X509v3 extensions:
- X509v3 Key Usage: critical
- Digital Signature, Key Agreement
- Authority Information Access:
- CA Issuers - URI:http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt
- OCSP - URI:http://ocsp2.globalsign.com/gsorganizationvalsha2g2
-
- X509v3 Certificate Policies:
- Policy: 1.3.6.1.4.1.4146.1.20
- CPS: https://www.globalsign.com/repository/
- Policy: 2.23.140.1.2.2
-
- X509v3 Basic Constraints:
- CA:FALSE
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://crl.globalsign.com/gs/gsorganizationvalsha2g2.crl
-
- X509v3 Subject Alternative Name:
- DNS:*.wikipedia.org, DNS:*.m.mediawiki.org, DNS:*.m.wikibooks.org, DNS:*.m.wikidata.org, DNS:*.m.wikimedia.org, DNS:*.m.wikimediafoundation.org, DNS:*.m.wikinews.org, DNS:*.m.wikipedia.org, DNS:*.m.wikiquote.org, DNS:*.m.wikisource.org, DNS:*.m.wikiversity.org, DNS:*.m.wikivoyage.org, DNS:*.m.wiktionary.org, DNS:*.mediawiki.org, DNS:*.planet.wikimedia.org, DNS:*.wikibooks.org, DNS:*.wikidata.org, DNS:*.wikimedia.org, DNS:*.wikimediafoundation.org, DNS:*.wikinews.org, DNS:*.wikiquote.org, DNS:*.wikisource.org, DNS:*.wikiversity.org, DNS:*.wikivoyage.org, DNS:*.wiktionary.org, DNS:*.wmfusercontent.org, DNS:*.zero.wikipedia.org, DNS:mediawiki.org, DNS:w.wiki, DNS:wikibooks.org, DNS:wikidata.org, DNS:wikimedia.org, DNS:wikimediafoundation.org, DNS:wikinews.org, DNS:wikiquote.org, DNS:wikisource.org, DNS:wikiversity.org, DNS:wikivoyage.org, DNS:wiktionary.org, DNS:wmfusercontent.org, DNS:wikipedia.org
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- X509v3 Subject Key Identifier:
- 28:2A:26:2A:57:8B:3B:CE:B4:D6:AB:54:EF:D7:38:21:2C:49:5C:36
- X509v3 Authority Key Identifier:
- keyid:96:DE:61:F1:BD:1C:16:29:53:1C:C0:CC:7D:3B:83:00:40:E6:1A:7C
-
- Signature Algorithm: sha256WithRSAEncryption
- 8b:c3:ed:d1:9d:39:6f:af:40:72:bd:1e:18:5e:30:54:23:35:
- 66:5e:62:d5:01:e2:63:47:70:cb:6d:1b:17:b0:f5:4d:11:e4:
- ad:94:51:c5:5e:72:03:b0:d5:ab:18:eb:b5:3a:08:a8:73:95:
- f3:7f:41:1a:28:7b:45:7c:83:2e:d3:14:95:d8:d5:d1:5f:99:
- 4b:0c:f4:c3:9b:0b:4f:e9:49:f4:2c:b5:ae:c3:1d:7d:2a:80:
- f6:70:29:4c:0c:e6:e0:cb:88:8a:8a:02:ee:a5:d1:73:c2:93:
- 58:24:ff:43:1b:e3:fd:7b:aa:f0:15:0c:60:52:8f:21:7d:87:
- 3a:14:fa:81:41:00:60:4f:96:9a:62:94:58:de:cb:15:5c:3c:
- f4:c1:4d:33:e3:ff:39:fe:28:fb:b0:41:3e:d2:8a:11:d1:06:
- 01:28:74:7d:71:d4:2a:ef:1f:e3:25:4b:2d:f0:66:ef:26:fb:
- 4c:f0:81:85:bb:1a:99:06:c9:37:87:de:8d:49:f7:00:91:a9:
- 42:31:4a:b9:40:a0:7d:4f:4f:a6:ea:d4:58:07:3c:01:e0:1a:
- 53:54:66:e1:a3:7e:30:cd:3b:f8:69:59:a3:48:92:48:e1:9e:
- 63:ab:08:70:91:f2:48:d2:83:4b:98:06:fa:fd:bc:99:02:da:
- 9c:98:b1:a3
基于x509 标准的证书的公钥读取方式如下
1 从证书中获取公钥对象,然后从公钥对象获取base64编码公钥字符串的方法
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- X509Certificate cert = (X509Certificate)cf.generateCertificate(new FileInputStream("my.cer"));
- PublicKey publicKey = cert.getPublicKey();
- BASE64Encoder base64Encoder=new BASE64Encoder();
- String publicKeyString = base64Encoder.encode(publicKey.getEncoded());
- System.out.println("-----------------公钥--------------------");
- System.out.println(publicKeyString);
- System.out.println("-----------------公钥--------------------");
- ---------------------
或者
- URL url = Demo.class.getClassLoader().getResource("C000024.crt"); //证书路径
- System.out.println("公钥所在路径:"+url.getFile());
- X509Certificate cert = X509Certificate.getInstance(new FileInputStream(url.getFile()));
- PublicKey publicKey = cert.getPublicKey();
- BASE64Encoder base64Encoder=new BASE64Encoder();
- String publicKeyString = base64Encoder.encode(publicKey.getEncoded());
- System.out.println("-----------------公钥--------------------");
- System.out.println(publicKeyString);
- System.out.println("-----------------公钥--------------------");
说明:因为只做示例,没有进行异常处理和流的释放,方式1的代码可能少点,方式2需要强转,美观上可能方式1更好看点,但方式1的实质还是调用的方式2,方式2内部有实现缓存策略.更多可以参考下api文档,文档上有提供示例.
X.509CRT-PEM
- -----BEGIN CERTIFICATE-----
- BASE64 ENCODED DATA
- -----END CERTIFICATE-----
最后说一下,如何从秘钥库中读取 公钥,私钥
1获取秘钥库
- public static KeyStore getKeyInfo(String pfxkeyfile, String keypwd,
- String type) throws IOException {
- LogUtil.writeLog("加载签名证书==>" + pfxkeyfile);
- FileInputStream fis = null;
- try {
- KeyStore ks = null;
- if ("JKS".equals(type)) {
- ks = KeyStore.getInstance(type);
- } else if ("PKCS12".equals(type)) {
- String jdkVendor = System.getProperty("java.vm.vendor");
- String javaVersion = System.getProperty("java.version");
- LogUtil.writeLog("java.vm.vendor=[" + jdkVendor + "]");
- LogUtil.writeLog("java.version=[" + javaVersion + "]");
- // Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
- if (null != jdkVendor && jdkVendor.startsWith("IBM")) {
- // 如果使用IBMJDK,则强制设置BouncyCastleProvider的指定位置,解决使用IBMJDK时兼容性问题
- Security.insertProviderAt(
- new org.bouncycastle.jce.provider.BouncyCastleProvider(),
- 1);
- printSysInfo();
- }else{
- Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
- }
- // ks = KeyStore.getInstance(type, "BC");
- ks = KeyStore.getInstance(type);
- }
- LogUtil.writeLog("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["
- + keypwd + "]");
- fis = new FileInputStream(pfxkeyfile);
- char[] nPassword = null;
- nPassword = null == keypwd || "".equals(keypwd.trim()) ? null
- : keypwd.toCharArray();
- if (null != ks) {
- ks.load(fis, nPassword);
- }
- return ks;
- } catch (Exception e) {
- if (Security.getProvider("BC") == null) {
- LogUtil.writeLog("BC Provider not installed.");
- }
- LogUtil.writeErrorLog("getKeyInfo Error", e);
- if ((e instanceof KeyStoreException) && "PKCS12".equals(type)) {
- Security.removeProvider("BC");
- }
- return null;
- }finally{
- if(null!=fis)
- fis.close();
- }
- }
2 获取公钥信息
- public static PublicKey getSignPublicKey() {
- try {
- Enumeration<String> aliasenum = keyStore.aliases();
- String keyAlias = null;
- if (aliasenum.hasMoreElements()) // we are readin just one
- // certificate.
- {
- keyAlias = (String) aliasenum.nextElement();
- }
- Certificate cert = keyStore.getCertificate(keyAlias);
- PublicKey pubkey = cert.getPublicKey();
- return pubkey;
- } catch (Exception e) {
- LogUtil.writeErrorLog(e.toString());
- return null;
- }
- }
3获取私钥信息
PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, certPwd.toCharArray());
正规流程:去CA机构申请SSL证书
域名型https证书(DVSSL):信任等级一般,只需验证网站的真实性便可颁发证书保护网站;
企业型https证书(OVSSL):信任等级高,须要验证企业的身份,审核严格,安全性更强;
增强型https证书(EVSSL):信任等级最高,一般用于银行证券等金融机构,审核严格,安全性最好,同时可以激活绿色网址栏
CA证书顾名思义就是由CA(Certification Authority)机构发布的数字证书。要对CA证书完全理解及其作用,首先要理解SSL。SSL(security sockets layer,安全套接层)是为网络通信提供安全及数据完整性的一种安全协议。SSL3.0版本以后又被称为TLS。SSL位于TCP与各应用层之间,是操作系统向外提供的API。SSL如何保证网络通信的安全和数据的完整性呢?就是采用了两种手段:身份认证和数据加密。首先身份认证就需要用到CA证书了。先了解CA证书具体包括哪些内容:
颁发者
使用者
版本
签名算法
签名哈希算法
使用者
公钥
指纹
指纹算法
……
上述中颁发者、使用者、版本等内容好理解,颁发者就是CA机构,下面会讲到。对于签名算法、签名哈希算法的理解,首先要先理解签名是什么东东?联系到实际情况,当我们向某机构提供报告时,往往在报告最后加上个人的名字,以表示该报告是我本人的。签名在网络通讯中的应用称为数字签名,当服务器向客户端发送信息时,会将报文生成报文摘要,同时对报文摘要进行hash计算,得到hash值,然后对hash值进行加密,然后将加密的hash值放置在报文后面,这个加密后的hash值就称为签名。服务器将报文、签名和数字证书一同发送给客户端。客户端收到这些信息后,会首先验证签名,利用签名算法对签名进行解密,得到报文摘要的hash值,然后将得到的报文生成报文摘要并利用签名hash算法生成新的hash值,通过对比这两个hash值是否一致,就能判断信息是否完整,是否是由真正的服务器发送的。可知签名有两个作用确认消息发送方可靠,确认消息完整准确。
上面提到了hash值的加密,我们还需要理解SSL的加密机制,在使用SSL的网络通讯过程中,消息在请求和响应中都是加密传送的。首先要知道加密算法分为两种:对称加密和非对称加密。对称加密就是发送双发使用相同的密钥对消息进行加解密,常见的对称加密为DES、3DES,AES等。非对称加密是发送双方各自拥有一对公钥私钥,其中公钥是公开的,私钥是保密的。当发送方向接收方发送消息时,发送方利用接收方的公钥对消息进行加密,接收方收到消息后,利用自己的私钥解密就能得到消息的明文。其中非对称加密方法有RSA、Elgamal、ECC等。此处只是简单了说明了这两种加密机制的过程,若要深入理解它们的原理、过程请搜索相应的资料,很容易搜索到。
好了,了解了签名原理和两种加密机制,我们继续理解网络通讯中是怎么利用CA证书进行身份认证的?客户端与服务端需要经过一个握手的过程才能完成身份认证,建立一个安全的连接。握手的过程如下:
以上就是整个握手的过程,在第三步实际上就完成了身份的认证,第四、五步是进行密钥的商定,因为非对称加密算法对数据加密非常慢,效率低,而对称加密加密效率很高,因此在整个握手过程要生成一个对称加密密钥,然后数据传输中使用对称加密算法对数据加密。可知ssl整个握手过程包括身份认证、密钥商定。上述讲述ssl的握手过程比较简单,想要深入理解ssl原理,下面这篇博文讲的不错:
https://segmentfault.com/a/1190000002554673
一定要看上面的博文,否则无法彻底理解证书使用的原理。
一般来说,现在公共网站数据传输都是使用SSL,即通过https协议访问。Https就是http加SSL。在上面SSL握手过程中,客户端是如何验证服务器发送的CA证书呢?我们以12306网站为例进行说明,此时,客户端就是浏览器,如果我们是第一次访问12306网站,使用https://www.12306.cn地址访问,返回如下结果:
提示此网站的安全证书有问题,说明证书不可信,如果我们忽略证书不可信,继续访问网站,打开12306网页,在首页提供一个根证书的下载,见下页面:
下载根证书,安装完毕,再次访问12036网站,就不会提示网站的安全证书有问题了。这是什么机制呢?
打开【工具】菜单(360浏览器为例),然后选择【内容】选项卡,点击【证书】按钮,打开证书窗口,选择【中级证书颁发机构】,会看到已经安装的12306的证书:
只要安装上12306证书,就说明证书是可信的。使用https协议访问时,服务器发送证书向浏览器时,首先查找该证书是否已在信任列表中,然后对证书进行校验,校验成功,那么就证明证书是可信的。另外,证书的认证是安装证书链执行的,证书链的意思是有一个证书机构A,A生成证书B,B也可以生成证书C,比如在证书窗口中有一个360证书,见下图:
360证书的颁发者是certification authority of wosign,在【受信任的根证书颁发机构】中,我们会看到该证书:见下图,
也就是说,certification authority of wosign生成360证书,360可以生成其它的证书。A证书或者certification authority of wosign证书在整个证书链上就被称为根证书,证书验证的机制是只要根证书是受信任的,那么它的子证书都是可信的。比如说,我们使用https协议访问了需要360证书的网站,即使我们不安装360证书,那么网站也不会提示证书不安全,因为,生成360证书的根证书certification authority of wosign证书,在受信任的证书列表中。如果一个证书的根证书是不可信的,那么这个证书肯定也是不可信任的。
由以上可知,根证书在证书验证中极其重要,而且,根证书是无条件信任的,只要我们将根证书安装上,就说明我们对根证书是信任的。比如我们安装12306的根证书,是出于我们对国家的信任,对网站的信任,我们才放心安装这个根证书。对于一些不安全的网站的证书,一定要慎重安装。
另外需要知道的是,【受信任的根证书颁发机构】中的证书是windows预先安装的一些证书,都是国际上很有权威的证书机构,他们证书的生成都有很严格的流程,因此他们的证书被认为是安全,就像我们相信银行是安全,所以把钱存入到银行。
世界上较早的数字认证中心是美国的verisign公司,在windows的证书窗口中可以看到好多verisign公司生成的证书,见下图:
另外还有加拿大的ENTRUST公司,也是很著名的证书机构。中国的安全认证体系分为金融CA和非金融CA。在金融CA方面,根证书由中国人民银行管理,在非金融CA方面,由中国电信负责。中国CA又可分为行业性CA和区域性CA,行业性CA中影响最大是中国金融认证中心和中国电信认证中国;区域性CA主要是以政府为背景,以企业机制运行,其中广东CA中心和上海CA中影响最大。
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.security.InvalidAlgorithmParameterException;
- import java.security.KeyStore;
- import java.security.KeyStoreException;
- import java.security.NoSuchAlgorithmException;
- import java.security.cert.CertificateException;
- import java.security.cert.PKIXParameters;
- import java.security.cert.TrustAnchor;
- import java.security.cert.X509Certificate;
- import java.util.Iterator;
-
-
- public class Main {
-
- public static void main(String[] args) {
- try {
- // Load the JDK's cacerts keystore file
- String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
- FileInputStream is = new FileInputStream(filename);
- KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
- String password = "changeit";
- keystore.load(is, password.toCharArray());
-
- // This class retrieves the most-trusted CAs from the keystore
- PKIXParameters params = new PKIXParameters(keystore);
-
- // Get the set of trust anchors, which contain the most-trusted CA certificates
- Iterator it = params.getTrustAnchors().iterator();
- while( it.hasNext() ) {
- TrustAnchor ta = (TrustAnchor)it.next();
- // Get certificate
- X509Certificate cert = ta.getTrustedCert();
- System.out.println(cert);
- }
- } catch (CertificateException e) {
- } catch (KeyStoreException e) {
- } catch (NoSuchAlgorithmException e) {
- } catch (InvalidAlgorithmParameterException e) {
- } catch (IOException e) {
- }
- }
- }
有时候,我们在内部系统传输数据需要使用SSL协议,对数据加密,但是我们又不想花钱去申请CA,这个时候可以使用自签名CA,实现数据加密传输的功能。首先要明确一点就是自签名证书是不安全的,存在安全漏洞,具体看下面的博文介绍:
为什么”自签名SSL证书”不安全?
https://www.wosign.com/FAQ/selfsigned_SSL_insecure.htm
自签名证书使用jdk中的keytool生成即可,看似神秘,但实际上比较简单,见下博文:
如何利用keytool工具生成数字证书
https://jingyan.baidu.com/article/b0b63dbfe18eff4a483070f4.html
自签名证书的安装也很简单,见下博文:
添加自签发的 SSL 证书为受信任的根证书
https://cnzhx.net/blog/self-signed-certificate-as-trusted-root-ca-in-windows/
在java编程中,使用socket网络编程,实现SSL协议,对服务器的证书需要导入到客户端的秘钥库中,这样才能完成自动认证,具体实现见下博文:
JAVA SSL SOCKET通信服务器端客户端证书双向认证
http://blog.csdn.net/matt8/article/details/45071815
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。