下面是一個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。