編輯:關於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文件,可以看到其中的一些目錄結構要求
serial文件內容圖
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
今天在項目中用到了android中常用的RadioGroup、RadioButton、Spinner、EditText等控件,在此介紹一下它們的用法,希望對
鑒於谷歌最新推出的Android Studio備受開發者的推崇,所以也跟著體驗一下。一、介紹Android Studio Android Studio 是一個A
cardView:添加依賴:在Studio搜索cardview即可 在V7包中或者直接在gradle中添加compile 'com.android.support
之前寫過一篇Eclipse制作.so的文章,使用的是GNUstep模擬Linux環境,過程現在看來是想相當麻煩,後來發現一個簡單的方法就是通過項目右鍵添加Native S