java操作x509数字证书_x509cert jar包-程序员宅基地

技术标签: java  数字证书  加密  

openssl 自建ca,颁发客户端证书
前一篇介绍了非对称加密,数字证书,ca等概念之后,剩下的就是一些实战了

java操作x509数字证书

一般我们自建了ca系统之后,就要颁发给客户端使用,当然证书用途很多了,例如,加密解密,签名验签等这些最原理性的使用,应用场景就比较多了,例如电子签章,数据指纹,生物识别,电商,支付安全等等都使用到了数字证书,例如有些政府部门做的内部身份认证系统,与设备,生物识别等都用到了数字证书。
本人是做java开发的,所以就从java的角度来具体操作下吧
本篇由于篇幅限制,所以不涉及加密,解密,签名验签等操作,只从代码的角度具体操作x509证书


x509证书简介

所有的X.509证书包含以下数据:
1、X.509版本号:指出该证书使用了哪种版本的X.509标准,版本号会影响证书中的一些特定信息。目前的版本是3。
2、证书持有人的公钥:包括证书持有人的公钥、算法(指明密钥属于哪种密码系统)的标识符和其他相关的密钥参数。
3、证书的序列号:由CA给予每一个证书分配的唯一的数字型编号,当证书被取消时,实际上是将此证书序列号放入由CA签发的CRL(Certificate Revocation List证书作废表,或证书黑名单表)中。这也是序列号唯一的原因。
4、主题信息:证书持有人唯一的标识符(或称DN-distinguished name)这个名字在 Internet上应该是唯一的。DN由许多部分组成,看起来象这样:
CN=Bob Allen, OU=Total Network Security Division
O=Network Associates, Inc.
C=US
这些信息指出该科目的通用名、组织单位、组织和国家或者证书持有人的姓名、服务处所等信息。
5、证书的有效期:证书起始日期和时间以及终止日期和时间;指明证书在这两个时间内有效。
6、认证机构:证书发布者,是签发该证书的实体唯一的CA的X.509名字。使用该证书意味着信任签发证书的实体。(注意:在某些情况下,比如根或顶级CA证书,发布者自己签发证书)
7、发布者的数字签名:这是使用发布者私钥生成的签名,以确保这个证书在发放之后没有被撰改过。
8、签名算法标识符:用来指定CA签署证书时所使用的签名算法。算法标识符用来指定CA签发证书时所使用的公开密钥算法和HASH算法。

证书主题属性

属性类型名称 含义 简写
Common Name 通用名称 CN
Organizational Unit name 机构单元名称 OU
Organization name 机构名 O
Locality 地理位置 L
State or province name 州/省名 S
Country 国名 C

此外还有一些有效期,颁发者,证书颁发对象,用途等
http://www.cnblogs.com/jiu0821/p/4598352.html

java操作代码实践

java对x509有自己的一套实现可以选择sun公司自己的实现类,但是有些复杂的操作sun自带的做不了,所以我们一般使用bouncycastle这个java开源加密包下载地址http://www.bouncycastle.org/latest_releases.html
虽然这里不介绍对称加密,但还是另提一句,jdk自带的aes加密只支持到128位,更高的256位的加密,需要到oracle官网下载jce包,替换java自带的加密包。一般对称和非对称加密都是混合使用的,这也是为了在安全性和效率上取得平衡,这也是业内目前普遍采用的方法。

具体代码

代码用到的jar包
这里写图片描述

x509接口


import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;

public interface X509Dao {
    

    /**
     * @param issuer 发布者  C=CN,ST=BJ,L=BJ,O=组织,OU=单位,CN=CCERT
     * @param notBefore 使用日期
     * @param notAfter 到期
     * @param certDestPath 生成证书地址
     * @param serial 证书序列号
     * @param alias 证书别名
     * @throws Exception
     */
    void createCert(String issuer, Date notBefore, Date notAfter, String certDestPath, BigInteger serial,
            String keyPassword, String alias) throws Exception;

    /** 输出证书信息
     * @param certPath 证书地址
     * @param keyPassword 证书密码
     */
    void printCert(String certPath, String keyPassword) throws Exception;

    /** 返回公钥
     * @param certPath 证书路径
     * @param keyPassword 证书密码
     * @return
     * @throws Exception
     */
    PublicKey getPublicKey(String certPath, String keyPassword) throws Exception;

    /** 返回私钥
     * @param certPath
     * @param keyPassword
     * @return
     * @throws Exception
     */
    PrivateKey getPrivateKey(String certPath, String keyPassword) throws Exception;

    /**
     * @param endTime 延期时间
     * @param certPath 证书地址
     * @param password 密码
     * @throws Exception 目前未实现,
     */
    void certDelayTo(Date endTime, String certPath, String password) throws Exception;

    /**修改密码
     * @param certPath 证书地址 密码
     * @param oldPwd 原始密码
     * @param newPwd 新密码
     * @throws Exception
     */
    void changePassword(String certPath, String oldPwd, String newPwd) throws Exception;

    /** 删除证书
     * @param certPath 证书地址
     * @param password 密码
     * @param alias 别名
     * @param entry 条目
     * @throws Exception
     */
    void deleteAlias(String certPath, String password, String alias, String entry) throws Exception;

}

x509 实现类



import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;


public class X509CertDaoImpl implements   X509Dao {
     

    public static final String Default_keyType="PKCS12";
    public static final String Default_KeyPairGenerator="RSA";
    public static final String Default_Signature="SHA1withRSA";
    public static final String cert_type="X509";
    public static final Integer Default_KeySize=2048;

    static {
        // 系统添加BC加密算法 以后系统中调用的算法都是BC的算法
        Security.addProvider(new BouncyCastleProvider());
    }

    @Override
    public void createCert(String issuer,Date notBefore,Date notAfter,String certDestPath,
            BigInteger serial,String keyPassword,String alias) throws Exception{
        //产生公私钥对
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(Default_KeyPairGenerator);
        kpg.initialize(Default_KeySize);
        KeyPair keyPair = kpg.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();  
        PrivateKey privateKey = keyPair.getPrivate();  
        // 组装证书
        X500Name issueDn = new X500Name(issuer);  
        X500Name subjectDn = new X500Name(issuer);  
        //组装公钥信息  
        SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo  
                 .getInstance(new ASN1InputStream(publicKey.getEncoded())  
                         .readObject());

        X509v3CertificateBuilder builder = new X509v3CertificateBuilder(  
                issueDn, serial, notBefore, notAfter, subjectDn,  
                subjectPublicKeyInfo); 
         //证书的签名数据  
        ContentSigner sigGen = new JcaContentSignerBuilder(Default_Signature).build(privateKey);  
        X509CertificateHolder holder = builder.build(sigGen); 
        byte[] certBuf = holder.getEncoded();  
        X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance(cert_type).generateCertificate(new ByteArrayInputStream(certBuf));  
        // 创建KeyStore,存储证书
        KeyStore store = KeyStore.getInstance(Default_keyType);
        store.load(null, null);
        store.setKeyEntry(alias, keyPair.getPrivate(),   
                 keyPassword.toCharArray(), new Certificate[] { certificate });
        FileOutputStream fout =new FileOutputStream(certDestPath);
        store.store(fout, keyPassword.toCharArray());       
        fout.close(); 
    }



    @Override
    public    void printCert(String certPath, String keyPassword) throws Exception{
                char[] charArray = keyPassword.toCharArray();
                KeyStore ks = KeyStore.getInstance(Default_keyType);
                FileInputStream fis = new FileInputStream(certPath);
                ks.load(fis, charArray);
                fis.close();
                System.out.println("keystore type=" + ks.getType());
                Enumeration enumas = ks.aliases();
                String keyAlias = null;
                if (enumas.hasMoreElements())
                {
                    keyAlias = (String)enumas.nextElement(); 
                    System.out.println("alias=[" + keyAlias + "]");
                }
                System.out.println("is key entry=" + ks.isKeyEntry(keyAlias));
                PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias,charArray );
                Certificate cert = ks.getCertificate(keyAlias);
                PublicKey pubkey = cert.getPublicKey();
                System.out.println("cert class = " + cert.getClass().getName());
                System.out.println("cert = " + cert);
                System.out.println("public key = " + pubkey);
                System.out.println("private key = " + prikey);
    }


    @Override
    public  PublicKey getPublicKey(String certPath, String keyPassword) throws Exception{
            char[] charArray = keyPassword.toCharArray();
            KeyStore ks = KeyStore.getInstance(Default_keyType);
            FileInputStream fis = new FileInputStream(certPath);
            ks.load(fis, charArray);
            fis.close();
            Enumeration enumas = ks.aliases();
            String keyAlias = null;
            if (enumas.hasMoreElements())
            {
                keyAlias = (String)enumas.nextElement();
                Certificate certificate = ks.getCertificate(keyAlias);

                return ks.getCertificate(keyAlias).getPublicKey();
            }
            return null;
}
    @Override
    public  PrivateKey getPrivateKey(String certPath, String keyPassword) throws Exception{
        char[] charArray = keyPassword.toCharArray();
        KeyStore ks = KeyStore.getInstance(Default_keyType);
        FileInputStream fis = new FileInputStream(certPath);
        ks.load(fis, charArray);
        fis.close();
        Enumeration enumas = ks.aliases();
        String keyAlias = null;
        if (enumas.hasMoreElements())
        {
            keyAlias = (String)enumas.nextElement();
            Certificate certificate = ks.getCertificate(keyAlias);

            return (PrivateKey) ks.getKey(keyAlias, charArray);
        }
        return null;
}


    @Override
    public void certDelayTo(Date endTime,String certPath,String password) throws Exception{

    }

    @Override
    public void changePassword(String certPath,String oldPwd,String newPwd) throws Exception{
        KeyStore ks = KeyStore.getInstance(Default_keyType);
        FileInputStream fis = new FileInputStream(certPath);
        ks.load(fis, oldPwd.toCharArray());
        fis.close();
        FileOutputStream output = new  FileOutputStream(certPath);
        ks.store(output,newPwd.toCharArray());
        output.close();
    }

    @Override
    public void deleteAlias(String certPath,String password,String alias,String entry) throws Exception{
        char[] charArray = password.toCharArray();
        KeyStore ks = KeyStore.getInstance(Default_keyType);
        FileInputStream fis = new FileInputStream(certPath);
        ks.load(fis, charArray);
        fis.close();
      if(ks.containsAlias(alias)){
            ks.deleteEntry(entry);
            FileOutputStream output = new  FileOutputStream(certPath );
            ks.store(output,password.toCharArray());
            output.close();
      }else{
          throw new Exception("该证书未包含别名--->"+alias);
      }
    }
    public static void main(String[] args) throws Exception {
        X509Dao impl=new X509CertDaoImpl();
        String issuer="C=CN,ST=BJ,L=BJ,O=testserver,OU=testserver,CN=testserver";
        String certDestPath="e://test.p12";
        BigInteger serial=BigInteger.valueOf(System.currentTimeMillis());
        String keyPassword="123";
        String alias="test";
        //impl.createCert(issuer, new Date(), new Date("2017/09/27"), certDestPath, serial, keyPassword, alias);
        //impl.changePassword(certDestPath, "123", "123");
        //impl.createCert(issuer, new Date(), new Date("2017/09/27"), certDestPath, serial, keyPassword, alias);
        //未实现
        impl.certDelayTo(new Date("2017/09/28"), certDestPath, keyPassword);
        //impl.printCert(certDestPath, keyPassword);
    }

}

目前证书延期这块,没有做到,p12 证书延期可以通过openssl 做,但是具体怎么做,我也没搞懂,以后有时间的话,具体看下openssl的文档,在公布给大家

这是java相关的证书操作,后续会介绍,java如何使用x509实现加密解密,签名验签等操作,以及这些技术的使用场景简介

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/do_bset_yourself/article/details/78159697

智能推荐

王斌老师的博客_王斌 github-程序员宅基地

文章浏览阅读480次。http://blog.sina.com.cn/s/blog_736d0b9101018cgc.html_王斌 github

ACM OJ Collection_htt//acm.wydtang.top/-程序员宅基地

文章浏览阅读737次。原文来自:http://blog.csdn.net/hncqp/article/details/4455263 ACM OJ Collection(排名不分先后):中国:浙江大学(ZJU):http://acm.zju.edu.cn/北京大学(PKU):htt_htt//acm.wydtang.top/

ios 自己服务器 苹果支付_修复苹果IOS支付-程序员宅基地

文章浏览阅读467次。更新记录1.0.0(2019-07-01)插件简介专门用来修复苹果IOS支付时出现"您已购买此App内购买项目。此项目将免费恢复"。问题描述首先在IOS平台里面创建“APP内购买项目”,选择的是“消耗型项目”,然后用uni-app官方的支付api进行支付,多支付几次,有时候就会出现提示“您已购买此App内购买项目。此项目将免费恢复”,特别是在沙盒测试里面支付很大几率出现,我明明选的是消耗型项目,应..._ios开发苹果支付恢复权益

spring MVC mock类单元测试(controller)_mvcmock-程序员宅基地

文章浏览阅读5.6k次。Spring从J2EE的Web端为每个关键接口提供了一个mock实现:MockHttpServletRequest几乎每个单元测试中都要使用这个类,它是J2EE Web应用程序最常用的接口HttpServletRequest的mock实现。MockHttpServletResponse此对象用于HttpServletRespons_mvcmock

【我的世界Minecraft-MC】常见及各种指令大杂烩【2022.8版】_summon生成掉落物-程序员宅基地

文章浏览阅读8.5k次,点赞7次,收藏22次。execute as @a at @s run clear @s minecraft:dark_oak_planks{display:{Name:“{“text”:“第三关[阴森古堡]”,“color”:“red”,“italic”:false}”,color:“16711680”},Enchantments:[{id:“protection”,lvl:1}],Unbreakable:1b} 1。Lore:[“{“text”:“免费”,“color”:“blue”,“italic”:false}”]..._summon生成掉落物

CentOS 7安装教程(图文详解)_centos 安装-程序员宅基地

文章浏览阅读10w+次,点赞487次,收藏2.1k次。CentOS 7安装教程: 准备: 软件:VMware Workstation 镜像文件:CentOS-7-x86_64-bin-DVD1.iso (附:教程较为详细,注释较多,故将操作的选项进行了加粗字体显示。) 1、文件--新建虚拟机--自定义 2、..._centos 安装

随便推点

Github项目分享——免费的画图工具drow,前端插件化面试_draw github画图-程序员宅基地

文章浏览阅读333次,点赞3次,收藏3次。项目介绍一款很好用的免费画图软件,支持ER图、时序图、流程图等等在项目的releases就可以下载最新版本同时支持在线编辑。_draw github画图

如何开始学习人工智能?入门的学习路径和资源是什么?_人工智能学习路径-程序员宅基地

文章浏览阅读930次。嗨,大家好!如果你对人工智能充满了好奇,并且想要入门这个领域,那么你来对地方了。本文将向你介绍如何从零基础开始学习人工智能,并逐步掌握核心概念和技能。无论你是大学生、职场新人还是对人工智能感兴趣的任何人,都可以按照以下学习路径逐步提升自己。_人工智能学习路径

Unity3D 导入资源_unity怎么导入压缩包-程序员宅基地

文章浏览阅读4.3k次,点赞2次,收藏8次。打开Unity3D的:window-asset store就会出来这样的界面:我们选择一个天空纹理,注意这里的标签只有一个,如果有多个就会显示所有标签的内容:找个比较小的免费的下载一下试试,比如这个:下载以后:点击import就会出现该窗口:然后再点击最底下的import:就导入到我们这里来了。从上面可以切换场景:..._unity怎么导入压缩包

jqgrid 服务器端验证,javascript – jqgrid服务器端错误消息/验证处理-程序员宅基地

文章浏览阅读254次。在你以前的问题的the answer的最后一部分,我试着给出你当前的问题的答案.也许我表示不够清楚.您不应该将错误信息放在标准成功响应中.您应该遵循用于服务器和客户端之间通信的HTTP协议的主要规则.根据HTTP协议实现网格中的加载数据,编辑行和与服务器的所有Ajax通信.每个HTTP响应都有响应第一行的状态代码.了解这个意义非常重要.典型的JSON数据成功请求如下HTTP/1.1 200 OK...._decode message error

白山头讲PV: 用calibre进行layout之间的比对-程序员宅基地

文章浏览阅读4k次,点赞8次,收藏29次。我们在流片之后,通常还是有机会对layout进行局部小的修改。例如metal change eco或者一些层次的局部修改。当我们修改之后,需要进行与之前gds的对比,以便确认没有因为某些..._calibre dbdiff

java exit方法_Java:如何测试调用System.exit()的方法?-程序员宅基地

文章浏览阅读694次。问题我有一些方法应该在某些输入上调用567779278。不幸的是,测试这些情况会导致JUnit终止!将方法调用放在新线程中似乎没有帮助,因为System.exit()终止了JVM,而不仅仅是当前线程。是否有任何常见的处理方式?例如,我可以将存根替换为System.exit()吗?[编辑]有问题的类实际上是一个命令行工具,我试图在JUnit中测试。也许JUnit根本不适合这份工作?建议使用互补回归测..._检查system.exit