OpenSSL 的基本使用与提取证书公钥私钥
由于之前生产环境已经使用了 Identityserver4 用来做授权与认证的服务,而新项目采用 Spring Cloud 微服务体系,一方面 Spring Cloud 官方暂时只支持 OAuth2.0 协议,还不支持 OpenID Connect 协议(由于考虑到前项目后端分离登陆安全相关的功能已经做好了,不考虑再次修改 Spring Security 二次开发与其他开源框架如:Keycloak);另外默认 Identityserver4 也支持 JwtToken ,现在的思路是登陆使用 Identityserver4 的 OpenID Connect 协议认证,授权是在 Zuul 网关中获得 Identityserver4 服务端的公钥从而进行验签,所以就有了这篇文章。
创建证书
#生成私钥文件 openssl genrsa -out idsrv4.key 2048 #创建证书签名请求文件 CSR(Certificate Signing Request),用于提交给证书颁发机构(即 Certification Authority (CA))即对证书签名,申请一个数字证书。 openssl req -new -key idsrv4.key -out idsrv4.csr #生成自签名证书(证书颁发机构(CA)签名后的证书,因为自己做测试那么证书的申请机构和颁发机构都是自己,crt 证书包含持有人的信息,持有人的公钥,以及签署者的签名等信息。当用户安装了证书之后,便意味着信任了这份证书,同时拥有了其中的公钥。) openssl x509 -req -days 365 -in idsrv4.csr -signkey idsrv4.key -out idsrv4.crt #自签名证书与私匙合并成一个文件 openssl pkcs12 -export -in idsrv4.crt -inkey idsrv4.key -out idsrv4.pfx 或 openssl req -newkey rsa:2048 -nodes -keyout idsrv4.key -x509 -days 365 -out idsrv4.cer openssl pkcs12 -export -in idsrv4.cer -inkey idsrv4.key -out idsrv4.pfx
OpenSSL 提取 pfx 证书公钥与私钥
从pfx证书中提取密钥信息,并转换为key格式(pfx使用pkcs12模式补足) 提取密钥对(如果pfx证书已加密,会提示输入密码) openssl pkcs12 -in idsrv4.pfx -nocerts -nodes -out idsrv4.key 从密钥对提取公钥 openssl rsa -in idsrv4.key -pubout -out idsrv4_pub.key 从密钥对提取私钥 openssl rsa -in idsrv4.key -out idsrv4_pri.key 因为RSA算法使用的是 pkcs8 模式补足,需要对提取的私钥进一步处理得到最终私钥 openssl pkcs8 -topk8 -inform PEM -in idsrv4_pri.key -outform PEM -nocrypt
代码方式获取
public class PFXUtil { /** * 获取RSA算法的keyFactory * * @return */ private static KeyFactory getKeyFactory() throws Exception { return getKeyFactory("RSA"); } /** * 获取指定算法的keyFactory * * @param algorithm * @return */ private static KeyFactory getKeyFactory(String algorithm) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(algorithm); return keyFactory; } /** * 根据pfx证书获取keyStore * * @param pfxData * @param password * @return * @throws Exception */ private static KeyStore getKeyStore(byte[] pfxData, String password) throws Exception { KeyStore keystore = KeyStore.getInstance("PKCS12"); keystore.load(new ByteArrayInputStream(pfxData), password.toCharArray()); return keystore; } /** * 根据pfx证书得到私钥 * * @param pfxData * @param password * @throws Exception */ public static PrivateKey getPrivateKeyByPfx(byte[] pfxData, String password) throws Exception { PrivateKey privateKey = null; KeyStore keystore = getKeyStore(pfxData, password); Enumeration<String> enums = keystore.aliases(); String keyAlias = ""; while (enums.hasMoreElements()) { keyAlias = enums.nextElement(); if (keystore.isKeyEntry(keyAlias)) { privateKey = (PrivateKey) keystore.getKey(keyAlias, password.toCharArray()); } } return privateKey; } /** * 根据pfx证书得到私钥 * * @param pfxPath * @param password * @return * @throws Exception */ public static PrivateKey getPrivateKeyByPfx(String pfxPath, String password) throws Exception { File pfxFile = new File(pfxPath); return getPrivateKeyByPfx(FileUtils.readFileToByteArray(pfxFile), password); } /** * 根据私钥字节数组获取私钥对象 * * @param privateKeyByte * @return * @throws Exception */ public static PrivateKey getPrivateKey(byte[] privateKeyByte) throws Exception { PrivateKey privateKey = null; PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyByte); KeyFactory keyFactory = getKeyFactory(); privateKey = keyFactory.generatePrivate(keySpec); return privateKey; } /** * 根据私钥Base64字符串获取私钥对象 * * @param privateKeyStr * @return * @throws Exception */ public static PrivateKey getPrivateKey(String privateKeyStr) throws Exception { byte[] privateKeyByte = Base64.decodeBase64(privateKeyStr); return getPrivateKey(privateKeyByte); } /** * 根据公钥字节数组获取公钥 * * @param publicKeyByte 公钥字节数组 * @return * @throws Exception */ public static PublicKey getPublicKey(byte[] publicKeyByte) throws Exception { PublicKey publicKey = null; X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByte); KeyFactory keyFactory = getKeyFactory(); publicKey = keyFactory.generatePublic(keySpec); return publicKey; } /** * 根据公钥base64字符串获取公钥 * * @param publicKeyStr Base64编码后的公钥字节数组 * @return * @throws Exception */ public static PublicKey getPublicKey(String publicKeyStr) throws Exception { byte[] publicKeyByte = Base64.decodeBase64(publicKeyStr); return getPublicKey(publicKeyByte); } /** * 根据pfx证书获取证书对象 * * @param pfxData pfx的字节数组 * @param password pfx证书密码 * @return * @throws Exception */ public static X509Certificate getX509Certificate(byte[] pfxData, String password) throws Exception { X509Certificate x509Certificate = null; KeyStore keystore = getKeyStore(pfxData, password); Enumeration<String> enums = keystore.aliases(); String keyAlias = ""; while (enums.hasMoreElements()) { keyAlias = enums.nextElement(); if (keystore.isKeyEntry(keyAlias)) { x509Certificate = (X509Certificate) keystore.getCertificate(keyAlias); } } return x509Certificate; } /** * 根据pfx证书获取证书对象 * * @param pfxPath pfx证书路径 * @param password pfx证书密码 * @return * @throws Exception */ public static X509Certificate getX509Certificate(String pfxPath, String password) throws Exception { File pfxFile = new File(pfxPath); return getX509Certificate(FileUtils.readFileToByteArray(pfxFile), password); } //生成pkcs12 /** * 根据私钥、公钥证书、密码生成pkcs12 * * @param privateKey 私钥 * @param x509Certificate 公钥证书 * @param password 需要设置的密钥 * @return * @throws Exception */ public static byte[] generatorPkcx12(PrivateKey privateKey, X509Certificate x509Certificate, String password) throws Exception { Certificate[] chain = {x509Certificate}; KeyStore keystore = KeyStore.getInstance("PKCS12"); keystore.load(null, password.toCharArray()); keystore.setKeyEntry(x509Certificate.getSerialNumber().toString(), privateKey, password.toCharArray(), chain); ByteArrayOutputStream bytesos = new ByteArrayOutputStream(); keystore.store(bytesos, password.toCharArray()); byte[] bytes = bytesos.toByteArray(); return bytes; } //合成pfx /** * 根据私钥、公钥证书、密钥,保存为pfx文件 * * @param privateKey 私钥 * @param x509Certificate 公钥证书 * @param password 打开pfx的密钥 * @param saveFile 保存的文件 * @return * @throws Exception */ public static String generatorPFX(PrivateKey privateKey, X509Certificate x509Certificate, String password, File saveFile) throws Exception { //判断文件是否存在 if (!saveFile.exists()) { //判断文件的目录是否存在 if (!saveFile.getParentFile().exists()) { saveFile.getParentFile().mkdirs(); } saveFile.createNewFile(); } byte[] pkcs12Byte = generatorPkcx12(privateKey, x509Certificate, password); FileUtils.writeByteArrayToFile(saveFile, pkcs12Byte); return saveFile.getPath(); } } public class TestRsa { @Test public void contextLoads() { String pfxPath ="D:\\github\\SecuringForWebAPI\\IdSrv4.HostSrv\\Certs\\idsrv4.pfx"; String password = "123456"; try { //私钥:pfx文件中获取私钥对象 PrivateKey privateKey = getPrivateKeyByPfx(pfxPath, password); byte[] privateKeyByte = privateKey.getEncoded(); String privateKeyStr = Base64.encodeBase64String(privateKeyByte); System.out.println("私钥Base64字符串:" + privateKeyStr); //=====私钥Base64字符串转私钥对象 PrivateKey privateKey2 = getPrivateKey(privateKeyStr); System.out.println("私钥Base64字符串2:" + Base64.encodeBase64String(privateKey2.getEncoded())); //证书:从pfx文件中获取证书对象 X509Certificate certificate = getX509Certificate(pfxPath, password); System.out.println("证书主题:" + certificate.getSubjectDN().getName()); String publicKeyStr = Base64.encodeBase64String(certificate.getPublicKey().getEncoded()); System.out.println("公钥Base64字符串:" + publicKeyStr); //=====根据公钥Base64字符串获取公钥对象 System.out.println("公钥Base64字符串2:" + Base64.encodeBase64String(getPublicKey(publicKeyStr).getEncoded())); // //PFX:合成pfx(需要私钥、公钥证书) // String savePath = generatorPFX(privateKey, certificate, "1", new File // ("C:\\Users\\irving\\Desktop\\idrv4.pfx")); // System.out.println(savePath); } catch (Exception e) { e.printStackTrace(); } } }
REFER:
OpenSSL使用文档
https://github.com/KaiZhang890/openssl-howto