Class: ShadowsocksRuby::Protocols::TlsTicketProtocol
- Inherits:
-
Object
- Object
- ShadowsocksRuby::Protocols::TlsTicketProtocol
- Includes:
- BufferHelper, DummyHelper
- Defined in:
- lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb
Overview
TLS 1.2 Obfuscation Protocol
Specification:
-
github.com/shadowsocksr/shadowsocksr/blob/manyuser/shadowsocks/obfsplugin/obfs_tls.py
-
github.com/shadowsocksr/obfsplugin/blob/master/c/tls1.2_ticket.c
TLS 1.2 Reference:
Constant Summary collapse
- VERSION_SSL_3_0 =
[3, 0]
- VERSION_TLS_1_0 =
[3, 1]
- VERSION_TLS_1_1 =
[3, 2]
- VERSION_TLS_1_2 =
[3, 3]
- CTYPE_ChangeCipherSpec =
Content types
0x14- CTYPE_Alert =
0x15- CTYPE_Handshake =
0x16- CTYPE_Application =
0x17- CTYPE_Heartbeat =
0x18- MTYPE_HelloRequest =
Message types
0- MTYPE_ClientHello =
1- MTYPE_ServerHello =
2- MTYPE_NewSessionTicket =
4- MTYPE_Certificate =
11- MTYPE_ServerKeyExchange =
12- MTYPE_CertificateRequest =
13- MTYPE_ServerHelloDone =
14- MTYPE_CertificateVerify =
15- MTYPE_ClientKeyExchange =
16- MTYPE_Finished =
20
Instance Attribute Summary collapse
-
#next_protocol ⇒ Object
Returns the value of attribute next_protocol.
Instance Method Summary collapse
-
#get_random ⇒ Object
helpers.
-
#initialize(params = {}) ⇒ TlsTicketProtocol
constructor
A new instance of TlsTicketProtocol.
- #make_ext_sni(host) ⇒ Object
- #recv_client_change_cipherspec_and_finish ⇒ Object
- #recv_client_hello ⇒ Object
- #recv_server_hello ⇒ Object
- #send_client_change_cipherspec_and_finish(data) ⇒ Object
- #send_client_hello ⇒ Object
- #send_data_application_pharse(data) ⇒ Object
- #send_server_hello ⇒ Object
- #tcp_receive_from_localbackend_first_packet(n) ⇒ Object (also: #tcp_receive_from_localbackend)
-
#tcp_receive_from_localbackend_other_packet(n) ⇒ Object
TLS 1.2 Application Pharse.
- #tcp_receive_from_remoteserver_first_packet(n) ⇒ Object (also: #tcp_receive_from_remoteserver)
-
#tcp_receive_from_remoteserver_other_packet(n) ⇒ Object
TLS 1.2 Application Pharse.
- #tcp_send_to_localbackend(data) ⇒ Object
- #tcp_send_to_remoteserver_first_packet(data) ⇒ Object (also: #tcp_send_to_remoteserver)
-
#tcp_send_to_remoteserver_other_packet(data) ⇒ Object
TLS 1.2 Application Pharse.
Methods included from BufferHelper
#tcp_receive_from_localbackend_in_buffer, #tcp_receive_from_localbackend_other_packet_helper, #tcp_receive_from_remoteserver_in_buffer, #tcp_receive_from_remoteserver_other_packet_helper
Methods included from DummyHelper
#async_recv, #raise_me, #send_data
Constructor Details
#initialize(params = {}) ⇒ TlsTicketProtocol
Returns a new instance of TlsTicketProtocol.
53 54 55 56 57 58 59 60 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 53 def initialize params = {} @params = {:compatible => true}.merge(params) @buffer = '' @client_id = Random.new.bytes(32) @max_time_dif = 60 * 60 * 24 # time dif (second) setting @startup_time = Time.now.to_i - 60 * 30 @client_data = @params[:lrucache] || LRUCache.new(:ttl => 60 * 5) end |
Instance Attribute Details
#next_protocol ⇒ Object
Returns the value of attribute next_protocol.
45 46 47 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 45 def next_protocol @next_protocol end |
Instance Method Details
#get_random ⇒ Object
helpers
145 146 147 148 149 150 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 145 def get_random verifyid = [Time.now.to_i].pack("N") << Random.new.bytes(18) hello = "" hello << verifyid # Random part 1 hello << ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, verifyid) # Random part 2 end |
#make_ext_sni(host) ⇒ Object
311 312 313 314 315 316 317 318 319 320 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 311 def make_ext_sni host name_type = 0 #host_name server_name = [name_type, host.length].pack("Cn") << host server_name_list = [server_name.length].pack("n") << server_name type = Util.hex2bin("0000") data = [server_name_list.length].pack("n") << server_name_list return type << data end |
#recv_client_change_cipherspec_and_finish ⇒ Object
286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 286 def recv_client_change_cipherspec_and_finish data = async_recv 43 if data[0, 6] != [CTYPE_ChangeCipherSpec, *VERSION_TLS_1_2, 0, 1, 1].pack("C*") # ChangeCipherSpec raise PharseError, "server_decode data error" end if data[6, 5] != [CTYPE_Handshake, *VERSION_TLS_1_2, 32].pack("C3n") # Finished raise PharseError, "server_decode data error" end if ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, data[0, 33]) != data[33, 10] raise PharseError, "server_decode data error" end end |
#recv_client_hello ⇒ Object
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 211 def recv_client_hello data = async_recv 3 if data != [CTYPE_Handshake, *VERSION_TLS_1_0].pack("C3") if @params[:compatible] @buffer = data @no_effect = true return else raise PharseError, "decode error" end end = async_recv(2).unpack("n")[0] = async_recv() if (.slice!(0, 2) != [MTYPE_ClientHello, 0].pack("C2")) raise PharseError, "tls_auth not client hello message" end len_client_hello = .slice!(0, 2).unpack("n")[0] client_hello = if (len_client_hello != client_hello.length ) raise PharseError, "tls_auth wrong message size" end if (client_hello.slice!(0,2) != [*VERSION_TLS_1_2].pack("C2")) raise PharseError, "tls_auth wrong tls version" end verifyid = client_hello.slice!(0, 32) len_sessionid = client_hello.slice!(0,1).unpack("C")[0] if (len_sessionid < 32) raise PharseError, "tls_auth wrong sessionid_len" end sessionid = client_hello.slice!(0, len_sessionid) @client_id = sessionid sha1 = ShadowsocksRuby::Cipher::hmac_sha1_digest(@params[:key] + sessionid, verifyid[0, 22]) utc_time = Time.at(verifyid[0, 4].unpack("N")[0]) time_dif = Time.now.to_i - utc_time.to_i #if @params[:obfs_param] != nil # @max_time_dif = @params[:obfs_param].to_i #end if @max_time_dif > 0 && (time_dif.abs > @max_time_dif or utc_time.to_i - @startup_time < - @max_time_dif / 2) raise PharseError, "tls_auth wrong time" end if sha1 != verifyid[22 .. -1] raise PharseError, "tls_auth wrong sha1" end if @client_data[verifyid[0, 22]] raise PharseError, "replay attack detect, id = #{Util.bin2hex(verifyid)}" end @client_data[verifyid[0, 22]] = sessionid end |
#recv_server_hello ⇒ Object
203 204 205 206 207 208 209 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 203 def recv_server_hello data = async_recv(129) # ServerHello 76 + ServerChangeSipherSpec 6 + Finished 37 verify = data[11 ... 33] if ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, verify) != data[33 ... 43] raise PharseError, "client_decode data error" end end |
#send_client_change_cipherspec_and_finish(data) ⇒ Object
194 195 196 197 198 199 200 201 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 194 def send_client_change_cipherspec_and_finish data buf = "" buf << [CTYPE_ChangeCipherSpec, *VERSION_TLS_1_2, 0, 1, 1].pack("C*") buf << [CTYPE_Handshake, *VERSION_TLS_1_2, 32].pack("C3n") << Random.new.bytes(22) buf << ShadowsocksRuby::Cipher::hmac_sha1_digest(@params[:key] + @client_id, buf) buf << [CTYPE_Application, *VERSION_TLS_1_2, data.length].pack("C3n") << data send_data buf end |
#send_client_hello ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 152 def send_client_hello client_hello = "" client_hello << [*VERSION_TLS_1_2].pack("C2") # ProtocolVersion client_hello << get_random # Random len 32 client_hello << [32].pack("C") << @client_id # SessionID client_hello << Util.hex2bin("001cc02bc02fcca9cca8cc14cc13c00ac014c009c013009c0035002f000a") # CipherSuite client_hello << Util.hex2bin("0100") # CompressionMethod ext = Util.hex2bin("ff01000100") # Extension 1 (type ff01 + len 0001 + data 00 ) hosts = @params[:obfs_param] || @params[:host] if (hosts == nil or hosts == "") raise PharseError, "No :host or :obfs_param parameters" end if (("0".."9").include? hosts[-1]) hosts = "" end hosts = hosts.split(",") if hosts.length != 0 host = hosts[Random.rand(hosts.length)] else host = "" end ext << make_ext_sni(host) # Extension 2 ext << Util.hex2bin("00170000") # Extension 3 (type 0017 + len 0000) ext << Util.hex2bin("002300d0") << Random.new.bytes(208) # ticket, Extension 4 (type 0023 + len 00d0 + data) ext << Util.hex2bin("000d001600140601060305010503040104030301030302010203") # Extension 5 (type 000d + len 0016 + data) ext << Util.hex2bin("000500050100000000") # Extension 6 (type 0005 + len 0005 + data) ext << Util.hex2bin("00120000") # Extension 7 (type 0012 + len 0000) ext << Util.hex2bin("75500000") # Extension 8 (type 7550 + len 0000) ext << Util.hex2bin("000b00020100") # Extension 9 (type 000b + len 0002 + data) ext << Util.hex2bin("000a0006000400170018") # Extension 10 (type 000a + len 0006 + data) client_hello << [ext.length].pack("n") << ext # Extension List = [MTYPE_ClientHello, 0, client_hello.length].pack("CCn") << client_hello = [CTYPE_Handshake,*VERSION_TLS_1_0, .length].pack("C3n") << send_data() end |
#send_data_application_pharse(data) ⇒ Object
299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 299 def send_data_application_pharse data buf = "" while data.length > 2048 size = [Random.rand(65535) % 4096 + 100, data.length].min buf << [CTYPE_Application, *VERSION_TLS_1_2, size].pack("C3n") << data.slice!(0, size) end if data.length > 0 buf << [CTYPE_Application, *VERSION_TLS_1_2, data.length].pack("C3n") << data end send_data buf end |
#send_server_hello ⇒ Object
272 273 274 275 276 277 278 279 280 281 282 283 284 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 272 def send_server_hello data = [*VERSION_TLS_1_2].pack("C2") data << get_random data << Util.hex2bin("20") # len 32 in decimal data << @client_id data << Util.hex2bin("c02f000005ff01000100") data = Util.hex2bin("0200") << [data.length].pack("n") << data data = Util.hex2bin("160303") << [data.length].pack("n") << data # ServerHello len 86 (11 + 32 + 1 + 32 + 10) data << Util.hex2bin("14") << [*VERSION_TLS_1_2].pack("C2") << Util.hex2bin("000101") # ChangeCipherSpec len (6) data << Util.hex2bin("16") << [*VERSION_TLS_1_2].pack("C2") << Util.hex2bin("0020") << Random.new.bytes(22) data << ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, data) # Finished len(37) send_data data # len 129 end |
#tcp_receive_from_localbackend_first_packet(n) ⇒ Object Also known as: tcp_receive_from_localbackend
103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 103 def tcp_receive_from_localbackend_first_packet n class << self alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet end recv_client_hello @no_effect ||= nil if !@no_effect send_server_hello recv_client_change_cipherspec_and_finish tcp_receive_from_localbackend_other_packet n else tcp_receive_from_localbackend_other_packet_helper n end end |
#tcp_receive_from_localbackend_other_packet(n) ⇒ Object
TLS 1.2 Application Pharse
121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 121 def tcp_receive_from_localbackend_other_packet n @no_effect ||= nil if !@no_effect head = async_recv 3 if head != [CTYPE_Application, *VERSION_TLS_1_2].pack("C3") raise PharseError, "server_decode appdata error" end size = async_recv(2).unpack("n")[0] @buffer << async_recv(size) end tcp_receive_from_localbackend_other_packet_helper n end |
#tcp_receive_from_remoteserver_first_packet(n) ⇒ Object Also known as: tcp_receive_from_remoteserver
78 79 80 81 82 83 84 85 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 78 def tcp_receive_from_remoteserver_first_packet n send_client_hello recv_server_hello class << self alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_other_packet end tcp_receive_from_remoteserver_other_packet n end |
#tcp_receive_from_remoteserver_other_packet(n) ⇒ Object
TLS 1.2 Application Pharse
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 90 def tcp_receive_from_remoteserver_other_packet n head = async_recv 3 if head != [CTYPE_Application, *VERSION_TLS_1_2].pack("C3") raise PharseError, "client_decode appdata error" end size = async_recv(2).unpack("n")[0] @buffer << async_recv(size) tcp_receive_from_remoteserver_other_packet_helper n end |
#tcp_send_to_localbackend(data) ⇒ Object
135 136 137 138 139 140 141 142 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 135 def tcp_send_to_localbackend data @no_effect ||= nil if !@no_effect send_data_application_pharse data else send_data data end end |
#tcp_send_to_remoteserver_first_packet(data) ⇒ Object Also known as: tcp_send_to_remoteserver
62 63 64 65 66 67 68 69 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 62 def tcp_send_to_remoteserver_first_packet data send_client_change_cipherspec_and_finish data class << self alias tcp_send_to_remoteserver tcp_send_to_remoteserver_other_packet end end |
#tcp_send_to_remoteserver_other_packet(data) ⇒ Object
TLS 1.2 Application Pharse
74 75 76 |
# File 'lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb', line 74 def tcp_send_to_remoteserver_other_packet data send_data_application_pharse data end |