• MQTT研究之EMQ:【CoAP协议的ECC证书研究】


    今天研究的内容,是CoAP这个协议在EMQ消息队列的支持,CoAP是一个受限资源的协议,基于UDP实现的多用于物联网环境的通信协议。相关介绍不多说,可以看RFC。

    CoAP协议下,基于DTLS通信,同样因为协议的产生背景原因,所以,对秘钥大小有有一些要求,尽量的小,所以ECC(椭圆曲线)秘钥算法成为了首先,比RSA秘钥短很多,但是加密安全强度不比RSA对应较长的秘钥安全性低。所以,EC加密算法研究成为了本博文的重点,另外,CoAP的证书中签名算法,也是有所限制的,用的是ECDSA,因为签名算法和秘钥加密算法是对应着工作的。

    相关验证逻辑,可以基于CoAP的开发工具Californium的java三件套(core,connector,scandium),可以用证书进行验证。

    《一》. 下面看看基于OpenSSL工具创建EC证书的过程

    [root@tkwh-kfcs-app2 coaps]# openssl ecparam -out coapCA.key -name secp521r1 -genkey
    [root@tkwh-kfcs-app2 coaps]# openssl req -new -key coapCA.key -out coapCA.csr
    [root@tkwh-kfcs-app2 coaps]# openssl x509 -req -days 365 -in coapCA.csr -signkey coapCA.key -out coapCA.crt
    
    [root@tkwh-kfcs-app2 coaps]# openssl ecparam -out coapApp.key -name secp521r1 -genkey
    [root@tkwh-kfcs-app2 coaps]# openssl req -new -key coapApp.key -out coapApp.csr
    [root@tkwh-kfcs-app2 coaps]# openssl x509 -req -days 365 -in coapApp.csr -signkey coapApp.key -out coapApp.crt

     从这个指令过程看,证书创建的步骤,EC算法和RSA算法没有什么太大的区别,也是三步走(1. 自签名根证书,2.生成CSR证书签名请求,3.生成对应目标证书)

    《二》下面基于JAVA原生JDK的工具创建ECC的证书全流程进行分享,直接上相关的代码,希望能给到相关朋友一些帮助,有什么不清楚,可以参考我前面的博文,关于RSA证书的创建过程。

    1.创建秘钥对

    /**
         * algo: e.g. ECC
         * signAlgo: e.g. secp256r1
         * @param algo
         * @param signAlgo
         * @return
         */
        public static KeyPair getKeyPair(String algo, String signAlgo) {
            KeyPairGenerator keyPairGenerator = null;
            try {
                keyPairGenerator = KeyPairGenerator.getInstance(algo);
                ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(signAlgo);
                keyPairGenerator.initialize(ecGenParameterSpec, new SecureRandom());
                KeyPair keyPair = keyPairGenerator.generateKeyPair();
                return keyPair;
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            }
            return null;
        }

    2.创建自签名证书(CA)

    /**
         * 生成自签名证书
         *
         * @param publicKey 公钥对象
         * @param privateKey 私钥对象
         * @param subj 证书主体描述信息
         * @param notBefore 有效期起始日期
         * @param validDays 有效期长度
         * @return
         * @throws Exception
         */
        public static X509Certificate createRootCert(PublicKey publicKey, PrivateKey privateKey, String subj, Date notBefore, long validDays) throws Exception{
    
            String algo = "SHA256WITHECDSA";
            try {
                //证书拥有者subject的描述name
                sun.security.x509.X500Name subject = new sun.security.x509.X500Name(subj);
    
                CertificateExtensions certExts = new CertificateExtensions();
                certExts.set(SubjectKeyIdentifierExtension.NAME, new SubjectKeyIdentifierExtension((new KeyIdentifier(publicKey)).getIdentifier()));
                certExts.set(AuthorityKeyIdentifierExtension.NAME, new AuthorityKeyIdentifierExtension(new KeyIdentifier(publicKey), null, null));
                //设置是否根证书
                BasicConstraintsExtension bce = new BasicConstraintsExtension(true, -1);
                certExts.set(BasicConstraintsExtension.NAME, new BasicConstraintsExtension(false, bce.getExtensionValue()));
    
                //配置证书的有效期,并生成根证书(自签名证书)
                X509CertInfo x509CertInfo = new X509CertInfo();
                //设置证书的版本号
                x509CertInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
    
                AlgorithmId algorithmId = AlgorithmId.get(algo);
                x509CertInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algorithmId));
    
                //设置证书的签发者信息
                x509CertInfo.set(X509CertInfo.ISSUER, subject);
    
                //设置证书的拥有者信息
                x509CertInfo.set(X509CertInfo.SUBJECT, subject);
    
                //设置证书的序列号,基于当前时间计算
                x509CertInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber((int) (System.currentTimeMillis() / 1000L)));
    
                //设置证书的公钥
                x509CertInfo.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
    
                //设置证书有效期
                Date endDate = new Date(notBefore.getTime() + validDays * 24 * 60 * 60 * 1000L);
                CertificateValidity cv = new CertificateValidity(notBefore, endDate);
                x509CertInfo.set(X509CertInfo.VALIDITY, cv);
    
                x509CertInfo.set(CertificateExtensions.NAME, certExts);
    
                X509CertImpl cert = new X509CertImpl(x509CertInfo);
                try {
                    cert.sign(privateKey, algo);
                } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException | NoSuchProviderException | SignatureException e3) {
                    e3.printStackTrace();
                }
    
                return cert;
    
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }  catch (CertificateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }

    3.创建用户证书(用2中的证书签发客户证书)

    /**
         * 基于根证书签发客户证书(非CA证书),即intermediate certificate
         *
         * @param ca 根证书文件对象
         * @param caKey 根证书对应的私钥
         * @param publicKey 待签发证书的公钥
         * @param subj 待签发证书的主体描述信息
         * @param notBefore 证书有效期起点
         * @param validDays 证书有效期长度
         * @param sginAlgo 证书签名算法
         * @return
         */
        public static X509Certificate createUserCert(X509Certificate ca, PrivateKey caKey, PublicKey publicKey, String subj, Date notBefore, long validDays, String sginAlgo)  {
    
            //获取ca证书
            X509Certificate caCert = ca;
    
            X509CertInfo x509CertInfo = new X509CertInfo();
    
            try {
                //设置证书的版本号
                x509CertInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
    
                //设置证书的序列号,基于当前时间计算
                x509CertInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber((int) (System.currentTimeMillis() / 1000L)));
    
                /**
                 * 下面这个设置算法ID的代码,是错误的,会导致证书验证失败,但是报错不是很明确。 若将生成的证书存为keystore,让后keytool转换
                 * 会出现异常。
                 *
                 * 重点: AlgorithmId的参数设置要和后面的证书签名中用到的算法信息一致。
                 */
                AlgorithmId algorithmId = AlgorithmId.get(sginAlgo);
                x509CertInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algorithmId));
    
                //设置证书的签发者信息
                sun.security.x509.X500Name issuer = new sun.security.x509.X500Name(caCert.getIssuerX500Principal().toString());
                x509CertInfo.set(X509CertInfo.ISSUER, issuer);
    
                //设置证书的拥有者信息
                sun.security.x509.X500Name subject = new sun.security.x509.X500Name(subj);
                x509CertInfo.set(X509CertInfo.SUBJECT, subject);
    
                //设置证书的公钥
                x509CertInfo.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
    
                //设置证书有效期
                Date endDate = new Date(notBefore.getTime() + validDays * 24 * 60 * 60 * 1000L);
                CertificateValidity cv = new CertificateValidity(notBefore, endDate);
                x509CertInfo.set(X509CertInfo.VALIDITY, cv);
    
                CertificateExtensions exts = new CertificateExtensions();
    
                exts.set(SubjectKeyIdentifierExtension.NAME, new SubjectKeyIdentifierExtension((new KeyIdentifier(publicKey)).getIdentifier()));
                exts.set(AuthorityKeyIdentifierExtension.NAME, new AuthorityKeyIdentifierExtension(new KeyIdentifier(ca.getPublicKey()), null, null));
                exts.set(BasicConstraintsExtension.NAME, new BasicConstraintsExtension(false,false,-1));
                x509CertInfo.set(CertificateExtensions.NAME, exts);
    
            } catch (CertificateException cee) {
                cee.printStackTrace();
            } catch (IOException eio) {
                eio.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
    
            // 获取CA私钥
            PrivateKey caPrivateKey = caKey;
            //用CA的私钥给当前证书进行签名,获取最终的下游证书(证书链的下一节点)
            X509CertImpl cert = new X509CertImpl(x509CertInfo);
            try {
                cert.sign(caPrivateKey, sginAlgo);
            } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException | NoSuchProviderException | SignatureException e3) {
                e3.printStackTrace();
            }
            return cert;
        }

    4. 证书的导出和导入相关方法

    /**
         * 导出ECC私钥文件存入文件,PEM格式,PKCS#8编码
         * @param privateKey
         * @param keyPath
         * @throws Exception
         */
        public static void savePrivateKeyAsPEM(PrivateKey privateKey, String keyPath) throws Exception {
            String content = Base64Util.encode(privateKey.getEncoded());
            File file = new File(keyPath);
            try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw")) {
                randomAccessFile.write(BEGIN_EC_PRIVATE_KEY.getBytes());
                randomAccessFile.write(NEW_LINE.getBytes());
                int i = 0;
                for (; i<(content.length() - (content.length() % 64)); i+=64) {
                    randomAccessFile.write(content.substring(i, i + 64).getBytes());
                    randomAccessFile.write(NEW_LINE.getBytes());
                }
    
                randomAccessFile.write(content.substring(i).getBytes());
                randomAccessFile.write(NEW_LINE.getBytes());
    
                randomAccessFile.write(END_EC_PRIVATE_KEY.getBytes());
            }
        }
    /**
         * 导出ECC公钥文件存入文件,PEM格式,PKCS#8编码
         * 
         * @param publicKey
         * @param name
         * @throws Exception
         */
        public static void savePublicKeyAsPEM(PublicKey publicKey, String name) throws Exception {
            String content = Base64Util.encode(publicKey.getEncoded());
            File file = new File(name);
            try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw")) {
                randomAccessFile.write(BEGIN_EC_PUBLIC_KEY.getBytes());
                randomAccessFile.write(NEW_LINE.getBytes());
                int i = 0;
                for (; i<(content.length() - (content.length() % 64)); i+=64) {
                    randomAccessFile.write(content.substring(i, i + 64).getBytes());
                    randomAccessFile.write(NEW_LINE.getBytes());
                }
    
                randomAccessFile.write(content.substring(i).getBytes());
                randomAccessFile.write(NEW_LINE.getBytes());
    
                randomAccessFile.write(END_EC_PUBLIC_KEY.getBytes());
            }
        }

    这里需要说明的是,写入文件后,文件格式中的头部和尾部信息如下:

    private static final String BEGIN_EC_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----";
    private static final String END_EC_PRIVATE_KEY = "-----END PRIVATE KEY-----";
    private static final String BEGIN_EC_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----";
    private static final String END_EC_PUBLIC_KEY = "-----END PUBLIC KEY-----";

    用OPENSSL创建的EC证书私钥,默认情况下会含有EC PARAMETERS的描述,这个部分,JAVA生成过程中,目前没有弄清楚,如何能做到和OPENSSL一样,不过,不考虑EC PARAMETERS部分,整个证书运行逻辑没有问题。(若有知道的博友,可以给我留言,告知我JAVA代码如何实现openssl生成的EC证书私钥模式的文件),下面给予一个对比,OPENSSL的EC私钥内容和用上述JAVA生成的EC私钥内容:

    OPENSSL(PKCS#1编码):

    openssl ecparam -out coapApp.key -name secp521r1 -genkey

    -----BEGIN EC PARAMETERS-----
    BgUrgQQAIw==
    -----END EC PARAMETERS-----
    -----BEGIN EC PRIVATE KEY-----
    MIHcAgEBBEIBHpCev79KIY4T9lMyheMD9A+kXUXxmhbTdQO+bA9PCeLeXpUuHiPU
    dgJ31MjWYBe/5lr9Vr9kwZ20CAErIPDgttCgBwYFK4EEACOhgYkDgYYABAGhKHT6
    J6aihJyNgjdGNDP2yaCGDZjmuQw2JIs9l0C27B6KHytxOV5qZfvA80s8kq/a1FBn
    lUlHHjsEaVi20wWTmAFMgs75xAU+VjXEU9i03GaQuwC73mySAHWPWVQXmFu0b+Bz
    wfvBf8so3Qew054UFbmg1zvcjZM0rBhn6GZtp7LOZw==
    -----END EC PRIVATE KEY-----

    查看具体内容:

    [root@ws2 opt]# openssl ec -in coapApp.key -noout -text
    read EC key
    Private-Key: (521 bit)
    priv:
        01:1e:90:9e:bf:bf:4a:21:8e:13:f6:53:32:85:e3:
        03:f4:0f:a4:5d:45:f1:9a:16:d3:75:03:be:6c:0f:
        4f:09:e2:de:5e:95:2e:1e:23:d4:76:02:77:d4:c8:
        d6:60:17:bf:e6:5a:fd:56:bf:64:c1:9d:b4:08:01:
        2b:20:f0:e0:b6:d0
    pub: 
        04:01:a1:28:74:fa:27:a6:a2:84:9c:8d:82:37:46:
        34:33:f6:c9:a0:86:0d:98:e6:b9:0c:36:24:8b:3d:
        97:40:b6:ec:1e:8a:1f:2b:71:39:5e:6a:65:fb:c0:
        f3:4b:3c:92:af:da:d4:50:67:95:49:47:1e:3b:04:
        69:58:b6:d3:05:93:98:01:4c:82:ce:f9:c4:05:3e:
        56:35:c4:53:d8:b4:dc:66:90:bb:00:bb:de:6c:92:
        00:75:8f:59:54:17:98:5b:b4:6f:e0:73:c1:fb:c1:
        7f:cb:28:dd:07:b0:d3:9e:14:15:b9:a0:d7:3b:dc:
        8d:93:34:ac:18:67:e8:66:6d:a7:b2:ce:67
    ASN1 OID: secp521r1
    NIST CURVE: P-521

    JAVA(PKCS#8编码):

    ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(“secp256r1”);

    -----BEGIN PRIVATE KEY-----
    MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAoWE90so3R0wAj/kWS
    p43qZEHS2WcdZZAehpPtfZyV6A==
    -----END PRIVATE KEY-----

    查看具体内容:

    [root@ws2 opt]# openssl ec -in eccDevCertPem.key -noout -text
    read EC key
    Private-Key: (256 bit)
    priv:
        28:58:4f:74:b2:8d:d1:d3:00:23:fe:45:92:a7:8d:
        ea:64:41:d2:d9:67:1d:65:90:1e:86:93:ed:7d:9c:
        95:e8
    pub: 
        04:af:74:c5:4f:53:69:76:51:0d:c7:0a:9d:36:62:
        f0:4c:ab:f1:42:5c:cf:68:28:e8:9c:c7:13:b4:61:
        b0:a9:52:2a:66:57:2e:35:fe:92:dc:1c:8f:c9:cb:
        fa:2f:88:6a:bb:c3:54:d2:3d:34:ad:d5:9c:20:f5:
        1d:1e:9d:87:3b
    ASN1 OID: prime256v1
    NIST CURVE: P-256

    5. JAVA创建证书的DEMO

    public void fromZeroToStart() throws Exception {
            String subjCA = "OU=TaiKang,O=TKCloud,L=Wuhan,ST=Hubei,C=CN,CN=IOT_" + "ECC_CA";
            String subjSVR = "OU=TaiKang,O=TKCloud,L=Wuhan,ST=Hubei,C=CN,CN=" + "10.95.197.8";
            String subjDev = "OU=TaiKang,O=TKCloud,L=Wuhan,ST=Hubei,C=CN,CN=IOT_" + "Device";
    
            KeyPair eccCaKey = CertUtils.getKeyPair("EC", "secp256r1");
            KeyPair eccEmKey = CertUtils.getKeyPair("EC", "secp256r1");
            KeyPair eccDvKey = CertUtils.getKeyPair("EC", "secp256r1");
    
            //自签发根证书
            Date notBefore = new Date();
            X509Certificate crt = CertUtils.createRootCert(eccCaKey.getPublic(), eccCaKey.getPrivate(), subjCA, notBefore,365, SIGN_ALGO);
    //根证书签发生成实体证书
            X509Certificate eccEmqCert = CertUtils.createUserCert(crt, eccCaKey.getPrivate(), eccEmKey.getPublic(), subjSVR, notBefore, 365, SIGN_ALGO);
    //写入证书到文件
            SSLUtils.exportPemCrtFile(crt.getEncoded(),basePath + "eccRootCert.crt");
            SSLUtils.exportDerKeyFile(eccCaKey.getPrivate().getEncoded(),basePath + "eccRootCert.key");
            SSLUtils.savePrivateKeyAsPEM(eccCaKey.getPrivate(), basePath + "eccRootCertPem.key");
            SSLUtils.exportPemCrtFile(eccEmqCert.getEncoded(),basePath + "eccEmqCert.crt");
            SSLUtils.exportDerKeyFile(eccEmKey.getPrivate().getEncoded(),basePath + "eccEmqCert.key");
            SSLUtils.savePrivateKeyAsPEM(eccEmKey.getPrivate(), basePath + "eccEmqCertPem.key");
        }

    6. 遇到的小麻烦

    1)证书的有效时间和验证服务器的时间不同步导致异常

    [root@mq2 ecc]# openssl verify -CAfile eccRootCert.crt eccEmqCert.crt 
    eccEmqCert.crt: CN = IOT_ECC_CA, C = CN, ST = Hubei, L = Wuhan, O = TKCloud, OU = TaiKang
    error 9 at 1 depth lookup:certificate is not yet valid

    等一会后,同样的证书,同样的操作,就可以了(生成的证书里面设置的有效时间范围,和当前验证操作,即执行openssl的服务的时间没有同步,服务器时间慢了点

    [root@mq2 ecc]# openssl verify -CAfile eccRootCert.crt eccEmqCert.crt 
    eccEmqCert.crt: OK
    [root@ws2 ecc]# mosquitto_pub -d -h 10.95.197.8 -p 8883 -t taikang/rulee -i client18 --cafile /opt/ecc/eccRootCert.crt --cert /opt/ecc/eccDevCert.crt --key /opt/ecc/eccDevCertPem.key -u shihuc -P shihuc -m "are you ok, emqttd"
    Client client18 sending CONNECT
    OpenSSL Error: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
    Error: A TLS error occurred.

    上述错误信息,也是证书的有效时间和服务器时间不同步,参照上面的错误。

    2)openssl的版本不同导致的查看证书出现异常

    [root@mq2 ecc]# openssl x509 -in eccRootCert.crt -noout -text           
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 1556080738 (0x5cbfe862)
        Signature Algorithm: ecdsa-with-SHA256
            Issuer: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
            Validity
                Not Before: Apr 24 04:38:58 2019 GMT
                Not After : Apr 23 04:38:58 2020 GMT
            Subject: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
            Subject Public Key Info:
                Public Key Algorithm: id-ecPublicKey
                    Public-Key: (256 bit)
                    pub: 
                        04:65:49:e6:46:8d:28:b2:49:d2:45:26:04:f9:d5:
                        b3:f4:84:f9:38:2e:ad:43:d1:14:92:af:ad:c3:0a:
                        3c:35:21:f3:25:39:85:41:a9:b9:51:d7:b3:20:6b:
                        5d:09:23:c6:66:b5:22:f3:fb:dd:a6:1c:74:43:19:
                        c1:b0:50:5c:44
                    ASN1 OID: prime256v1
                    NIST CURVE: P-256
            X509v3 extensions:
                X509v3 Authority Key Identifier: 
                    keyid:0F:62:52:44:B1:7F:AA:23:BE:55:70:E3:05:F1:0F:EE:96:CB:C1:E9
    
                X509v3 Basic Constraints: 
                    CA:TRUE
                X509v3 Subject Key Identifier: 
                    0F:62:52:44:B1:7F:AA:23:BE:55:70:E3:05:F1:0F:EE:96:CB:C1:E9
        Signature Algorithm: ecdsa-with-SHA256
             30:44:02:20:02:f5:d5:3b:59:8a:42:af:c7:9a:15:06:f9:4b:
             03:09:0d:bb:28:59:dc:eb:91:38:65:99:64:45:91:33:2d:d5:
             02:20:51:f6:c3:ff:8e:76:32:cd:f2:a9:a9:23:18:37:d3:0a:
             18:9a:94:94:16:00:b4:fc:7c:cc:11:e8:99:18:81:21
    [root@mq2 ecc]# openssl version
    OpenSSL 1.0.2k-fips  26 Jan 2017

    同一个证书,在另外一个服务器上查看:

    [root@tkwh-kfcs-app2 java]# openssl x509 -in eccRootCert.crt -noout -text
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 1556066987 (0x5cbfb2ab)
        Signature Algorithm: ecdsa-with-SHA256
            Issuer: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
            Validity
                Not Before: Apr 24 00:49:35 2019 GMT
                Not After : Apr 23 00:49:35 2020 GMT
            Subject: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
            Subject Public Key Info:
                Public Key Algorithm: id-ecPublicKey
                Unable to load Public Key
    139880214046624:error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group:ec_curve.c:371:
    139880214046624:error:100D7010:elliptic curve routines:ECKEY_PUB_DECODE:EC lib:ec_ameth.c:206:
    139880214046624:error:0B07707D:x509 certificate routines:X509_PUBKEY_get:public key decode error:x_pubkey.c:164:
            X509v3 extensions:
                X509v3 Authority Key Identifier: 
                    keyid:06:67:AB:58:41:C5:DA:BD:23:73:9C:BA:E5:45:79:28:73:1C:E2:AF
    
                X509v3 Basic Constraints: 
                    CA:TRUE
                X509v3 Subject Key Identifier: 
                    06:67:AB:58:41:C5:DA:BD:23:73:9C:BA:E5:45:79:28:73:1C:E2:AF
        Signature Algorithm: ecdsa-with-SHA256
             30:44:02:20:5e:f6:fa:30:42:6f:20:1e:f6:34:1f:66:2c:a3:
             c7:a8:25:27:a1:8f:83:73:96:23:f2:e4:0d:e5:4b:a8:d2:a5:
             02:20:4c:6f:8b:2b:d4:5d:23:b3:fd:ba:3e:18:66:30:69:dc:
             48:f5:a9:88:7e:2f:e8:e9:7b:7b:4c:85:e0:bc:d5:01
    [root@tkwh-kfcs-app2 java]# openssl version
    OpenSSL 1.0.1e-fips 11 Feb 2013         

    好了,到这里,ECC证书创建和基本的验证过程,到此结束,有相关需求或者探讨的,可以关注我的博客,一起深入。

  • 相关阅读:
    使用Unity5.1进行VR开发的配置(最新的未必是最好的!!!)
    从单幅深度图识别人体姿态
    工作中编写存储过程小记
    【积累】根据CheckBox的不选中 ,用JQuery 清除 RidaoButtonList 的选中项
    【积累】LinqToSql复合查询结果转DataTable数据
    MSSSQL 脚本收藏
    VS2010历史记录清理
    PowerDesigner16工具学习笔记-建立CDM
    Android 安装过程中的问题
    Unity3D集成SVN进行版本控制
  • 原文地址:https://www.cnblogs.com/shihuc/p/10833229.html
Copyright © 2020-2023  润新知