用openssl生成SSL使用的私鑰和證書,並自己做CA簽名(轉)


 本 文記敘的是一次基於SSL的socket通訊程序開發中,有關證書,簽名,身份驗證相關的步驟。 我們的場景下,socket服務端是java語言編寫的,客戶端是c語言。使用了一個叫做matrixssl的c語言庫。自己做CA簽名,不等同於“自簽 名”。 自簽名的情況,RSA的公鑰私鑰只有一對,用私鑰對公鑰證書做簽名。而我們的場景是,自己做CA,有一個CA的公鑰私鑰對。 而socket的服務端也有一個公鑰私鑰對。 用CA的私鑰對socket服務端的公鑰證書做簽名。

openssl genrsa -out ca.key 1024

 (這里我們沒有用des3加密。 可以增加一個-des3參數加密,詳情可以man genrsa) 

 

openssl req -new -x509 -days 36500 -key ca.key -out ca.crt

 (這一步的時候需要在提示之下輸入許多信息,包括國家代碼,省份,城市,公司機構名等) 

 

生成server端的私鑰key:

openssl genrsa -out server.key 1024

 

 生成server端的req文件(這一步生成的req文件,包含公鑰證書,外加身份信息,例如國家,省份,公司等。用它提交給ca,讓ca來對它做簽名 ):

openssl req -new -key server.key -out server.csr

 

用CA的私鑰對server的req文件做簽名,得到server的證書: 

openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

 (注:如果第一次使用openssl,報告一些相關的文件找不到之類的錯誤,可能需要先執行2個命令:touch /etc/pki/CA/index.txt 和 echo '01' > /etc/pki/CA/serial) 

 

以 上得到的server.crt就是服務端的證書文件。(有很多軟件中需要各種不同證書存儲格式,可能需要各種轉換。 如PEM, P12等,我們的場景下也需要一點轉換,下文會描述。剛開始做這些的同學可能會覺得證書,以及格式等非常的混亂。 這個時候能做的就是冷靜下來,耐心的理清楚TLS, RSA等原理, 多看看openssl的man文檔) 
不知道把ca.crt叫做CA的證書文件是否妥當,但是可以確定的是,客戶端使用ca.crt可以校驗server的身份。server在SSL/TLS 握手的過程中會下發自己的證書,而這個證書是經過CA簽名的。CA簽名的時候使用的是CA自己的私鑰,而ca.crt則包含了CA的公鑰,可以用於檢驗這 一簽名,以確認是否是自己簽的名。

服務端需要使用的文件是:server私鑰(key), server證書。 
客戶端需要使用的文件是:CA file(ca的證書,用以驗證server下發的證書)

我們的server端使用java, 使用p12(PKCS12)格式的證書。使用openssl可以進行格式轉換: 

openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12

可以看到輸出的server.p12中應該包含了server.key和server.crt的內容。

我們的c語言客戶端直接使用CA文件: ca.crt.

我們也用java寫過客戶端, java使用CA文件格式為 jks。那么可能需要一個轉換,這里使用的是java的bin目錄下的keytool: 

keytool -importcert -alias CA -file ca.crt -keystore ca.jks

轉換的時候要求輸入一個密碼。這樣就把ca.crt轉換為了 ca.jks格式。

下面附上部分socket服務端和java版的客戶端的代碼。c的就不貼了,用的matrixssl。

java服務端(mina)代碼片段:

String file = "/file/path/server.p12";
        String keyType = "PKCS12"; char[] password = "passwd".toCharArray();
        KeyStore ks = KeyStore.getInstance(keyType);
        ks.load(new FileInputStream(file), password);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
            KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(ks, password);
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(kmf.getKeyManagers(), null, null);

        SslFilter sslFilter = new SslFilter(ctx); // 在mina的acceptor中增加這個filter就可以了。 
acceptor.getFilterChain().addLast("ssl", new SslFilter(createSslContext()));

 java版客戶端(mina)代碼片段:

// trust String file = "/data/tmp/ca.jks";
        String keyType = "jks"; char[] password = "123456".toCharArray();
        KeyStore ks = KeyStore.getInstance(keyType);
        ks.load(new FileInputStream(file), password);
        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);
        SslFilter sslFilter = new SslFilter(sslContext);
        sslFilter.setUseClientMode(true); // server端是addLast ,  這個卻是 addFirst. 這個順序不能搞錯了。
 connector.getFilterChain().addFirst("sslFilter", sslFilter);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM