OpenSSL
一、證書
1、 證書製作
1) 生成root 證書
<server>
openssl genrsa -out server\server_root.key 2048
openssl req -x509 -new -key server\server_root.key-days 10000 -out server\server_root.crt -subj"/C=US/ST=California/L=Silicon Valley/O=CAcert.org/OU=CAcert/CN=server_root/[email protected]"
輸出:server\server_root.key server\server_root.crt
<client>
openssl genrsa -out client\client_root.key 2048
openssl req -x509 -new -key client\client_root.key -days 10000 -outclient\client_root.crt -subj "/C=US/ST=California/L=SiliconValley/O=CAcert.org/OU=CAcert/CN=client_root/[email protected]"
輸出:client\client_root.key client\client_root.crt
2) 生成CA證書
<server>
openssl genrsa -out server\ford_server.key 2048
openssl req -new -key server\ford_server.key -days 10000 -outserver\ford_server.crt.req -subj"/C=US/ST=Michigan/L=Detroit/O=FORD_SERVER/OU=FORD_SDL_SERVER/CN=FORD/[email protected]"
openssl x509 -hash -req -in server\ford_server.crt.req -CAserver\server_root.crt -CAkey server\server_root.key -CAcreateserial -outserver\ford_server.crt -days 10000
輸出:server\ford_server.key server\ford_server.crt
<client>
openssl genrsa -out client\ford_client.key 2048
openssl req -new -key client\ford_client.key -days 10000 -outclient\ford_client.crt.req -subj"/C=US/ST=Michigan/L=Detroit/O=FORD_CLIENT/OU=FORD_SDL_CLIENT/CN=FORD_CLIENT/[email protected]"
openssl x509 -hash -req -in client\ford_client.crt.req -CAclient\client_root.crt -CAkey client\client_root.key -CAcreateserial -outclient\ford_client.crt -days 10000
輸出:client\ford_client.key client\ford_client.crt
3) 分別合併
輸出:server\ server_verification_ca_cetrificates.crt client\ client_verification_ca_cetrificates.crt
4) 生成簽名加密證書
<server>
openssl genrsa -out server\server.key 2048
openssl req -new -key server\server.key -days 10000 -out server\server.crt.req-subj "/C=RU/ST=Russia/L=St.Petersburg/O=Luxoft/OU=Mobile/CN=server/[email protected]/serialNumber=SPT"
openssl x509 -hash -req -in server\server.crt.req -CA server\ford_server.crt-CAkey server\ford_server.key -CAcreateserial -out server\server.crt -days10000
openssl pkcs12 -export -out server\spt_credential.p12 -inkey server\server.key-in server\server.crt -name "SPT key and certificates" -CAfile client\client_verification_ca_cetrificates.crt -passout pass:
輸出:server\server.key server\server.crt server\spt_credential.p12
<client>
openssl genrsa -out client\client.key 2048
openssl req -new -key client\client.key -days 10000 -out client\client.crt.req-subj "/C=RU/ST=Russia/L=St.Petersburg/O=Luxoft/OU=HeadUnit/CN=client/[email protected]/serialNumber=SPT"
openssl x509 -hash -req -in client\client.crt.req -CA client\ford_client.crt-CAkey client\ford_client.key -CAcreateserial -out client\client.crt -days10000
輸出:client\client.key client\client.crt
5) 生成無簽名證書
<server>
openssl req -x509 -new -key server\server.key -days 10000 -outserver\server_unsigned.crt -subj "/C=RU/ST=Russia/L=St.Petersburg/O=Luxoft/OU=Mobile_unsigned/CN=server/[email protected]/serialNumber=SPT"
openssl pkcs12 -export -out server\spt_credential_unsigned.p12 -inkeyserver\server.key -in server\server_unsigned.crt -name "SPT key andcertificates" -CAfile client\client_verification_ca_cetrificates.crt -passout pass:
openssl req -new -key server\server.key -days 10000 -outserver\server_expired.crt.req -subj "/C=RU/ST=Russia/L=St.Petersburg/O=Luxoft/OU=Mobile_expired/CN=server/[email protected]/serialNumber=SPT"
輸出:server\server_unsigned.crt server\spt_credential_unsigned.p12 server\server_expired.crt.req server\spt_credential_unsigned.p12.enc (base64編碼)
<client>
openssl req -x509 -new -key client\client.key -days 10000 -out client\client_unsigned.crt-subj "/C=RU/ST=Russia/L=St.Petersburg/O=Luxoft/OU=Mobile_unsigned/CN=client/[email protected]/serialNumber=SPT"
openssl pkcs12 -export -out client\client_credential_unsigned.p12 -inkeyclient\client.key -in client\client_unsigned.crt -name "SPT key andcertificates" -CAfile server\server_verification_ca_cetrificates.crt -passout pass:
1> --== Client pkcs12 expiredcertificate generating ==--
openssl req -new -key client\client.key -days 10000 -out client\client_expired.crt.req-subj "/C=RU/ST=Russia/L=St.Petersburg/O=Luxoft/OU=Mobile_expired/CN=client/[email protected]/serialNumber=SPT"
輸出:client\client_unsigned.crt client\client_credential_unsigned.p12 client\client_expired.crt.req client\client_credential_unsigned.p12.enc(base64編碼)
二、編譯
1) 下載openssl :git clone https://github.com/openssl/openssl.git
2) 下載並編譯wcecompat,wince openssl依賴它的頭文件和庫
地址:git clone https://github.com/mauricek/wcecompat.git
編譯wcecompat ,直接使用Qt打開wcecompat.pro用Qt編譯即可完成
然後把編譯好的.lib 文件和include 文件夾放到c盤c:\wcecompat
3) 下載並安裝Microsoft eMbedded C++ 4.0
4) 安裝WCE SDK,例如CHSINT SDK For WinCE(ARMV4I)
5) 下載並安裝perl
6) 編譯openssl:
a) 找到C:\Program Files (x86)\Microsoft eMbedded C++ 4.0\EVC\WCE400\BIN\WCEARMV4I.BAT用文本編輯器打開,修改以下內容:
REM PLATFORM=CHSINT SDK For WinCE 6.0
REM OSVERSION=WCE600
REM WCEROOT=C:\Program Files(x86)\Microsoft eMbedded C++ 4.0
REM SDKROOT=C:\Program Files (x86)\WindowsCE Tools
setPATH=%WCEROOT%\COMMON\EVC\bin;%WCEROOT%\EVC\WCE400\bin;C:\Program Files(x86)\Microsoft Visual Studio 9.0\VC\ce\bin\x86_arm;C:\Program Files(x86)\Microsoft Visual Studio 9.0\VC\bin;C:\Program Files (x86)\MicrosoftVisual Studio 9.0\Common7\Tools;C:\Program Files (x86)\Microsoft Visual Studio9.0\Common7\IDE;%path%
setINCLUDE=%SDKROOT%\%OSVERSION%\%PLATFORM%\include\ARMV4I;%SDKROOT%\%OSVERSION%\%PLATFORM%\MFC\include;%SDKROOT%\%OSVERSION%\%PLATFORM%\ATL\include;C:\ProgramFiles (x86)\Microsoft Visual Studio 9.0\VC\ce\include;C:\Program Files(x86)\Microsoft Visual Studio 9.0\VC\ce\atlmfc\include;
set LIB=%SDKROOT%\%OSVERSION%\%PLATFORM%\lib\ARMV4I;%SDKROOT%\%OSVERSION%\%PLATFORM%\MFC\lib\ARMV4I;%SDKROOT%\%OSVERSION%\%PLATFORM%\ATL\lib\ARMV4I;C:\ProgramFiles (x86)\Microsoft Visual Studio 9.0\VC\ce\lib\armv4i;C:\Program Files(x86)\Microsoft Visual Studio 9.0\VC\ce\atlmfc\lib\armv4i;
b) 運行cmd,執行剛纔修改的WCEARMV4I.BAT 文件
c) 設置WCECOMPAT的路徑,否則openssl找不到相關頭文件和依賴的庫。執行 set WCECOMPAT=C:\wcecompat
需要注意的是 wcecompat 源碼下 time.c 裏面涉及struct tm的需要修改,這是個bug,
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
tm_mon=實際月份-1
比如2016年8月20日,那麼它的值應該是:
tm_year=2016-1900=116;
tm_mon=8-1=7
如果不改,可能導致openssl 校驗證書時會出現“format error in certificate's notBefore field” 錯誤,實際上證書沒錯,只是wcecompat裏面gmtime錯了,導致openssl裏面調用的時候 tm_year=2016 ,不在取值範圍內
d) set OSVERSION=WCE600
e) cd到openssl源碼目錄執行perl Configure VC-CE
f) 執行ms\do_ms 生成兩個mak文件,ms\ce.mak 和ms\cedll.mak,一個是靜態庫一個是動態庫
g) 刪除ms\ce.mak裏面的CFLAG 裏面的-WX,然後執行nmake –f ms\ce.mak 編譯完成。
三、使用openssl
1) 初始化
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_library_init();
2) 建立安全連接
server 端:以1.0版本協議爲例
// 設置SSL指針
SSL_CTX *ctx=SSL_CTX_new(SSLv1_server_method());
// 建立連接
SSL *conn = SSL_new(SSL_CTX* ctx);
void SSL_set_accept_state(SSL *);// server端使用
void SSL_set_connect_state(SSL *);// client端使用
3) 證書使用
// base64解碼
BIO* bio =BIO_new(BIO_f_base64());
BIO* bmem = BIO_new_mem_buf((char*)cert_data.c_str(), cert_data.length());
bmem = BIO_push(bio, bmem);
char* buf = new char[cert_data.length()];
int len =BIO_read(bmem, buf, cert_data.length());
BIO* bio_cert =BIO_new(BIO_s_mem());
int k = BIO_write(bio_cert, buf, len);
PKCS12* p12 = d2i_PKCS12_bio(bio_cert, NULL);
EVP_PKEY* pkey = NULL;
X509* cert = NULL;
PKCS12_parse(p12, NULL, &pkey,&cert, NULL);
SSL_CTX_use_certificate(context_,cert);
asn1_time_to_tm(X509_get_notAfter(cert));
SSL_CTX_use_PrivateKey(context_,pkey);
SSL_CTX_check_private_key(context_);
// 加載信任證書
SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
const char *CApath);
CAfile是可信任證書文件名,CApath證書所在路徑
4) 讀寫操作
// 設置BIO,用於存放讀寫的緩存
void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio);
SSL_is_init_finished(a); //在通信之前有個握手操作,握手操作完成才能算初始化完成
int BIO_read(BIO *b, void *data, int len);
int BIO_write(BIO *b, const void *data, int len);
5) 握手操作
在通信之前有個握手操作,交換驗證證書
//握手操作
int SSL_do_handshake(SSL *s);
6) 結束處理
void SSL_shutdown(SSL *);
void free(SSL *);
void SSL_CTX_free(SSL_CTX *);