Record.pm 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. # Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License 2.0 (the "License"). You may not use
  4. # this file except in compliance with the License. You can obtain a copy
  5. # in the file LICENSE in the source distribution or at
  6. # https://www.openssl.org/source/license.html
  7. use strict;
  8. use TLSProxy::Proxy;
  9. package TLSProxy::Record;
  10. my $server_encrypting = 0;
  11. my $client_encrypting = 0;
  12. my $etm = 0;
  13. use constant TLS_RECORD_HEADER_LENGTH => 5;
  14. #Record types
  15. use constant {
  16. RT_APPLICATION_DATA => 23,
  17. RT_HANDSHAKE => 22,
  18. RT_ALERT => 21,
  19. RT_CCS => 20,
  20. RT_UNKNOWN => 100
  21. };
  22. my %record_type = (
  23. RT_APPLICATION_DATA, "APPLICATION DATA",
  24. RT_HANDSHAKE, "HANDSHAKE",
  25. RT_ALERT, "ALERT",
  26. RT_CCS, "CCS",
  27. RT_UNKNOWN, "UNKNOWN"
  28. );
  29. use constant {
  30. VERS_TLS_1_4 => 0x0305,
  31. VERS_TLS_1_3 => 0x0304,
  32. VERS_TLS_1_2 => 0x0303,
  33. VERS_TLS_1_1 => 0x0302,
  34. VERS_TLS_1_0 => 0x0301,
  35. VERS_SSL_3_0 => 0x0300,
  36. VERS_SSL_LT_3_0 => 0x02ff
  37. };
  38. my %tls_version = (
  39. VERS_TLS_1_3, "TLS1.3",
  40. VERS_TLS_1_2, "TLS1.2",
  41. VERS_TLS_1_1, "TLS1.1",
  42. VERS_TLS_1_0, "TLS1.0",
  43. VERS_SSL_3_0, "SSL3",
  44. VERS_SSL_LT_3_0, "SSL<3"
  45. );
  46. #Class method to extract records from a packet of data
  47. sub get_records
  48. {
  49. my $class = shift;
  50. my $server = shift;
  51. my $flight = shift;
  52. my $packet = shift;
  53. my $partial = "";
  54. my @record_list = ();
  55. my @message_list = ();
  56. my $recnum = 1;
  57. while (length ($packet) > 0) {
  58. print " Record $recnum ", $server ? "(server -> client)\n"
  59. : "(client -> server)\n";
  60. #Get the record header (unpack can't fail if $packet is too short)
  61. my ($content_type, $version, $len) = unpack('Cnn', $packet);
  62. if (length($packet) < TLS_RECORD_HEADER_LENGTH + ($len // 0)) {
  63. print "Partial data : ".length($packet)." bytes\n";
  64. $partial = $packet;
  65. last;
  66. }
  67. my $data = substr($packet, TLS_RECORD_HEADER_LENGTH, $len);
  68. print " Content type: ".$record_type{$content_type}."\n";
  69. print " Version: $tls_version{$version}\n";
  70. print " Length: $len\n";
  71. my $record = TLSProxy::Record->new(
  72. $flight,
  73. $content_type,
  74. $version,
  75. $len,
  76. 0,
  77. $len, # len_real
  78. $len, # decrypt_len
  79. $data, # data
  80. $data # decrypt_data
  81. );
  82. if ($content_type != RT_CCS
  83. && (!TLSProxy::Proxy->is_tls13()
  84. || $content_type != RT_ALERT)) {
  85. if (($server && $server_encrypting)
  86. || (!$server && $client_encrypting)) {
  87. if (!TLSProxy::Proxy->is_tls13() && $etm) {
  88. $record->decryptETM();
  89. } else {
  90. $record->decrypt();
  91. }
  92. $record->encrypted(1);
  93. if (TLSProxy::Proxy->is_tls13()) {
  94. print " Inner content type: "
  95. .$record_type{$record->content_type()}."\n";
  96. }
  97. }
  98. }
  99. push @record_list, $record;
  100. #Now figure out what messages are contained within this record
  101. my @messages = TLSProxy::Message->get_messages($server, $record);
  102. push @message_list, @messages;
  103. $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len);
  104. $recnum++;
  105. }
  106. return (\@record_list, \@message_list, $partial);
  107. }
  108. sub clear
  109. {
  110. $server_encrypting = 0;
  111. $client_encrypting = 0;
  112. }
  113. #Class level accessors
  114. sub server_encrypting
  115. {
  116. my $class = shift;
  117. if (@_) {
  118. $server_encrypting = shift;
  119. }
  120. return $server_encrypting;
  121. }
  122. sub client_encrypting
  123. {
  124. my $class = shift;
  125. if (@_) {
  126. $client_encrypting= shift;
  127. }
  128. return $client_encrypting;
  129. }
  130. #Enable/Disable Encrypt-then-MAC
  131. sub etm
  132. {
  133. my $class = shift;
  134. if (@_) {
  135. $etm = shift;
  136. }
  137. return $etm;
  138. }
  139. sub new
  140. {
  141. my $class = shift;
  142. my ($flight,
  143. $content_type,
  144. $version,
  145. $len,
  146. $sslv2,
  147. $len_real,
  148. $decrypt_len,
  149. $data,
  150. $decrypt_data) = @_;
  151. my $self = {
  152. flight => $flight,
  153. content_type => $content_type,
  154. version => $version,
  155. len => $len,
  156. sslv2 => $sslv2,
  157. len_real => $len_real,
  158. decrypt_len => $decrypt_len,
  159. data => $data,
  160. decrypt_data => $decrypt_data,
  161. orig_decrypt_data => $decrypt_data,
  162. sent => 0,
  163. encrypted => 0,
  164. outer_content_type => RT_APPLICATION_DATA
  165. };
  166. return bless $self, $class;
  167. }
  168. #Decrypt using encrypt-then-MAC
  169. sub decryptETM
  170. {
  171. my ($self) = shift;
  172. my $data = $self->data;
  173. if($self->version >= VERS_TLS_1_1()) {
  174. #TLS1.1+ has an explicit IV. Throw it away
  175. $data = substr($data, 16);
  176. }
  177. #Throw away the MAC (assumes MAC is 20 bytes for now. FIXME)
  178. $data = substr($data, 0, length($data) - 20);
  179. #Find out what the padding byte is
  180. my $padval = unpack("C", substr($data, length($data) - 1));
  181. #Throw away the padding
  182. $data = substr($data, 0, length($data) - ($padval + 1));
  183. $self->decrypt_data($data);
  184. $self->decrypt_len(length($data));
  185. return $data;
  186. }
  187. #Standard decrypt
  188. sub decrypt()
  189. {
  190. my ($self) = shift;
  191. my $mactaglen = 20;
  192. my $data = $self->data;
  193. #Throw away any IVs
  194. if (TLSProxy::Proxy->is_tls13()) {
  195. #A TLS1.3 client, when processing the server's initial flight, could
  196. #respond with either an encrypted or an unencrypted alert.
  197. if ($self->content_type() == RT_ALERT) {
  198. #TODO(TLS1.3): Eventually it is sufficient just to check the record
  199. #content type. If an alert is encrypted it will have a record
  200. #content type of application data. However we haven't done the
  201. #record layer changes yet, so it's a bit more complicated. For now
  202. #we will additionally check if the data length is 2 (1 byte for
  203. #alert level, 1 byte for alert description). If it is, then this is
  204. #an unencrypted alert, so don't try to decrypt
  205. return $data if (length($data) == 2);
  206. }
  207. $mactaglen = 16;
  208. } elsif ($self->version >= VERS_TLS_1_1()) {
  209. #16 bytes for a standard IV
  210. $data = substr($data, 16);
  211. #Find out what the padding byte is
  212. my $padval = unpack("C", substr($data, length($data) - 1));
  213. #Throw away the padding
  214. $data = substr($data, 0, length($data) - ($padval + 1));
  215. }
  216. #Throw away the MAC or TAG
  217. $data = substr($data, 0, length($data) - $mactaglen);
  218. if (TLSProxy::Proxy->is_tls13()) {
  219. #Get the content type
  220. my $content_type = unpack("C", substr($data, length($data) - 1));
  221. $self->content_type($content_type);
  222. $data = substr($data, 0, length($data) - 1);
  223. }
  224. $self->decrypt_data($data);
  225. $self->decrypt_len(length($data));
  226. return $data;
  227. }
  228. #Reconstruct the on-the-wire record representation
  229. sub reconstruct_record
  230. {
  231. my $self = shift;
  232. my $server = shift;
  233. my $data;
  234. #We only replay the records in the same direction
  235. if ($self->{sent} || ($self->flight & 1) != $server) {
  236. return "";
  237. }
  238. $self->{sent} = 1;
  239. if ($self->sslv2) {
  240. $data = pack('n', $self->len | 0x8000);
  241. } else {
  242. if (TLSProxy::Proxy->is_tls13() && $self->encrypted) {
  243. $data = pack('Cnn', $self->outer_content_type, $self->version,
  244. $self->len);
  245. } else {
  246. $data = pack('Cnn', $self->content_type, $self->version,
  247. $self->len);
  248. }
  249. }
  250. $data .= $self->data;
  251. return $data;
  252. }
  253. #Read only accessors
  254. sub flight
  255. {
  256. my $self = shift;
  257. return $self->{flight};
  258. }
  259. sub sslv2
  260. {
  261. my $self = shift;
  262. return $self->{sslv2};
  263. }
  264. sub len_real
  265. {
  266. my $self = shift;
  267. return $self->{len_real};
  268. }
  269. sub orig_decrypt_data
  270. {
  271. my $self = shift;
  272. return $self->{orig_decrypt_data};
  273. }
  274. #Read/write accessors
  275. sub decrypt_len
  276. {
  277. my $self = shift;
  278. if (@_) {
  279. $self->{decrypt_len} = shift;
  280. }
  281. return $self->{decrypt_len};
  282. }
  283. sub data
  284. {
  285. my $self = shift;
  286. if (@_) {
  287. $self->{data} = shift;
  288. }
  289. return $self->{data};
  290. }
  291. sub decrypt_data
  292. {
  293. my $self = shift;
  294. if (@_) {
  295. $self->{decrypt_data} = shift;
  296. }
  297. return $self->{decrypt_data};
  298. }
  299. sub len
  300. {
  301. my $self = shift;
  302. if (@_) {
  303. $self->{len} = shift;
  304. }
  305. return $self->{len};
  306. }
  307. sub version
  308. {
  309. my $self = shift;
  310. if (@_) {
  311. $self->{version} = shift;
  312. }
  313. return $self->{version};
  314. }
  315. sub content_type
  316. {
  317. my $self = shift;
  318. if (@_) {
  319. $self->{content_type} = shift;
  320. }
  321. return $self->{content_type};
  322. }
  323. sub encrypted
  324. {
  325. my $self = shift;
  326. if (@_) {
  327. $self->{encrypted} = shift;
  328. }
  329. return $self->{encrypted};
  330. }
  331. sub outer_content_type
  332. {
  333. my $self = shift;
  334. if (@_) {
  335. $self->{outer_content_type} = shift;
  336. }
  337. return $self->{outer_content_type};
  338. }
  339. sub is_fatal_alert
  340. {
  341. my $self = shift;
  342. my $server = shift;
  343. if (($self->{flight} & 1) == $server
  344. && $self->{content_type} == TLSProxy::Record::RT_ALERT) {
  345. my ($level, $alert) = unpack('CC', $self->decrypt_data);
  346. return $alert if ($level == 2);
  347. }
  348. return 0;
  349. }
  350. 1;