基于密码机、BC生成国密(SM2)证书

密码机:硬件加密模块、HSM,支持国密的SM3WITHSM2算法
BC:BouncyCastle,开源第三方安全组件,支持SM3摘要,尚不支持sm2
OIDS:
SM3withSM2 OID 为1.2.156.10197.1.501。
SM2的公钥参数OID为1.2.156.10197.1.301
<QQ:22066821>

正常的SHA1withRSA证书是这样的:
	X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(new X500Name(issuer),
			serial, notBefore,notAfter, new X500Name(subject), publicKey);

	// "SHA1withRSA"
	ContentSigner sigGen = new JcaContentSignerBuilder(alg).setProvider("BC").build(privKey);
	X509CertificateHolder holder = builder.build(sigGen);
	CertificateFactory cf = CertificateFactory.getInstance("X.509");
	InputStream is1 = new ByteArrayInputStream(holder.toASN1Structure().getEncoded());
	X509Certificate theCert = (X509Certificate) cf.generateCertificate(is1);
	is1.close();


重点是new JcaContentSignerBuilder(alg),把SHA1withRSA更换成SM3withSM2,查看区别,
打开JcaContentSignerBuilder:
    public JcaContentSignerBuilder(String signatureAlgorithm)
    {
        this.signatureAlgorithm = signatureAlgorithm;
        this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
    }

再打开DefaultSignatureAlgorithmIdentifierFinder,会发现
        algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
        algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
        algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);

再看PKCSObjectIdentifiers
  
 static final ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
    /** PKCS#1: 1.2.840.113549.1.1.1 */
    static final ASN1ObjectIdentifier    rsaEncryption             = pkcs_1.branch("1");
    /** PKCS#1: 1.2.840.113549.1.1.2 */
    static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
    /** PKCS#1: 1.2.840.113549.1.1.3 */
    static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
    /** PKCS#1: 1.2.840.113549.1.1.4 */
    static final ASN1ObjectIdentifier    md5WithRSAEncryption      = pkcs_1.branch("4");
    /** PKCS#1: 1.2.840.113549.1.1.5 */
    static final ASN1ObjectIdentifier    sha1WithRSAEncryption     = pkcs_1.branch("5");

于是乎,我们似乎明白了,用OID可以构造SM3withSM2的ASN1ObjectIdentifier,只需改动下
DefaultSignatureAlgorithmIdentifierFinder就可以实现。

考虑到BC的jar包是经过sun签名的,如果全部重新编译,会有一系列的问题,至少我还不知道怎么去找sun签名(有人能告知吗?)
采取第二方案,扩展JcaContentSignerBuilder,做的过程中发现JcaContentSignerBuilder中的OperatorHelper无法在包外引用,
于是在org.bouncycastle.operator.jcajce包中扩展,又发现这样做过不了sun的签名检查,怒了......彻底修改包名,
把OperatorHelper也重写,于是乎就有了JcaContentSignerBuilderXA,OperatorHelperXA。

现在,BC签名工具认识SM3withSM2了,具体的实现就靠加密机了,在自己的provider中加入
	put("Signature.SM3withSM2", "com.xahtss.jceprovider.sign.SM3withSM2");
	put("Signature.1.2.156.10197.1.501", "com.xahtss.jceprovider.sign.SM3withSM2");

在实现类中完成签名操作就可以了。
<生成的证书尚未经过检验>

猜你喜欢

转载自linuxgao.iteye.com/blog/2207557