X.509 V3证书的签发与验证

工作原因接触X.509 V3证书的开发工作,对于X.509 V3证书最好的工具仍然是openssl,但是特殊场景下,openssl可能不是最好的选择,比如你的私钥被要求不能存在于内存中,这个时候可以考虑BouncyCastle,这个密码学库的标准兼容性也十分完美,同时一般的HSM硬件会支持JCE,而BouncyCastle也是建立在JCE基础上的。下文主要记录,使用BouncyCastle产生标准的X.509 V3证书的过程。

贴代码之前,总结一下需要注意的地方:

1)openssl在验证证书链时,会检查extension的密钥用途,因此证书需要KeyUsage.keyCertSign能力;

2)openssl在验证证书链时,会检查AuthorityKeyIdentifier和SubjectKeyIdentifier,即上级和当前证书的标识符,这组extension也不能省;

3)最后openssl会验证CA证书是否有BasicConstraints的CA标志。

对于V3来说,这些extension并非可有可无的“补充信息”,而且切实工作的校验环节。

参考代码如下:

    private static X509Certificate createCertificate(String dn, String issuer, BigInteger serialnumber,

            Date notBefore, Date notAfter, PublicKey capublicKey,

            PublicKey publicKey, PrivateKey privateKey, boolean isCA) throws Exception {

        X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();

        // certGenerator.setSerialNumber(BigInteger.valueOf(Math.abs(new

        // Random().nextLong())));

        certGenerator.setSerialNumber(serialnumber);

        certGenerator.setSubjectDN(new X509Name(dn));

        certGenerator.setIssuerDN(new X509Name(issuer)); // Set issuer!

        certGenerator.setNotBefore(notBefore);

        certGenerator.setNotAfter(notAfter);

        certGenerator.setPublicKey(publicKey);

        certGenerator.setSignatureAlgorithm("sha256WithRSA");

        BasicConstraints basicConstraints = new BasicConstraints(isCA); //

        certGenerator.addExtension(X509Extensions.BasicConstraints, true, basicConstraints); // Basic Constraints is

        certGenerator.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(

                KeyUsage.digitalSignature | KeyUsage.keyEncipherment |

                        KeyUsage.keyCertSign));

        certGenerator.addExtension(X509Extensions.AuthorityKeyIdentifier, false,

                new AuthorityKeyIdentifierStructure(capublicKey));

        certGenerator.addExtension(X509Extensions.SubjectKeyIdentifier, false,

                new SubjectKeyIdentifierStructure(publicKey));

        X509Certificate certificate = (X509Certificate) certGenerator.generate(

                privateKey, "LunaProvider");

        return certificate;

    }

一些小坑,

openssl.exe verify -verbose -partial_chain -CAfile C:\ssl\interCA.pem C:\ssl\sign.pem

error 20 at 0 depth lookup: unable to get local issuer certificate

这个错误是说,它觉得interCA不是0层CA,事实上它是一个1(中间层)层CA。

加上一个partial_chain即可验证通过,如下

openssl.exe verify -verbose -partial_chain -CAfile C:\ssl\interCA.pem C:\ssl\sign.pem

C:\ssl\sign.pem: OK

否则,也可以补全证书链,一起验证,如下

C:\ssl>"C:\cygwin\usr\local\ssl\bin\openssl.exe" verify -verbose -CAfile C:\ssl\rootCA.pem -untrusted C:\ssl\interCA.pem C:\ssl\sign.pem

C:\ssl\sign.pem: OK

注意这里untrusted并不是说不可信的意思,而是说需要验证后才可信的意思(即有条件信任),而rootCA是无条件信任的,注意CA证书的extension的CA标记位。

以下是把0层与1层CA附加在一起,这个openssl也是支持的。

C:\ssl>"C:\cygwin\usr\local\ssl\bin\openssl.exe" verify -verbose -CAfile C:\ssl\interCA_rootCA.pem C:\ssl\sign.pem

C:\ssl\sign.pem: OK

interCA_rootCA.pem是interCA在前,rootCA在后的简单粘贴。

有的时候可能会遇到,其他“稀奇古怪”的错误,比如

error 2 at 1 depth lookup: unable to get issuer certificate

这些错误一般都是openssl认为extension信息缺失或者没有匹配,特别注意AuthorityKeyIdentifier(签发者)和SubjectKeyIdentifier(被签发者),它们一般由相对应的公钥散列值比较好。

最终的证书用openssl X509 -text可以查看,注意红字部分是必要的检查点,如下:

Issuer: CN = root

Subject: CN = Inter

X509v3 extensions:

            X509v3 Basic Constraints: critical

                CA:TRUE

            X509v3 Key Usage: critical

                Digital Signature, Key Encipherment, Certificate Sign

            X509v3 Authority Key Identifier:

                keyid:63:10:31:B9:5F:A4:D1:B9:43:C0:FE:C1:BB:AF:A4:5F:A4:2A:4A:F8

            X509v3 Subject Key Identifier:

                63:10:31:B9:5F:A4:D1:B9:43:C0:FE:C1:BB:AF:A4:5F:A4:2A:4A:F8

你可能感兴趣的:(Java,密码,X509,证书,BouncyCastle)