Nginx+openssl的web https訪問:
1證書的生成:
openssl genrsa -des3 -out host.key 2048
生成簽發(fā)機構密鑰
openssl req -new -x509 -days 7305 -key host.key -out host.crt
生成簽發(fā)用證書
openssl genrsa -des3 -out applier.pem 1024
請求認證的公司生成私鑰
openssl rsa -in applier.pem -out applier.key
生成applier.pem對應的解密密鑰applier.key
openssl req -new -key applier.pem -out applier.csr
請求認證的證書申請
openssl ca -policy policy_anything -days 1460 -cert host.crt -keyfile host.key -in applier.csr -out applier.crt
Ca對applier.csr簽名并發(fā)布證書applier.crt
//認證環(huán)境
mkdir -p CA/newcerts
touch CA/index.txt
touch CA/serial
echo "01" > CA/serial

2 Nginx的配置
Server{
Listen 443 ssl default_server;
Index index.html index.htm;
Location / {
Root /rootdir
}
Ssl on
Ssl_certificate /path/applier.crt ??#提供證書
Ssl_certificate_key /path/applier.key ?#提供解密私鑰
}
訪問時通過https協(xié)議直接訪問localhost,此時瀏覽器會與服務器握手并收到證書消息,由于試驗中使用的自簽名證書,因此瀏覽器會提示證書不可信,將此證書添加到exception中即可訪問。在服務器發(fā)給客戶機的證書報文段中,包含有服務器證書的公鑰;客戶機接收到該報文段后,按照協(xié)議規(guī)定,從報文段的對應位置中讀取出服務器證書的公鑰存入相關變量中。
與網(wǎng)站建立SSL安全連接時使用https協(xié)議,即采用https://ip:port/的方式來訪問。瀏覽器與Web Server之間要經(jīng)過一個握手的過程來完成身份鑒定與密鑰交換,從而建立安全連接。具體過程如下:
1用戶瀏覽器將其SSL版本號、加密設置參數(shù)、與session有關的數(shù)據(jù)以及其它一些必要信息發(fā)送到服務器。
服務器將其SSL版本號、加密設置參數(shù)、與session有關的數(shù)據(jù)以及其它一些必要信息發(fā)送給瀏覽器,同時發(fā)給瀏覽器的還有服務器的證書。如果配置服務器的SSL需要驗證用戶身份,還要發(fā)出請求要求瀏覽器提供用戶證書。
2客戶端檢查服務器證書,如果檢查失敗,提示不能建立SSL連接。如果成功,那么繼續(xù)。客戶端瀏覽器為本次會話生成pre-master secret,并將其用服務器公鑰加密后發(fā)送給服務器。如果服務器要求鑒別客戶身份,客戶端還要再對另外一些數(shù)據(jù)簽名后并將其與客戶端證書一起發(fā)送給服務器。
如果服務器要求鑒別客戶身份,則檢查簽署客戶證書的CA是否可信。如果不在信任列表中,結束本次會話。如果檢查通過,服務器用自己的私鑰解密收到的pre-master secret,并用它通過某些算法生成本次會話的master secret。
3客戶端與服務器均使用此master secret生成本次會話的會話密鑰(對稱密鑰)。在雙方SSL握手結束后傳遞任何消息均使用此會話密鑰。這樣做的主要原因是對稱加密比非對稱加密的運算量低一個數(shù)量級以上,能夠顯著提高雙方會話時的運算速度。 ?客戶端通知服務器此后發(fā)送的消息都使用這個會話密鑰進行加密。并通知服務器客戶端已經(jīng)完成本次SSL握手。 服務器通知客戶端此后發(fā)送的消息都使用這個會話密鑰進行加密。并通知客戶端服務器已經(jīng)完成本次SSL握手。
x509協(xié)議api
證書的初始化函數(shù):
void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ){
memset( crt, 0, sizeof(mbedtls_x509_crt) );}
證書的空間釋放函數(shù)
void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
證書結構:
typedef struct mbedtls_x509_crt
{
mbedtls_x509_buf raw;隨機數(shù)據(jù)
mbedtls_x509_buf tbs;簽名
int version;版本
mbedtls_x509_buf serial; ??????????CA頒發(fā)的唯一序列號
mbedtls_x509_buf sig_oid;簽名算法,比如. sha1RSA *
mbedtls_x509_time valid_from;證書有效起始時間
mbedtls_x509_time valid_to;證書失效時間
mbedtls_pk_context pk;公鑰容器
int ext_types; ?????????????/**< Bit string containing detected and parsed extensions */
int max_pathlen;最大路徑長度
mbedtls_x509_buf sig;用私鑰加密后的簽名
mbedtls_md_type_t sig_md;信息摘要生成算法名稱. MBEDTLS_MD_SHA256mbedtls_pk_type_t sig_pk;簽名加密算法集的名稱MBEDTLS_PK_RSA */
struct mbedtls_x509_crt *next;指向下一個證書的指針
}
Mbedtls中的握手:
客戶端函數(shù)
int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl )
輸入?yún)?shù)為ssl_context為安全連接的配置參數(shù),包含了握手狀態(tài)、握手參數(shù)、會話數(shù)據(jù)、客戶端ID以及相關回調(diào)入口等參數(shù)。
以下程序摘自ssl_tls.c文件,可以看出mbed根據(jù)宏定義分別實現(xiàn)了server端和client端
#if defined(MBEDTLS_SSL_CLI_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
ret = mbedtls_ssl_handshake_client_step( ssl );
#endif
#if defined(MBEDTLS_SSL_SRV_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
ret = mbedtls_ssl_handshake_server_step( ssl );
#endif
Client端的邏輯:
Client發(fā)起clienthello請求后,server回serverhello包以及certificate(如果對客戶端有認證需求則會跟隨發(fā)送一個certificate request包來請求客戶端的證書),之后client開始分析傳來的server證書是否有效合法:
首先確認是否需要證書驗證,通過判斷ssl->transform_negotiate->ciphersuite_info字段
MBEDTLS_KEY_EXCHANGE_ECJPAKE,
MBEDTLS_KEY_EXCHANGE_PSK,
MBEDTLS_KEY_EXCHANGE_DHE_PSK,
MBEDTLS_KEY_EXCHANGE_ECDHE_PSK
以上四種psk加密套件不需要證書交互,需要證書的加密套件如下:
MBEDTLS_KEY_EXCHANGE_ECDHE_RSA,
MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
MBEDTLS_KEY_EXCHANGE_ECDH_RSA,
MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA,
其次驗證證書的有效性:mbedtls_x509_crt_verify_with_profile是x509_crt.c中的驗證函數(shù),其輸入?yún)?shù)是會話的peer證書、證書鏈、可信ca列表、認證配置文件、以及認證參數(shù)等。
1、對比CN字段是否匹配,若不匹配返回CN_MISMATCH錯誤---x509_memcasecmp函數(shù)
2、根據(jù)配置文件檢查密鑰大小和類型是否正確,不正確返回BAD_KEY錯誤----x509_profile_check_key函數(shù)
3、判斷CA的簽發(fā)方以及父簽發(fā)方(簽發(fā)鏈)是否可信-----x509_crt_check_parent函數(shù)
驗證完畢后,會判斷證書使用的是否是EC密鑰,如果是的話會使用函數(shù)mbedtls_ssl_check_curve來驗證橢圓曲線是否正確。