Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Openssl CA證書生成以及雙向認證,及windows系統證書批量導出,android cer轉bks

Openssl CA證書生成以及雙向認證,及windows系統證書批量導出,android cer轉bks

編輯:關於Android編程

只是途中有些問題折騰了一下,比如openssl.cnf如何來的,這個文件在編譯完openssl後,應該openssl根目錄下/apps/demoCA有個,可以把他拷貝到openssl.exe同一級目錄
裡面有些目錄配置,自己可以修改下,但是我沒有修改,所以最後生成的文件路徑必須按openssl.cnf裡面來,至於如何編譯openssl 請參考我的另一篇文章

開始生成證書,需要提前做一些准備,生成一些特定目錄,這些目錄和openssl.cnf裡面配置要求一致,在demoCA目錄下,還需要建立一個index.txt,index.txt.attr空文件,以及serial文件,serial文件裡面寫00
注意每次輸入下一步命令前,如果index.txt serial文件內容發生改變,請把index.txt中的內容清空,serial重置為00,否則後續命令中會報錯(比如報數據庫更新錯誤,此時依然會產生證書,但是c++代碼加載證書時卻會報錯)

打開openssl.cnf文件,可以看到其中的一些目錄結構要求
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片3

serial文件內容圖
這裡寫3描述

cmd進入openssl.exe所在目錄下,依次輸入以下命令(證書名字可以自己調整,輸入過程中需要輸入一些信息,如國家,省,市,主機名,郵件,密碼等,請盡量保持一致) 例如我的主機名就寫127.0.0.1 可以檢驗證書域名,代碼在客戶端給出<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCgk8cD6y+sn6Q0HX1Mepw/vWpMrpPGJyIC8+DQoJb3BlbnNzbC5leGUgZ2VucnNhIC1vdXQgcHJpdmF0ZVxjYS5rZXkgLXJhbmQgcHJpdmF0ZS5ybmQgLWRlcyAyMDQ4PGJyIC8+DQoJb3BlbnNzbC5leGUgcmVxIC1uZXcgLXg1MDkgLWRheXMgMzY1MCAta2V5IHByaXZhdGVcY2Eua2V5IC1vdXQgcHJpdmF0ZVxjYS5jcnQgLWNvbmZpZyBvcGVuc3NsLmNuZjxiciAvPg0KCW9wZW5zc2wuZXhlIHg1MDkgLWluIHByaXZhdGVcY2EuY3J0IC1ub291dCAtdGV4dDwvcD4NCgk8cD6y+sn6c2VydmVytcTWpMrpuf2zzDxiciAvPg0KCW9wZW5zc2wuZXhlIGdlbnJzYSAtb3V0IHByaXZhdGVcc2VydmVyLmtleSAxMDI0PGJyIC8+DQoJb3BlbnNzbC5leGUgcmVxIC1uZXcgLWtleSBwcml2YXRlXHNlcnZlci5rZXkgLW91dCBuZXdjZXJ0c1xzZXJ2ZXIuY3NyIC1jb25maWcgb3BlbnNzbC5jbmY8YnIgLz4NCglvcGVuc3NsLmV4ZSBjYSAtaW4gbmV3Y2VydHNcc2VydmVyLmNzciAtY2VydCBwcml2YXRlXGNhLmNydCAta2V5ZmlsZSBwcml2YXRlXGNhLmtleTxiciAvPg0KCS1jb25maWcgb3BlbnNzbC5jbmYgLXBvbGljeSBwb2xpY3lfYW55dGhpbmcgLW91dCBjZXJ0c1xzZXJ2ZXIuY3J0PGJyIC8+DQoJb3BlbnNzbC5leGUgeDUwOSAtaW4gY2VydHNcc2VydmVyLmNydCAtbm9vdXQgLXRleHQ8L3A+DQoJPHA+svrJ+nByb3h5tcTWpMrpuf2zzDxiciAvPg0KCW9wZW5zc2wuZXhlIGdlbnJzYSAtb3V0IHByaXZhdGVccHJveHkua2V5IDEwMjQ8YnIgLz4NCglvcGVuc3NsLmV4ZSByZXEgLW5ldyAta2V5IHByaXZhdGVccHJveHkua2V5IC1vdXQgbmV3Y2VydHNccHJveHkuY3NyIC1jb25maWcgb3BlbnNzbC5jbmY8YnIgLz4NCglvcGVuc3NsLmV4ZSBjYSAtaW4gbmV3Y2VydHNccHJveHkuY3NyIC1jZXJ0IHByaXZhdGVcY2EuY3J0IC1rZXlmaWxlIHByaXZhdGVcY2Eua2V5IC1jb25maWcgb3BlbnNzbC5jbmYgLXBvbGljeSBwb2xpY3lfYW55dGhpbmcgLW91dCBjZXJ0c1xwcm94eS5jcnQ8YnIgLz4NCglvcGVuc3NsLmV4ZSB4NTA5IC1pbiBjZXJ0c1xwcm94eS5jcnQgLW5vb3V0IC10ZXh0PC9wPg0KCTxwPrL6yfpjbGllbnS1xNakyum5/bPMPGJyIC8+DQoJb3BlbnNzbC5leGUgZ2VucnNhIC1vdXQgcHJpdmF0ZVxjbGllbnQua2V5IDEwMjQ8YnIgLz4NCglvcGVuc3NsLmV4ZSByZXEgLW5ldyAta2V5IHByaXZhdGVcY2xpZW50LmtleSAtb3V0IG5ld2NlcnRzXGNsaWVudC5jc3IgLWNvbmZpZyBvcGVuc3NsLmNuZjxiciAvPg0KCW9wZW5zc2wuZXhlIGNhIC1pbiBuZXdjZXJ0c1xjbGllbnQuY3NyIC1jZXJ0IHByaXZhdGVcY2EuY3J0IC1rZXlmaWxlIHByaXZhdGVcY2Eua2V5IC1jb25maWcgb3BlbnNzbC5jbmYgLXBvbGljeSBwb2xpY3lfYW55dGhpbmcgLW91dCBjZXJ0c1xjbGllbnQuY3J0PGJyIC8+DQoJb3BlbnNzbC5leGUgeDUwOSAtaW4gY2VydHNcY2xpZW50LmNydCAtbm9vdXQgLXRleHQ8L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD7V+7j2uf2zzL3hyvi68zxiciAvPg0KPGltZyBhbHQ9"這裡寫圖片描述" src="/uploadfile/Collfiles/20160526/20160526094312202.png" title="\" />
這裡寫圖片描述
這裡寫圖片描述

ca.crt為自簽名證書;
server.crt,server.key為服務器端的證書和私鑰文件;
proxy.crt,proxy.key為代理服務器端的證書和私鑰文件;
client.crt,client.key為客戶端的證書和私鑰文件。

代碼塊

服務端測試代碼,我做了點修改

//server  
#include   
#include   
#include   
#include   
#include "openssl/x509.h"  
#include "openssl/ssl.h"  
#include "openssl/err.h" 

#define MSGLENGTH      1024  
#define PORT           8443  
#define CACERT         "ca.crt"  
#define SVRCERTF       "server.crt"  
#define SVRKEYF        "server.key" 

int main()  
{  
    WSADATA wsaData;  
    WSAStartup(MAKEWORD(2,2), &wsaData);  
    SOCKET sock;  
    SSL_METHOD *meth;  
    SSL_CTX* ctx;  
    SSL* ssl;  
    //SSL初始化  
    OpenSSL_add_ssl_algorithms();  
    //SSL錯誤信息初始化  
    SSL_load_error_strings(); 

    //創建本次會話所使用的協議  
    meth = TLSv1_server_method();  
    //申請SSL會話的環境  
    ctx = SSL_CTX_new(meth);  
    if (NULL == ctx)  
        exit(1); 

   //設置會話的握手方式並加載CA證書  
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_load_verify_locations(ctx, "D:\\usr\\local\\ssl\\bin\\private\\ca.crt", NULL);
    //加載服務器端的證書  
    if (0 == SSL_CTX_use_certificate_file(ctx, "D:\\usr\\local\\ssl\\bin\\certs\\server.crt", SSL_FILETYPE_PEM)) 
    {
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    //加載服務器端的私鑰  
    if (0 == SSL_CTX_use_PrivateKey_file(ctx, "D:\\usr\\local\\ssl\\bin\\private\\server.key", SSL_FILETYPE_PEM))
    {
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    //檢查服務器端的證書和私鑰是否匹配  
    if (!SSL_CTX_check_private_key(ctx)) {
        printf("Private key does not match the certificate public key\n");
        exit(1);
    }

    //加密方式  
    SSL_CTX_set_cipher_list(ctx, "RC4-MD5");  
    //處理握手多次  
    SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 

    /*以下是正常的TCP socket建立過程 .............................. */  
    printf("Begin tcp socket...\n");  
    sock = socket(AF_INET, SOCK_STREAM, 0);  
    if (sock == INVALID_SOCKET) {  
        printf("SOCKET有問題. \n");  
        return 0;  
    } 

    sockaddr_in addr;  
    memset(&addr, '\0', sizeof(addr));  
    addr.sin_family = AF_INET;  
    addr.sin_port = htons(PORT); /* Server Port number */  
    addr.sin_addr.s_addr = INADDR_ANY; 

    //綁定sock  
    int nResult = bind(sock, (sockaddr *)&addr, sizeof(addr));  
    if (nResult == SOCKET_ERROR) {  
        printf("綁定SOCKET有問題. \n");  
        return 0;  
    }  
    printf("服務器啟動成功,端口:%d\n正在等待連接\n", PORT); 

    /*接受TCP鏈接*/  
    sockaddr_in sa_cli;  
    int err = listen(sock, 5);  
    if (-1 == err)  
        exit(1);  
    int client_len = sizeof(sa_cli);  
    int ss = accept(sock, (struct sockaddr *) &sa_cli, &client_len);  
    if (ss == -1) {  
        exit(1);  
    }  
    closesocket(sock);  
    printf("Connection from %d, port %d\n", sa_cli.sin_addr.s_addr, sa_cli.sin_port); 

    /* TCP 鏈接已建立.開始 SSL 握手過程.......................... */  
    //綁定套接字  
    ssl = SSL_new(ctx);  
    if (NULL == ssl)  
        exit(1);  
    if (0 == SSL_set_fd(ssl, ss)) {  
        printf("Attach to Line fail!\n");  
        exit(1);  
    }  
    //SSL握手  
    //SSL_accept(ssl);  
    int k = SSL_accept(ssl);  
    if (0 == k) {  
        printf("%d\n", k);  
        printf("SSL connect fail!\n");  
        exit(1);  
    }  
    //進行信息驗證  
    X509 *client_cert;  
    client_cert = SSL_get_peer_certificate(ssl); 

    printf("發現客戶端嘗試連接\n");  
    if (client_cert != NULL) {  
        printf ("Client certificate:\n"); 

        int rv = SSL_get_verify_result(ssl);
        if (rv != X509_V_OK)
        {
            printf("認證出錯!\n");
            exit(1);
        }
        //讀取證書subject名並顯示  
        char *str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);  
        if (NULL == str) {  
            printf("認證出錯!\n");  
            exit(1);  
        }  
        printf("subject: %s\n", str);  
        //讀取證書的issuer名並顯示  
        str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);  
        if (NULL == str) {  
            printf("證書名為空\n");  
            exit(1);  
        }  
        printf("issuer: %s\n", str);  
        printf("連接成功\n"); 

        X509_free (client_cert);/*如不再需要,需將證書釋放 */  
        OPENSSL_free(str);  
    }  
    else {  
        printf("找不到客戶端的認證證書\n");  
        exit(1);  
    } 

    char buf[MSGLENGTH];  
    SSL_write(ssl, "Server is connect to you!\n", strlen("Server is connect to you!\n"));  
    printf("Listen to the client: \n");  
    while (1) {  
        err = SSL_read(ssl, buf, sizeof(buf));  
        if(err == -1)
            break;
        buf[err] = '\0';  
        printf("%s\n", buf);  
    } 

    //關閉套接字  
    SSL_shutdown(ssl);  
    SSL_free(ssl);  
    SSL_CTX_free(ctx);  
    WSACleanup();  
    getch();  
    return 0;  
} 

客戶端測試代碼,我做了點修改

//client  
#include   
#include   
#include   
#include "openssl/x509.h"  
#include "openssl/ssl.h"  
#include "openssl/err.h"  
#include "openssl/rand.h" 

#define PORT       8443  
#define SERVER     "127.0.0.1"  
#define CACERT     "D:\\usr\\local\\ssl\\bin\\private\\ca.crt"  
#define MYCERTF    "D:\\usr\\local\\ssl\\bin\\certs\\client.crt"  
#define MYKEYF     "D:\\usr\\local\\ssl\\bin\\private\\client.key"  
#define MSGLENGTH  1024 

int GetSrvCert(SSL * ssl, X509 ** pCert)
{
    int rv = -1;
    if (ssl == NULL)
    {
        return rv;
    }
    rv = SSL_get_verify_result(ssl);
    *pCert = SSL_get_peer_certificate(ssl);
    return rv;
}

//驗證證書的合法性
int VerifyCert(X509 * pCert, const char * hostname)
{
    char commonName[512] = { 0 };
    X509_name_st * name = NULL;

    if (pCert == NULL || hostname == NULL)
    {
        return -1;
    }
    //獲取commonName
    name = X509_get_subject_name(pCert);
    X509_NAME_get_text_by_NID(name, NID_commonName, commonName, 512);
    fprintf(stderr, "VerifyCert - Common Name on certificate: %s\n", commonName);
    if (strcmp(commonName, hostname) == 0)
    {
        printf("證書主機名%s\n", commonName);
        return 1;
    }
    else
    {
        return 0;
    }
}

int main()  
{  
   WSADATA wsadata;
    WSAStartup(MAKEWORD(2, 2), &wsadata);
    sockaddr_in sin;
    int seed_int[100]; /*存放隨機序列*/

    SSL*ssl;
    const SSL_METHOD *meth;
    SSL_CTX *ctx;

    //SSL初始化  
    OpenSSL_add_ssl_algorithms();
    //SSL錯誤信息初始化  
    SSL_load_error_strings();

    //創建本次會話所使用的協議  
    meth = TLSv1_client_method();
    //申請SSL會話的環境  
    ctx = SSL_CTX_new(meth);
    if (NULL == ctx)
        exit(1);

    SSL_CTX_set_default_passwd_cb(ctx, pem_password_cb1);
    //SSL_CTX_set_default_passwd_cb_userdata(ctx, (void*)"555555");
    //設置會話的握手方式並加載CA證書  
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_load_verify_locations(ctx, CACERT, NULL);
    //加載自己的證書  
    if (0 == SSL_CTX_use_certificate_file(ctx, MYCERTF, SSL_FILETYPE_PEM)) {
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    //加載自己的私鑰  
    if (0 == SSL_CTX_use_PrivateKey_file(ctx, MYKEYF, SSL_FILETYPE_PEM)) {
        ERR_print_errors_fp(stderr);
        exit(1);
    }



    //檢查自己的證書和私鑰是否匹配  
    if (!SSL_CTX_check_private_key(ctx)) {
        printf("Private key does not match the certificate public key\n");
        exit(1);
    }



    /*構建隨機數生成機制,WIN32平台必需*/
    srand((unsigned)time(NULL));
    for (int i = 0; i < 100; i++)
        seed_int[i] = rand();
    RAND_seed(seed_int, sizeof(seed_int));

    //加密方式  
    SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
    //處理握手多次  
    SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);

    /*以下是正常的TCP socket建立過程 .............................. */
    SOCKET sock;
    printf("Begin tcp socket...\n");
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        printf("SOCKET有問題. \n");
    }

    memset(&sin, '\0', sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(SERVER); /* Server IP */
    sin.sin_port = htons(PORT); /* Server Port number */

    int icnn = connect(sock, (sockaddr *)&sin, sizeof(sin));
    if (icnn == SOCKET_ERROR) {
        printf("連不上服務器\n", GetLastError());
        exit(1);
    }

    /* TCP 鏈接已建立.開始 SSL 握手過程.......................... */
    //綁定套接字  
    ssl = SSL_new(ctx);
    if (NULL == ssl)
        exit(1);
    if (0 >= SSL_set_fd(ssl, sock)) {
        printf("Attach to Line fail!\n");
        exit(1);
    }
    //SSL握手  
    //SSL_connect(ssl);  
    int k = SSL_connect(ssl);
    if (0 == k) {
        printf("%d\n", k);
        printf("SSL connect fail!\n");
        exit(1);
    }
    printf("連接服務器成功\n");

    fprintf(stderr, "Retrieving peer certificate\n");
    //獲取服務器證書

    X509* pCert = NULL;
    if (GetSrvCert(ssl, &pCert) != X509_V_OK)
    {
        if (SSL_get_verify_result(ssl) != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
        {
            fprintf(stderr, "Certificate verification error: %i\n", SSL_get_verify_result(ssl));            
            SSL_CTX_free(ctx);
            return 0;
        }
        else
        {
            fprintf(stderr, "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY\n");
        }
    }


    //校驗服務器證書
    fprintf(stderr, "Validating peer certificate\n");
    if (!VerifyCert(pCert, "127.0.0.1"))
    {
        fprintf(stderr, "Hostname and Common Name do not match\n");

        SSL_CTX_free(ctx);
        return 0;
    }

    char sendmsg[MSGLENGTH] = "\0";
    char revmsg[MSGLENGTH] = "\0";

    int err = SSL_read(ssl, revmsg, sizeof(revmsg));
    revmsg[err] = '\0';
    printf("%s\n", revmsg);

    while (1) {
        printf("請輸入所要發送的數據:\n");
        scanf("%s", sendmsg);
        SSL_write(ssl, sendmsg, strlen(sendmsg));
        printf("發送消息“ %s ”成功!\n", sendmsg);
    }

    //關閉套接字  
    SSL_shutdown(ssl);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    closesocket(sock);
    WSACleanup();   
    return 0;
} 

系統內置證書問題

現在有個問題,當訪問百度,支付寶,銀聯的時候,浏覽器是內置證書,怎麼獲取批量獲取這些證書呢?
在cmd中輸入certmgr.msc
這裡寫圖片描述
選擇受信任的根證書頒發機構,全選,點郵件,所有任務,導出
這裡寫圖片描述
輸入密碼
這裡寫圖片描述

就生成一個pfx文件,現在只要用openssl轉成cer文件就可以了,命令
openssl pkcs12 -nodes -nokeys -in 11.pfx -out 1.cer -passin pass:123456
在程序中使用SSL_CTX_load_verify_locations 預先加載這個1.cer文件就可以了

Android BKS證書

Android加載bks格式證書,Ios/Pc加載cer格式證書,一般而言,生成cer格式比較常見,因此需要進行cer轉bks操作,操作步驟如下:

首先要下載特定版本的JCE Provider包
http://www.bouncycastle.org/download/bcprov-jdk15on-146.jar
或者
http://pan.baidu.com/s/1c1ur13y

轉換命令說明:
keytool -importcert -v -trustcacerts -alias 位置1 \
-file 位置2 \
-keystore 位置3 -storetype BKS \
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
-providerpath 位置4 -storepass 位置5

位置1:是個隨便取的別名
位置2:cer或crt證書的全地址
位置3:生成後bks文件的位置,建議寫全地址
位置4:上面下載JCE Provider包的位置
位置5:生成後證書的密碼

轉換完整示例
keytool -importcert -v -trustcacerts -alias my12306 -file C:\Users\Administrator\Desktop\證書\srca.cer -keystore C:\Users\Administrator\Desktop\證書\srca.bks -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\Users\Administrator\Desktop\證書\bcprov-jdk15on-146.jar -storepass 123456

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved