如何生成合法X.509证书以获取公钥?Java模块错误解决
如何生成有效X.509证书以获取公钥?
现有从证书字符串提取公钥的代码
private PublicKey getKey(String certificateValue) { try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); ByteArrayInputStream bis = new ByteArrayInputStream(certificateValue.getBytes(StandardCharsets.UTF_8)); Certificate certificate = null; while (bis.available() > 0) { certificate = cf.generateCertificate(bis); } return certificate.getPublicKey(); }
遇到的编译错误
尝试使用sun.security.x509包生成X.509证书时,触发以下编译错误:
import sun.security.x509.*; ^ (package sun.security.x509 is declared in module java.base, which does not export it to the unnamed module)
原因是sun.security.x509属于Java内部私有API,Java 9及以后的模块化系统禁止未命名模块直接访问这类内部包,且该API不具备跨版本兼容性,绝对不建议使用。
正确生成X.509证书的方案
方案1:使用BouncyCastle(兼容Java 8+)
BouncyCastle是广泛使用的开源安全库,提供了稳定的X.509证书生成能力:
- 添加Maven依赖:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency>
- 生成自签名X.509证书代码:
import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.Date; public X509Certificate generateSelfSignedCertificate() throws Exception { // 生成2048位RSA密钥对 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 设置证书有效期为1年 long validityMillis = 365 * 24 * 60 * 60 * 1000L; Date startDate = new Date(); Date endDate = new Date(startDate.getTime() + validityMillis); // 定义证书颁发者/使用者信息 X500Name subject = new X500Name("CN=SelfSignedCert, OU=Dev, O=Example, L=Beijing, ST=Beijing, C=CN"); // 构建证书 JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder( subject, BigInteger.valueOf(System.currentTimeMillis()), startDate, endDate, subject, keyPair.getPublic() ); // 用私钥签名证书 JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder("SHA256withRSA"); return new JcaX509CertificateConverter().getCertificate(certBuilder.build(signerBuilder.build(keyPair.getPrivate()))); }
方案2:使用Java 11+标准API(无需第三方库)
Java 11及以上内置了标准证书生成API,无需额外依赖:
import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom; import java.security.cert.CertificateBuilder; import java.security.cert.X509Certificate; import java.util.Date; public X509Certificate generateSelfSignedCert() throws Exception { // 生成RSA密钥对 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(2048); KeyPair kp = kpg.generateKeyPair(); // 设置证书有效期 Date start = new Date(); Date end = new Date(start.getTime() + 365L * 24 * 60 * 60 * 1000); // 构建并生成自签名证书 CertificateBuilder builder = CertificateBuilder.getInstance("X.509"); builder.setIssuer("CN=SelfSigned, O=Example") .setSubject("CN=SelfSigned, O=Example") .setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())) .setNotBefore(start) .setNotAfter(end) .setPublicKey(kp.getPublic()) .sign(kp.getPrivate(), "SHA256withRSA"); return (X509Certificate) builder.build(); }
将证书转换为字符串供getKey方法使用
生成证书后,将其转换为PEM格式字符串,即可直接传入你的getKey方法:
import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.security.cert.CertificateEncodingException; import java.util.Base64; public String certToPemString(X509Certificate cert) throws CertificateEncodingException { byte[] certBytes = cert.getEncoded(); String base64Cert = Base64.getEncoder().encodeToString(certBytes); return "-----BEGIN CERTIFICATE-----\n" + base64Cert + "\n-----END CERTIFICATE-----"; }
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

