想學習一下dtls,是因為想以后沒有公司免費VPN可用的時候,我能買一個主機,自己建一個VPN。
1.介紹
Web, email大多用TLS協議來做安全的網絡傳輸,它們必須跑在可靠的TCP傳輸通道里。
如果傳輸的是實時媒體數據,那么重傳丟掉的包就沒有意義,這個時候,我們希望它是跑在UDP傳輸通道里。
再有,應用層協議SIP可以用TCP或UDP來傳,但我們更希望是UDP的。於是有了DTLS。
2. TLS有一些不同:
1)TLS不能單獨對某個記錄進行完整性檢查,如果記錄N沒收到,那記錄N+1無法被認證。因為MAC值是通過序列號計算的,而記錄里並沒有顯示的包含序列號段。
2)TLS握手協議不用考慮丟包的問題
3.DTLS是跑在UDP上的TLS,這做了一些改變解決了幾個問題
1) 禁止流加密。這樣可以保證記錄間加密上下文的獨立性。
2) 給記錄增加一個顯示的序列號字段用來做重放攻擊保護和記錄數據認證。
3) 給握手包加入重傳機制。為了requeset啟用一個timer,如果沒有收到response,而timer超時,那就重傳request.
4) 保證握手包的順序。每個握手包是有序列號的,如果不是期望收到的握手包,那么把它放入隊列。如果是,立刻處理。
5) 消息的size。UDP包如果大於1500會被分片。所以每個DTLS握手報文包含一個段偏移和段長,如此便可還原被分片的握手報文。
6)重放保護。維護一個接收報文的bitmap window。過老的報文或者收到過的包都被扔掉。
4. DTLS記錄的格式。除了上面提到的一些不同,很多字段和應用場景與TLS相同。
5. DTLS握手協議。DTLS握手協議基本與TLS相同,只有三個變化:
1) 加入一個無狀態的cookie交換,以防止dos攻擊。(就是給每一個請求連接的IP地址分配一個Cookie,如果短時間內連續受到某個IP的重復報文,就丟棄它)
2) 修改握手包頭來處理丟包,重排序和IP包分片問題。
3) 重傳timer,來處理丟包丟傳問題。
6. DTLS握手包頭,body較多不貼圖了,細節參見RFC.
7. 握手流程
8.我寫了一個簡單的例子,client用dtls協議發送一個字符串到server的5000端口,在Mac OS上編譯通過,正常工作。
https://github.com/andyhu-hz/mycode/tree/master/dtls_test
9.openssl中關於SSL_pending的一個錯誤認識。
開始以為SSL_pending是用來檢測有數據到來的,當SSL_pending返回一個非零正整數時,再調用SSL_Read從buffer中讀取數據。
事實上SSL_pending一直返回零,有人也遇到了類似的問題。見這里http://stackoverflow.com/questions/6616976/why-does-this-ssl-pending-call-always-return-zero
You are using SSL_pending()
the completely wrong way. OpenSSL uses a state machine, whereSSL_pending()
indicates if the state machine has any pending bytes that have been buffered and are awaiting processing. Since you are never calling SSL_read()
, you are never buffering any data or advancing the state machine.
If the SSL_pending function returns a return code of 0, it does not necessarily mean that there is no data immediately available for reading on the SSL session. A return code of 0 indicates that there is no more data in the current SSL data record. However, more SSL data records may have been received from the network already. If the SSL_pending function returns a return code of 0, issue the select function, passing the file descriptor of the socket to check if the socket is readable. Readable means more data has been received from the network on the socket.