ClientHello.pm 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # Copyright 2016-2024 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. package TLSProxy::ClientHello;
  9. use TLSProxy::Record;
  10. use vars '@ISA';
  11. push @ISA, 'TLSProxy::Message';
  12. sub new
  13. {
  14. my $class = shift;
  15. my ($isdtls,
  16. $server,
  17. $msgseq,
  18. $msgfrag,
  19. $msgfragoffs,
  20. $data,
  21. $records,
  22. $startoffset,
  23. $message_frag_lens) = @_;
  24. my $self = $class->SUPER::new(
  25. $isdtls,
  26. $server,
  27. TLSProxy::Message::MT_CLIENT_HELLO,
  28. $msgseq,
  29. $msgfrag,
  30. $msgfragoffs,
  31. $data,
  32. $records,
  33. $startoffset,
  34. $message_frag_lens);
  35. $self->{isdtls} = $isdtls;
  36. $self->{client_version} = 0;
  37. $self->{random} = [];
  38. $self->{session_id_len} = 0;
  39. $self->{session} = "";
  40. $self->{legacy_cookie_len} = 0; #DTLS only
  41. $self->{legacy_cookie} = ""; #DTLS only
  42. $self->{ciphersuite_len} = 0;
  43. $self->{ciphersuites} = [];
  44. $self->{comp_meth_len} = 0;
  45. $self->{comp_meths} = [];
  46. $self->{extensions_len} = 0;
  47. $self->{extension_data} = "";
  48. return $self;
  49. }
  50. sub parse
  51. {
  52. my $self = shift;
  53. my $ptr = 2;
  54. my ($client_version) = unpack('n', $self->data);
  55. my $random = substr($self->data, $ptr, 32);
  56. $ptr += 32;
  57. my $session_id_len = unpack('C', substr($self->data, $ptr));
  58. $ptr++;
  59. my $session = substr($self->data, $ptr, $session_id_len);
  60. $ptr += $session_id_len;
  61. my $legacy_cookie_len = 0;
  62. my $legacy_cookie = "";
  63. if($self->{isdtls}) {
  64. $legacy_cookie_len = unpack('C', substr($self->data, $ptr));
  65. $ptr++;
  66. $legacy_cookie = substr($self->data, $ptr, $legacy_cookie_len);
  67. $ptr += $legacy_cookie_len;
  68. }
  69. my $ciphersuite_len = unpack('n', substr($self->data, $ptr));
  70. $ptr += 2;
  71. my @ciphersuites = unpack('n*', substr($self->data, $ptr,
  72. $ciphersuite_len));
  73. $ptr += $ciphersuite_len;
  74. my $comp_meth_len = unpack('C', substr($self->data, $ptr));
  75. $ptr++;
  76. my @comp_meths = unpack('C*', substr($self->data, $ptr, $comp_meth_len));
  77. $ptr += $comp_meth_len;
  78. my $extensions_len = unpack('n', substr($self->data, $ptr));
  79. $ptr += 2;
  80. #For now we just deal with this as a block of data. In the future we will
  81. #want to parse this
  82. my $extension_data = substr($self->data, $ptr);
  83. if (length($extension_data) != $extensions_len) {
  84. die "Invalid extension length\n";
  85. }
  86. my %extensions = ();
  87. while (length($extension_data) >= 4) {
  88. my ($type, $size) = unpack("nn", $extension_data);
  89. my $extdata = substr($extension_data, 4, $size);
  90. $extension_data = substr($extension_data, 4 + $size);
  91. $extensions{$type} = $extdata;
  92. }
  93. $self->client_version($client_version);
  94. $self->random($random);
  95. $self->session_id_len($session_id_len);
  96. $self->session($session);
  97. $self->legacy_cookie_len($legacy_cookie_len);
  98. $self->legacy_cookie($legacy_cookie);
  99. $self->ciphersuite_len($ciphersuite_len);
  100. $self->ciphersuites(\@ciphersuites);
  101. $self->comp_meth_len($comp_meth_len);
  102. $self->comp_meths(\@comp_meths);
  103. $self->extensions_len($extensions_len);
  104. $self->extension_data(\%extensions);
  105. $self->process_extensions();
  106. print " Client Version:".$TLSProxy::Record::tls_version{$client_version}."\n";
  107. print " Session ID Len:".$session_id_len."\n";
  108. if($self->{isdtls}) {
  109. print " Legacy Cookie Len:".$legacy_cookie_len."\n";
  110. }
  111. print " Ciphersuite len:".$ciphersuite_len."\n";
  112. print " Compression Method Len:".$comp_meth_len."\n";
  113. print " Extensions Len:".$extensions_len."\n";
  114. }
  115. #Perform any actions necessary based on the extensions we've seen
  116. sub process_extensions
  117. {
  118. my $self = shift;
  119. my %extensions = %{$self->extension_data};
  120. #Clear any state from a previous run
  121. TLSProxy::Record->etm(0);
  122. if (exists $extensions{TLSProxy::Message::EXT_ENCRYPT_THEN_MAC}) {
  123. TLSProxy::Record->etm(1);
  124. }
  125. }
  126. sub extension_contents
  127. {
  128. my $self = shift;
  129. my $key = shift;
  130. my $extension = "";
  131. my $extdata = ${$self->extension_data}{$key};
  132. $extension .= pack("n", $key);
  133. $extension .= pack("n", length($extdata));
  134. $extension .= $extdata;
  135. return $extension;
  136. }
  137. #Reconstruct the on-the-wire message data following changes
  138. sub set_message_contents
  139. {
  140. my $self = shift;
  141. my $data;
  142. my $extensions = "";
  143. $data = pack('n', $self->client_version);
  144. $data .= $self->random;
  145. $data .= pack('C', $self->session_id_len);
  146. $data .= $self->session;
  147. if($self->{isdtls}){
  148. $data .= pack('C', $self->legacy_cookie_len);
  149. if($self->legacy_cookie_len > 0) {
  150. $data .= $self->legacy_cookie;
  151. }
  152. }
  153. $data .= pack('n', $self->ciphersuite_len);
  154. $data .= pack("n*", @{$self->ciphersuites});
  155. $data .= pack('C', $self->comp_meth_len);
  156. $data .= pack("C*", @{$self->comp_meths});
  157. foreach my $key (keys %{$self->extension_data}) {
  158. next if ($key == TLSProxy::Message::EXT_PSK);
  159. $extensions .= $self->extension_contents($key);
  160. #Add extension twice if we are duplicating that extension
  161. $extensions .= $self->extension_contents($key) if ($key == $self->dupext);
  162. }
  163. #PSK extension always goes last...
  164. if (defined ${$self->extension_data}{TLSProxy::Message::EXT_PSK}) {
  165. $extensions .= $self->extension_contents(TLSProxy::Message::EXT_PSK);
  166. }
  167. #unless we have EXT_FORCE_LAST
  168. if (defined ${$self->extension_data}{TLSProxy::Message::EXT_FORCE_LAST}) {
  169. $extensions .= $self->extension_contents(TLSProxy::Message::EXT_FORCE_LAST);
  170. }
  171. $data .= pack('n', length($extensions));
  172. $data .= $extensions;
  173. $self->data($data);
  174. }
  175. #Read/write accessors
  176. sub client_version
  177. {
  178. my $self = shift;
  179. if (@_) {
  180. $self->{client_version} = shift;
  181. }
  182. return $self->{client_version};
  183. }
  184. sub random
  185. {
  186. my $self = shift;
  187. if (@_) {
  188. $self->{random} = shift;
  189. }
  190. return $self->{random};
  191. }
  192. sub session_id_len
  193. {
  194. my $self = shift;
  195. if (@_) {
  196. $self->{session_id_len} = shift;
  197. }
  198. return $self->{session_id_len};
  199. }
  200. sub session
  201. {
  202. my $self = shift;
  203. if (@_) {
  204. $self->{session} = shift;
  205. }
  206. return $self->{session};
  207. }
  208. sub legacy_cookie_len
  209. {
  210. my $self = shift;
  211. if (@_) {
  212. $self->{legacy_cookie_len} = shift;
  213. }
  214. return $self->{legacy_cookie_len};
  215. }
  216. sub legacy_cookie
  217. {
  218. my $self = shift;
  219. if (@_) {
  220. $self->{legacy_cookie} = shift;
  221. }
  222. return $self->{legacy_cookie};
  223. }
  224. sub ciphersuite_len
  225. {
  226. my $self = shift;
  227. if (@_) {
  228. $self->{ciphersuite_len} = shift;
  229. }
  230. return $self->{ciphersuite_len};
  231. }
  232. sub ciphersuites
  233. {
  234. my $self = shift;
  235. if (@_) {
  236. $self->{ciphersuites} = shift;
  237. }
  238. return $self->{ciphersuites};
  239. }
  240. sub comp_meth_len
  241. {
  242. my $self = shift;
  243. if (@_) {
  244. $self->{comp_meth_len} = shift;
  245. }
  246. return $self->{comp_meth_len};
  247. }
  248. sub comp_meths
  249. {
  250. my $self = shift;
  251. if (@_) {
  252. $self->{comp_meths} = shift;
  253. }
  254. return $self->{comp_meths};
  255. }
  256. sub extensions_len
  257. {
  258. my $self = shift;
  259. if (@_) {
  260. $self->{extensions_len} = shift;
  261. }
  262. return $self->{extensions_len};
  263. }
  264. sub extension_data
  265. {
  266. my $self = shift;
  267. if (@_) {
  268. $self->{extension_data} = shift;
  269. }
  270. return $self->{extension_data};
  271. }
  272. sub set_extension
  273. {
  274. my ($self, $ext_type, $ext_data) = @_;
  275. $self->{extension_data}{$ext_type} = $ext_data;
  276. }
  277. sub delete_extension
  278. {
  279. my ($self, $ext_type) = @_;
  280. delete $self->{extension_data}{$ext_type};
  281. }
  282. 1;