美文网首页
Java下使用BouncyCastle制作证书(RSA/ECC/

Java下使用BouncyCastle制作证书(RSA/ECC/

作者: 音愈香 | 来源:发表于2019-01-30 23:48 被阅读0次

    简介

    首先简单介绍下什么是数字证书,所谓数字证书,就是互联网通讯中的“身份证”。通常的数字证书是由权威机构CA证书授权中心发行的,能提供在Internet上进行身份验证。数字证书的认证原理基于非对称加密算法。生成证书前首先需要生成一对非对称密钥,将颁发者身份信息、使用者身份信息、公钥、颁发者私钥对基本证书域的签名值以及一些算法标识符oid按照RFC2459所规定的形式组合成符合文档定义的ASN1结构,就完成证书的制作了。但实际的证书生成,标准的流程都是先生成证书请求,这个证书请求中包含自身的身份信息,证书所需公钥,私钥对证书请求信息域的签名值,扩展项信息和一些算法标识oid,证书请求的数据格式定义在RFC2986中,生成证书时通过解析证书请求来获取使用者身份信息和使用者公钥。BouncyCastle是一种用于 Java 平台的开放源码的轻量级密码包,它支持大量的密码算法,同时抽象包装了各种ASN1数据类型以及ASN1结构相关的解析和组装。使用BC包可以很方便的组装生成证书。我使用的JDK版本1.8,BC版本为1.59,BC对于SM2算法的集成于版本1.57,组装国密证书部分的代码需要至少BC1.57的支持,之前版本的sm2签名写法与1.59的略有差异。完整代码在我的Github,希望可以帮助到你。


    一. 生成自签发根证书

    为了方便,自签发根证书就不走证书请求了,直接使用传入的使用者身份信息(Subject)和生成的密钥对(Keypair)来制作证书。

     public static Certificate selfSignedCertGen(X500Name subject, KeyPair keyPair, Date notBefore, Date notAfter) throws Exception{
            SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
            BcX509ExtensionUtils extUtils = new BcX509ExtensionUtils();
            ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
            extensionsGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));    //ca cert
            extensionsGenerator.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign));
            extensionsGenerator.addExtension(Extension.subjectKeyIdentifier,false,extUtils.createSubjectKeyIdentifier(subjectPublicKeyInfo));
            extensionsGenerator.addExtension(Extension.authorityKeyIdentifier,false,extUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo));
            V3TBSCertificateGenerator   tbsGen = new V3TBSCertificateGenerator();
            tbsGen.setSerialNumber(new ASN1Integer(UUID.randomUUID().getMostSignificantBits()&Long.MAX_VALUE));
            tbsGen.setIssuer(subject);  //自签证书颁发者等于使用者
            tbsGen.setStartDate(new Time(notBefore, Locale.CHINA));
            tbsGen.setEndDate(new Time(notAfter,Locale.CHINA));
            tbsGen.setSubject(subject);
            tbsGen.setSubjectPublicKeyInfo(subjectPublicKeyInfo);
            tbsGen.setExtensions(extensionsGenerator.generate());
            tbsGen.setSignature(getSignAlgo(subjectPublicKeyInfo.getAlgorithm()));   //签名算法标识等于密钥算法标识
            TBSCertificate tbs = tbsGen.generateTBSCertificate();
            byte[] signature = null;
            if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("ECDSA")) {
                if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(GMObjectIdentifiers.sm2p256v1)) {
                    signature = Signers.SM2Sign(tbsCertificate.getEncoded(),issuerPrivateKey);
                } else if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(SECObjectIdentifiers.secp256k1)) {  //项目中ecdsa签名使用的曲线为secp256k1
                    signature = Signers.ECDSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
                } else
                    throw new IllegalArgumentException("不支持的曲线");
            } else if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("RSA")) {
                signature = Signers.RSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
            } else
                throw new IllegalArgumentException("不支持的密钥算法");
            ASN1EncodableVector v = new ASN1EncodableVector();
            v.add(tbsCertificate);
            v.add(getSignAlgo(issuerSubjectPublicKeyInfo.getAlgorithm())); //根据公钥算法标识返回对应签名算法标识
            v.add(new DERBitString(signature));
            return Certificate.getInstance(new DERSequence(v));
        }
    

    二. 生成证书请求

    传入使用者身份信息(Subject),使用者公钥,组装证书请求信息对象(CertificateRequestInfo),并使用传入的使用者私钥进行签名,最终生成P10格式的证书请求。

    public static PKCS10CertificationRequest generateCSR(X500Name subject, PublicKey publicKey, PrivateKey privateKey) {
            try {
                SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
                CertificationRequestInfo info = new CertificationRequestInfo(subject,subjectPublicKeyInfo,new DERSet());
                byte[] signature;
                AlgorithmIdentifier signAlgo = getSignAlgo(subjectPublicKeyInfo.getAlgorithm());
                if(signAlgo.getAlgorithm().equals(GMObjectIdentifiers.sm2sign_with_sm3)) {
                    signature = Signers.SM2Sign(info.getEncoded(ASN1Encoding.DER),privateKey);
                } else if(signAlgo.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA256)) {
                    signature = Signers.ECDSASign(info.getEncoded(ASN1Encoding.DER),privateKey);
                } else if(signAlgo.getAlgorithm().equals(PKCSObjectIdentifiers.sha256WithRSAEncryption)) {
                    signature = Signers.RSASign(info.getEncoded(ASN1Encoding.DER),privateKey);
                } else
                    throw new IllegalArgumentException("密钥算法不支持");
                return new PKCS10CertificationRequest(new CertificationRequest(info,signAlgo,new DERBitString(signature)));
            } catch (Exception e) {
                e.printStackTrace();
                throw new IllegalArgumentException("密钥结构错误");
            }
        }
    

    三. 签发终端实体证书

    终端实体证书有别于CA证书,它无法向下签发任何证书,V3的终端实体证书中使用扩展字段(BasicConstraints=false)来区分该证书是不是CA证书。制作终端实体证书需要颁发者证书(必须是CA证书),颁发者证书的私钥。

    public static Certificate certGen(PKCS10CertificationRequest csr, PrivateKey issuerPrivateKey, byte[] issuerCert, Date notBefore, Date notAfter) throws Exception {
            X509CertificateHolder issuer = new X509CertificateHolder(issuerCert);
            if(!verifyCSR(csr))
                throw new IllegalArgumentException("证书请求验证失败");
            X500Name subject = csr.getSubject();
            BcX509ExtensionUtils extUtils = new BcX509ExtensionUtils();
            ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
            extensionsGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));    //entity cert
            extensionsGenerator.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature));
            extensionsGenerator.addExtension(Extension.authorityKeyIdentifier,false,extUtils.createAuthorityKeyIdentifier(issuer)); //授权密钥标识
            extensionsGenerator.addExtension(Extension.subjectKeyIdentifier,false,extUtils.createSubjectKeyIdentifier(csr.getSubjectPublicKeyInfo())); //使用者密钥标识
            V3TBSCertificateGenerator tbsGen = new V3TBSCertificateGenerator();
            tbsGen.setSerialNumber(new ASN1Integer(UUID.randomUUID().getMostSignificantBits()&Long.MAX_VALUE));
            tbsGen.setIssuer(issuer.getSubject());
            tbsGen.setStartDate(new Time(notBefore, Locale.CHINA));
            tbsGen.setEndDate(new Time(notAfter,Locale.CHINA));
            tbsGen.setSubject(subject);
            tbsGen.setSubjectPublicKeyInfo(csr.getSubjectPublicKeyInfo());
            tbsGen.setExtensions(extensionsGenerator.generate());
            tbsGen.setSignature(issuer.getSubjectPublicKeyInfo().getAlgorithm());   //签名算法标识等于颁发者证书的密钥算法标识
            TBSCertificate tbs = tbsGen.generateTBSCertificate();
            byte[] signature = null;
            if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("ECDSA")) {
                if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(GMObjectIdentifiers.sm2p256v1)) {
                    signature = Signers.SM2Sign(tbsCertificate.getEncoded(),issuerPrivateKey);
                } else if(issuerSubjectPublicKeyInfo.getAlgorithm().getParameters().equals(SECObjectIdentifiers.secp256k1)) {
                    signature = Signers.ECDSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
                } else
                    throw new IllegalArgumentException("不支持的曲线");
            } else if(issuerPrivateKey.getAlgorithm().equalsIgnoreCase("RSA")) {
                signature = Signers.RSASign(tbsCertificate.getEncoded(),issuerPrivateKey);
            } else
                throw new IllegalArgumentException("不支持的密钥算法");
            ASN1EncodableVector v = new ASN1EncodableVector();
            v.add(tbsCertificate);
            v.add(getSignAlgo(issuerSubjectPublicKeyInfo.getAlgorithm()));
            v.add(new DERBitString(signature));
            return Certificate.getInstance(new DERSequence(v));
        }
    

    相关文章

      网友评论

          本文标题:Java下使用BouncyCastle制作证书(RSA/ECC/

          本文链接:https://www.haomeiwen.com/subject/aawzjqtx.html