下面是一個ssl握手的過程,沒有進行用戶端驗證:
1.C-S:ClientHello---cipher-suit-list
2.S-C:ServerHello---selected-cipher-suit
3.S-C:ServerKeyExchange
4.S-C:ServerHelloDone
5.C-S:ClientKeyExchange
6.C-S:完成
7.S-C:完成
第3步是否發送要看c和s協商的cipher-suit是什麼,cipher-suit包含四個部分(将摘要算法并入認證算法的話也可以看作三個部分),第一是密鑰交換算法,第二是簽名算法/驗簽算法,第三是摘要算法,第四是對稱加密算法,RFC2246中建議了很多中組合,一般寫法是"密鑰交換算法-簽名算法-對稱加密算法-摘要算法",如果隻有rfc的建議是可用的,那就難免要在各個ssl實作中加以若幹硬性的規定,這樣密鑰交換和認證就不得不耦合起來了,比如使用ECC算法簽名的證書不能使用RSA算法進行密鑰交換,證書中密鑰太長的的涉及出口限制的必須使用臨時rsa進行密鑰交換,如果使用rsa作為密鑰交換算法,那麼在ClientKeyExchange中的pre-master必須用證書中的公鑰加密等等,之是以有這麼多限制就是因為一些人或者機構的管理因素在裡面,比如美國的出口限制等等,從協定本身來說,這些限制是不應該的,證書僅僅用于認證,而不和密鑰交換挂鈎,當然,它們之間也不是沒有任何關系,比如KeyExchange消息本身就需要認證,而認證的公私鑰資訊可以在證書中。
協定本身來看,任何的算法都能組合成一個cipher-suit,以RFC2246的一個建議為例,使用RSA作為密鑰交換算法的不能發送ServerKeyExchange消息,我們來看一下如何違反它進而實作一個新的不在RFC中的cipher-suit,這個cipher-suit使用rsa作為密鑰交換算法,但是使用ecdsa作為認證算法,暫且不考慮對稱加密算法和摘要算法。仍以上述握手過程為例,第2步時server端選擇了RSA-ECDSA-XX-YY這個cipher-suit,緊接着第3步,server将自己的使用ecdsa簽名的證書發送給了client,client用ca的ecc公鑰驗證server證書中ecc簽名,然後server違反rfc建議,在密鑰交換算法是rsa的情況下發送ServerKeyExchange消息,由于使用rsa進行密鑰交換,而證書中的公鑰是ecc算法簽名的,那麼這個ServerKeyExchange消息中必須包含一個臨時的rsa公鑰,server自己保留臨時rsa私鑰,然後server用自己的ecc私鑰将這個ServerKeyExchange消息進行簽名後發給client,client收到後會使用server證書中的ecc公鑰來驗證這個簽名,通過後儲存該消息中提取的server的臨時rsa公鑰,接着處理完hellodone消息後生成一個pre-master,然後用剛才儲存的server臨時rsa公鑰加密這個pre-master作為ClientKeyExchange消息發送給server,随後兩端使用密鑰導出算法導出一個對稱密鑰,認證完成,密鑰交換完成,握手完成。
上述的整個過程了解起來很簡單,就把ecc算法簽名的證書當成密鑰太長并有出口限制的rsa證書即可。總之,不考慮匿名dh以及一切類似情況下,任何需要驗證的地方,公鑰一般都驗證書裡面的,私鑰都取本地加載的,涉及密鑰交換的地方,嚴格按照cipher-suit中的算法進行。以上的論述在OpenSSL中不被支援,要想讓OpenSSL支援這個RSA-ECDSA-XX-YY的話就必須修改OpenSSL的源代碼,這個修改很簡單,僅僅修改s3_srvr.c,s3_clnt.c等不多的幾個檔案即可,加上對諸如(l & SSL_kRSA) && (l & SSL_aECDSA)等組合的判斷,本文不述。總之,就協定而言,任意的算法都能組合成一個cipher-suit。
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1271782