基于密码机、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


正常的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.xa.jceprovider.sign.SM3withSM2");
put("Signature.1.2.156.10197.1.501", "com.xa.jceprovider.sign.SM3withSM2");

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

你可能感兴趣的:(一口言)