ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

是时候该写下Springboot基于Keytool的SSL双向认证代码示了

2022-03-18 23:34:34  阅读:226  来源: 互联网

标签:keystore Keytool Springboot 证书 entity SSL alias final String


1.前言

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 [1] 。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。

JDK中keytool 常用命令: 

-genkey      在用户主目录中创建一个默认文件".keystore",还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书
(在没有指定生成位置的情况下,keystore会存在用户系统默认目录,如:对于window xp系统,会生成在系统的C:/Documents and Settings/UserName/文件名为“.keystore”)
-alias       产生别名
-keystore    指定密钥库的名称(产生的各类信息将不在.keystore文件中)
-keyalg      指定密钥的算法 (如 RSA  DSA(如果不指定默认采用DSA))
-validity    指定创建的证书有效期多少天
-keysize     指定密钥长度
-storepass   指定密钥库的密码(获取keystore信息所需的密码)
-keypass     指定别名条目的密码(私钥的密码)
-dname       指定证书拥有者信息 例如:  "CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名称,ST=州或省份名称,C=单位的两字母国家代码"
-list        显示密钥库中的证书信息      keytool -list -v -keystore 指定keystore -storepass 密码
-v           显示密钥库中的证书详细信息
-export      将别名指定的证书导出到文件  keytool -export -alias 需要导出的别名 -keystore 指定keystore -file 指定导出的证书位置及证书名称 -storepass 密码
-file        参数指定导出到文件的文件名
-delete      删除密钥库中某条目          keytool -delete -alias 指定需删除的别  -keystore 指定keystore  -storepass 密码
-printcert   查看导出的证书信息          keytool -printcert -file yushan.crt
-keypasswd   修改密钥库中指定条目口令    keytool -keypasswd -alias 需修改的别名 -keypass 旧密码 -new  新密码  -storepass keystore密码  -keystore sage
-storepasswd 修改keystore口令      keytool -storepasswd -keystore e:/yushan.keystore(需修改口令的keystore) -storepass 123456(原始密码) -new yushan(新密码)
-import      将已签名数字证书导入密钥库  keytool -import -alias 指定导入条目的别名 -keystore 指定keystore -file 需导入的证书

本文使用okhttp3访问SpringBoot创建的https接口。

2.SpringBoot配置文件

applicathon.properties

#端口
server.port=8443

#需要分别配置Key Store和Trust Store的文件、密码等信息,即使是同一个文件。
server.ssl.enabled=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:star_server.p12
server.ssl.key-store-password=xxxxxxx
server.ssl.key-alias=star_server
 
server.ssl.trust-store=classpath:star_server.p12
server.ssl.trust-store-password=xxxxxxx
server.ssl.trust-store-provider=SUN
server.ssl.trust-store-type=PKCS12

#server.ssl.client-auth有三个可配置的值:none、want和need。
#双向验证应该配置为need;
#none表示不验证客户端;
#want表示会验证,但不强制验证,即验证失败也可以成功建立连接
server.ssl.client-auth=need

3.代码逻辑

3.1 公共实体类&KeyTools工具类

KeyStoreCommand .java

public class KeyStoreCommand {

    private String alias;//产生别名
    private int keysize;//指定密钥长度
    private String keyalg; //指定密钥的算法 (如 RSA DSA(如果不指定默认采用DSA))
    private String sigalg;// 签名算法名称
    private String destalias; //目标别名
    private String startdate;//证书有效期开始日期/时间
    private String commonname;//CN=名字与姓氏
    private String organizationalUnit;//OU=组织单位名称
    private String organization;//O=组织名称
    private String city;//L=城市或区域名称
    private String state;//ST=州或省份名称
    private String country;//C=单位的两字母国家代码
    private long validity; //指定创建的证书有效期多少天
    private String keystore;// 指定密钥库的名称
    private String storepass;// 指定密钥库的密码(获取keystore信息所需的密码)
    private String keypass;//指定别名条目的密码(私钥的密码)
    private String storetype;//密钥库类型
    private String filepath;// 参数指定导出到文件的证书文件名

Keytools.java类

//1.使用java代码生成密钥库
    public static KeyStore createKeyStoreFile(KeyStoreCommand entity,String serverAlias,Certificate serverCert) throws Exception {
        final String alias = entity.getAlias();//"home2";
        String keystore = entity.getKeystore();//"d:/keys/home2.p12";
        final int keySize = entity.getKeysize(); //1024;
        final String keyalg=entity.getKeyalg();//RSA
        final String sigalg=entity.getSigalg();//SHA256withRSA
        final String commonName = entity.getCommonname();//"db";
        final String organizationalUnit = entity.getOrganizationalUnit();//"com.home";
        final String organization = entity.getOrganization();//"easywith";
        final String city = entity.getCity();//"guiyang";
        final String state = entity.getState();//"guizhou"
        final String country = entity.getCountry();//"cn"
        final long validity = entity.getValidity();//3650
        final String keyPassword = entity.getKeypass();//"123456";
        final String storetype = entity.getStoretype();//PKCS12
        // keytool工具
        CertAndKeyGen keyGen = new CertAndKeyGen(keyalg, sigalg);

        // 通用信息
        X500Name x500Name = new X500Name(commonName, organizationalUnit, organization, city, state, country);
        //根据密钥长度生成公钥和私钥
        keyGen.generate(keySize);
        PrivateKey privateKey = keyGen.getPrivateKey();
        // 证书
        X509Certificate certificate = keyGen.getSelfCertificate(x500Name, new Date(), (long) validity * 24 * 60 * 60);
        KeyStore keyStore = KeyStore.getInstance(storetype);
        keyStore.load(null,null);
        keyStore.setKeyEntry(alias,privateKey,keyPassword.toCharArray(),new Certificate[]{certificate});

        System.out.println("Assigns the given trusted certificate to the given alias");
        if(StringUtils.isNotEmpty(serverAlias)){
            keyStore.setCertificateEntry(serverAlias,serverCert);
        }
        FileOutputStream outputStream = new FileOutputStream(keystore);
        keyStore.store(outputStream,keyPassword.toCharArray());
        outputStream.close();
        System.out.println("keyStore file created ...");
        return keyStore;
    }

3.2 构造实体对象

3.2.1 构造KeyStoreCommand实例对象

            HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
            //拼音小写
            format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
            //不带声调
            format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
            //要转换中文格式
            String clientAlias = PinyinHelper.toHanYuPinyinString(tenant.getFullName(), format, "", true);
            //每次更新秘钥及证书文件版本递增(alias_0,alias_1....)
            clientAlias = clientAlias+"_"+tenant.getVersion();

            Long validity = ((tenant.getExpaireTime().getTime() - tenant.getCreateTime().getTime()) / 86400000L);
            log.info("受信任证书有效天数:{}(单位:天)",validity);
            String  CN = (tenant.getShortName()),
                    OU = (tenant.getFullName()),
                    O = (tenant.getShortName()),
                    L = (PinyinHelper.toHanYuPinyinString(tenant.getCity(), format, "", true)),
                    ST = (PinyinHelper.toHanYuPinyinString(tenant.getProvince(), format, "", true)),
                    C = ("CN");
            log.info("CN=(名字与姓氏):{}, OU=(组织单位名称):{}, O=(组织名称):{}," +
                    " L=(城市或区域名称):{}, ST=(州或省份名称):{}, C=(单位的两字母国家代码):{}",
                    CN,OU,O,L,ST,C);
            String keyStore = rootPath + clientAlias+".p12";
            String cerPath = rootPath + clientAlias+".cer"; 

            log.info("客户端秘钥库:{},受信任证书库:{}",keyStore,cerPath);

3.2.2 重点:核心操作(证书交换)双方受信任

总体步骤:

 1. 创建服务端keystore秘钥库
 2. 从服务端keystore秘钥库导出服务端证书
 3. 创建客户端keystore秘钥库
 4. 从客户端keystore秘钥库导出客户端证书
 5. 将服务端证书导入客户端keystore中
 6. 将客户端证书导入服务端keystore中

首先提前创建好服务端keystore并导出服务端证书(两种方式)
1.通过keytool命令行方式来创建

1.生成服务端keystore
keytool -genkeypair -alias server -keyalg RSA -sigalg SHA256withRSA -dname CN="xxxxx公司",OU="易xx" ,O="大数据组" ,L=Guiyang,ST=Guizhou,C=CN -validity 3650 -keypass 123456-storepass xxxxxx -storetype PKCS12 -keystore D:/keys/starpulse_server.p12
2.导出服务端证书
keytool -export -alias server -file D:/keys/starpulse_server.cer -keystore D:/keys/starpulse_server.p12 -storetype PKCS12 -storepass 123456

2.根据java代码来创建

  //1.使用java代码生成密钥库
    public static KeyStore createKeyStoreFile() throws Exception {
        //构造KeyStoreCommand实体对象
        final String alias = entity.getAlias();//"home2";
        String keystore = entity.getKeystore();//"d:/keys/home2.p12";
        final int keySize = entity.getKeysize(); //1024;
        final String keyalg=entity.getKeyalg();//RSA
        final String sigalg=entity.getSigalg();//SHA256withRSA
        final String commonName = entity.getCommonname();
        final String organizationalUnit = entity.getOrganizationalUnit();
        final String organization = entity.getOrganization();
        final String city = entity.getCity();
        final String state = entity.getState();//
        final String country = entity.getCountry();
        final long validity = entity.getValidity();
        final String keyPassword = entity.getKeypass();
        final String storetype = entity.getStoretype();//PKCS12
        
        // keytool工具
        CertAndKeyGen keyGen = new CertAndKeyGen(keyalg, sigalg);

        // 通用信息
        X500Name x500Name = new X500Name(commonName, organizationalUnit, organization, city, state, country);
        //根据密钥长度生成公钥和私钥
        keyGen.generate(keySize);
        PrivateKey privateKey = keyGen.getPrivateKey();
        // 证书
        X509Certificate certificate = keyGen.getSelfCertificate(x500Name, new Date(), (long) validity * 24 * 60 * 60);
        KeyStore keyStore = KeyStore.getInstance(storetype);
        keyStore.load(null,null);
        keyStore.setKeyEntry(alias,privateKey,keyPassword.toCharArray(),new Certificate[]{certificate});
        FileOutputStream outputStream = new FileOutputStream(keystore);
        keyStore.store(outputStream,keyPassword.toCharArray());
        outputStream.close();
        System.out.println("keyStore file created ...");
    }

 //导出证书 base64格式
    public static void exportCert(KeyStore keystore, String alias, String exportFile) throws Exception {
        Certificate cert = keystore.getCertificate(alias);
        BASE64Encoder encoder = new BASE64Encoder();
        String encoded = encoder.encode(cert.getEncoded());
        FileWriter fw = new FileWriter(exportFile);
        fw.write("-----BEGIN CERTIFICATE-----\r\n");    //非必须
        fw.write(encoded);
        fw.write("\r\n-----END CERTIFICATE-----");  //非必须
        fw.close();
    }

核心操作(证书交换)双方受信任

 //第一步:加载服务端秘钥库
            KeyStore serverKeystore = KeyStore.getInstance("PKCS12");
            serverKeystore.load(new FileInputStream(new File(serverStore)), password.toCharArray());
            Certificate serverCert = serverKeystore.getCertificate(serverAlias);

            //第二步:创建客户端秘钥库(详见keytools工具类)
            KeyStore clientKeystore = KeyTools.createKeyStoreFile(entity,serverAlias,serverCert);
            KeyTools.exportCert(clientKeystore, entity.getAlias(),entity.getFilepath());
            log.info("客户信任证书:{}制发完成",entity.getFilepath());

            Certificate clientCert = clientKeystore.getCertificate(entity.getAlias());
            log.info("根据alias导出证书客户指纹信任证书:{}",entity.getAlias());

            //第三步:导入客户端证书到服务端受信库(让服务端信任客户端)
            serverKeystore.setCertificateEntry(entity.getAlias(),clientCert);
            //第四步:将服务端秘钥保存到文件
            FileOutputStream outputStream = new FileOutputStream(serverStore);
            serverKeystore.store(outputStream,password.toCharArray());
            log.info("客户:{}信任证书,alias:{}制发完成",entity.getCommonname(),entity.getAlias());

运行秘钥及证书结果如下
在这里插入图片描述
导出证书生成功能完成

4.示例代码使用okhttp3访问https接口

使用okhttp3访问SpringBoot创建的https接口
明天写吧,今天太累了。。。。。。。。。。。。。。。

标签:keystore,Keytool,Springboot,证书,entity,SSL,alias,final,String
来源: https://blog.csdn.net/u012637358/article/details/123586002

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有