Message.pm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. # Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
  2. #
  3. # Licensed under the OpenSSL license (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::Message;
  9. use TLSProxy::Alert;
  10. use constant TLS_MESSAGE_HEADER_LENGTH => 4;
  11. #Message types
  12. use constant {
  13. MT_HELLO_REQUEST => 0,
  14. MT_CLIENT_HELLO => 1,
  15. MT_SERVER_HELLO => 2,
  16. MT_NEW_SESSION_TICKET => 4,
  17. MT_ENCRYPTED_EXTENSIONS => 8,
  18. MT_CERTIFICATE => 11,
  19. MT_SERVER_KEY_EXCHANGE => 12,
  20. MT_CERTIFICATE_REQUEST => 13,
  21. MT_SERVER_HELLO_DONE => 14,
  22. MT_CERTIFICATE_VERIFY => 15,
  23. MT_CLIENT_KEY_EXCHANGE => 16,
  24. MT_FINISHED => 20,
  25. MT_CERTIFICATE_STATUS => 22,
  26. MT_NEXT_PROTO => 67
  27. };
  28. #Alert levels
  29. use constant {
  30. AL_LEVEL_WARN => 1,
  31. AL_LEVEL_FATAL => 2
  32. };
  33. #Alert descriptions
  34. use constant {
  35. AL_DESC_CLOSE_NOTIFY => 0,
  36. AL_DESC_UNEXPECTED_MESSAGE => 10,
  37. AL_DESC_ILLEGAL_PARAMETER => 47,
  38. AL_DESC_NO_RENEGOTIATION => 100
  39. };
  40. my %message_type = (
  41. MT_HELLO_REQUEST, "HelloRequest",
  42. MT_CLIENT_HELLO, "ClientHello",
  43. MT_SERVER_HELLO, "ServerHello",
  44. MT_NEW_SESSION_TICKET, "NewSessionTicket",
  45. MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions",
  46. MT_CERTIFICATE, "Certificate",
  47. MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange",
  48. MT_CERTIFICATE_REQUEST, "CertificateRequest",
  49. MT_SERVER_HELLO_DONE, "ServerHelloDone",
  50. MT_CERTIFICATE_VERIFY, "CertificateVerify",
  51. MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange",
  52. MT_FINISHED, "Finished",
  53. MT_CERTIFICATE_STATUS, "CertificateStatus",
  54. MT_NEXT_PROTO, "NextProto"
  55. );
  56. use constant {
  57. EXT_SERVER_NAME => 0,
  58. EXT_MAX_FRAGMENT_LENGTH => 1,
  59. EXT_STATUS_REQUEST => 5,
  60. EXT_SUPPORTED_GROUPS => 10,
  61. EXT_EC_POINT_FORMATS => 11,
  62. EXT_SRP => 12,
  63. EXT_SIG_ALGS => 13,
  64. EXT_USE_SRTP => 14,
  65. EXT_ALPN => 16,
  66. EXT_SCT => 18,
  67. EXT_PADDING => 21,
  68. EXT_ENCRYPT_THEN_MAC => 22,
  69. EXT_EXTENDED_MASTER_SECRET => 23,
  70. EXT_SESSION_TICKET => 35,
  71. EXT_KEY_SHARE => 51,
  72. EXT_PSK => 41,
  73. EXT_SUPPORTED_VERSIONS => 43,
  74. EXT_COOKIE => 44,
  75. EXT_PSK_KEX_MODES => 45,
  76. EXT_POST_HANDSHAKE_AUTH => 49,
  77. EXT_SIG_ALGS_CERT => 50,
  78. EXT_RENEGOTIATE => 65281,
  79. EXT_NPN => 13172,
  80. EXT_CRYPTOPRO_BUG_EXTENSION => 0xfde8,
  81. EXT_UNKNOWN => 0xfffe,
  82. #Unknown extension that should appear last
  83. EXT_FORCE_LAST => 0xffff
  84. };
  85. # SignatureScheme of TLS 1.3 from:
  86. # https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme
  87. # We have to manually grab the SHA224 equivalents from the old registry
  88. use constant {
  89. SIG_ALG_RSA_PKCS1_SHA256 => 0x0401,
  90. SIG_ALG_RSA_PKCS1_SHA384 => 0x0501,
  91. SIG_ALG_RSA_PKCS1_SHA512 => 0x0601,
  92. SIG_ALG_ECDSA_SECP256R1_SHA256 => 0x0403,
  93. SIG_ALG_ECDSA_SECP384R1_SHA384 => 0x0503,
  94. SIG_ALG_ECDSA_SECP521R1_SHA512 => 0x0603,
  95. SIG_ALG_RSA_PSS_RSAE_SHA256 => 0x0804,
  96. SIG_ALG_RSA_PSS_RSAE_SHA384 => 0x0805,
  97. SIG_ALG_RSA_PSS_RSAE_SHA512 => 0x0806,
  98. SIG_ALG_ED25519 => 0x0807,
  99. SIG_ALG_ED448 => 0x0808,
  100. SIG_ALG_RSA_PSS_PSS_SHA256 => 0x0809,
  101. SIG_ALG_RSA_PSS_PSS_SHA384 => 0x080a,
  102. SIG_ALG_RSA_PSS_PSS_SHA512 => 0x080b,
  103. SIG_ALG_RSA_PKCS1_SHA1 => 0x0201,
  104. SIG_ALG_ECDSA_SHA1 => 0x0203,
  105. SIG_ALG_DSA_SHA1 => 0x0202,
  106. SIG_ALG_DSA_SHA256 => 0x0402,
  107. SIG_ALG_DSA_SHA384 => 0x0502,
  108. SIG_ALG_DSA_SHA512 => 0x0602,
  109. OSSL_SIG_ALG_RSA_PKCS1_SHA224 => 0x0301,
  110. OSSL_SIG_ALG_DSA_SHA224 => 0x0302,
  111. OSSL_SIG_ALG_ECDSA_SHA224 => 0x0303
  112. };
  113. use constant {
  114. CIPHER_RSA_WITH_AES_128_CBC_SHA => 0x002f,
  115. CIPHER_DHE_RSA_AES_128_SHA => 0x0033,
  116. CIPHER_ADH_AES_128_SHA => 0x0034,
  117. CIPHER_TLS13_AES_128_GCM_SHA256 => 0x1301,
  118. CIPHER_TLS13_AES_256_GCM_SHA384 => 0x1302
  119. };
  120. use constant {
  121. CLIENT => 0,
  122. SERVER => 1
  123. };
  124. my $payload = "";
  125. my $messlen = -1;
  126. my $mt;
  127. my $startoffset = -1;
  128. my $server = 0;
  129. my $success = 0;
  130. my $end = 0;
  131. my @message_rec_list = ();
  132. my @message_frag_lens = ();
  133. my $ciphersuite = 0;
  134. my $successondata = 0;
  135. my $alert;
  136. sub clear
  137. {
  138. $payload = "";
  139. $messlen = -1;
  140. $startoffset = -1;
  141. $server = 0;
  142. $success = 0;
  143. $end = 0;
  144. $successondata = 0;
  145. @message_rec_list = ();
  146. @message_frag_lens = ();
  147. $alert = undef;
  148. }
  149. #Class method to extract messages from a record
  150. sub get_messages
  151. {
  152. my $class = shift;
  153. my $serverin = shift;
  154. my $record = shift;
  155. my @messages = ();
  156. my $message;
  157. @message_frag_lens = ();
  158. if ($serverin != $server && length($payload) != 0) {
  159. die "Changed peer, but we still have fragment data\n";
  160. }
  161. $server = $serverin;
  162. if ($record->content_type == TLSProxy::Record::RT_CCS) {
  163. if ($payload ne "") {
  164. #We can't handle this yet
  165. die "CCS received before message data complete\n";
  166. }
  167. if (!TLSProxy::Proxy->is_tls13()) {
  168. if ($server) {
  169. TLSProxy::Record->server_encrypting(1);
  170. } else {
  171. TLSProxy::Record->client_encrypting(1);
  172. }
  173. }
  174. } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
  175. if ($record->len == 0 || $record->len_real == 0) {
  176. print " Message truncated\n";
  177. } else {
  178. my $recoffset = 0;
  179. if (length $payload > 0) {
  180. #We are continuing processing a message started in a previous
  181. #record. Add this record to the list associated with this
  182. #message
  183. push @message_rec_list, $record;
  184. if ($messlen <= length($payload)) {
  185. #Shouldn't happen
  186. die "Internal error: invalid messlen: ".$messlen
  187. ." payload length:".length($payload)."\n";
  188. }
  189. if (length($payload) + $record->decrypt_len >= $messlen) {
  190. #We can complete the message with this record
  191. $recoffset = $messlen - length($payload);
  192. $payload .= substr($record->decrypt_data, 0, $recoffset);
  193. push @message_frag_lens, $recoffset;
  194. $message = create_message($server, $mt, $payload,
  195. $startoffset);
  196. push @messages, $message;
  197. $payload = "";
  198. } else {
  199. #This is just part of the total message
  200. $payload .= $record->decrypt_data;
  201. $recoffset = $record->decrypt_len;
  202. push @message_frag_lens, $record->decrypt_len;
  203. }
  204. print " Partial message data read: ".$recoffset." bytes\n";
  205. }
  206. while ($record->decrypt_len > $recoffset) {
  207. #We are at the start of a new message
  208. if ($record->decrypt_len - $recoffset < 4) {
  209. #Whilst technically probably valid we can't cope with this
  210. die "End of record in the middle of a message header\n";
  211. }
  212. @message_rec_list = ($record);
  213. my $lenhi;
  214. my $lenlo;
  215. ($mt, $lenhi, $lenlo) = unpack('CnC',
  216. substr($record->decrypt_data,
  217. $recoffset));
  218. $messlen = ($lenhi << 8) | $lenlo;
  219. print " Message type: $message_type{$mt}\n";
  220. print " Message Length: $messlen\n";
  221. $startoffset = $recoffset;
  222. $recoffset += 4;
  223. $payload = "";
  224. if ($recoffset <= $record->decrypt_len) {
  225. #Some payload data is present in this record
  226. if ($record->decrypt_len - $recoffset >= $messlen) {
  227. #We can complete the message with this record
  228. $payload .= substr($record->decrypt_data, $recoffset,
  229. $messlen);
  230. $recoffset += $messlen;
  231. push @message_frag_lens, $messlen;
  232. $message = create_message($server, $mt, $payload,
  233. $startoffset);
  234. push @messages, $message;
  235. $payload = "";
  236. } else {
  237. #This is just part of the total message
  238. $payload .= substr($record->decrypt_data, $recoffset,
  239. $record->decrypt_len - $recoffset);
  240. $recoffset = $record->decrypt_len;
  241. push @message_frag_lens, $recoffset;
  242. }
  243. }
  244. }
  245. }
  246. } elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) {
  247. print " [ENCRYPTED APPLICATION DATA]\n";
  248. print " [".$record->decrypt_data."]\n";
  249. if ($successondata) {
  250. $success = 1;
  251. $end = 1;
  252. }
  253. } elsif ($record->content_type == TLSProxy::Record::RT_ALERT) {
  254. my ($alertlev, $alertdesc) = unpack('CC', $record->decrypt_data);
  255. print " [$alertlev, $alertdesc]\n";
  256. #A CloseNotify from the client indicates we have finished successfully
  257. #(we assume)
  258. if (!$end && !$server && $alertlev == AL_LEVEL_WARN
  259. && $alertdesc == AL_DESC_CLOSE_NOTIFY) {
  260. $success = 1;
  261. }
  262. #Fatal or close notify alerts end the test
  263. if ($alertlev == AL_LEVEL_FATAL || $alertdesc == AL_DESC_CLOSE_NOTIFY) {
  264. $end = 1;
  265. }
  266. $alert = TLSProxy::Alert->new(
  267. $server,
  268. $record->encrypted,
  269. $alertlev,
  270. $alertdesc);
  271. }
  272. return @messages;
  273. }
  274. #Function to work out which sub-class we need to create and then
  275. #construct it
  276. sub create_message
  277. {
  278. my ($server, $mt, $data, $startoffset) = @_;
  279. my $message;
  280. #We only support ClientHello in this version...needs to be extended for
  281. #others
  282. if ($mt == MT_CLIENT_HELLO) {
  283. $message = TLSProxy::ClientHello->new(
  284. $server,
  285. $data,
  286. [@message_rec_list],
  287. $startoffset,
  288. [@message_frag_lens]
  289. );
  290. $message->parse();
  291. } elsif ($mt == MT_SERVER_HELLO) {
  292. $message = TLSProxy::ServerHello->new(
  293. $server,
  294. $data,
  295. [@message_rec_list],
  296. $startoffset,
  297. [@message_frag_lens]
  298. );
  299. $message->parse();
  300. } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) {
  301. $message = TLSProxy::EncryptedExtensions->new(
  302. $server,
  303. $data,
  304. [@message_rec_list],
  305. $startoffset,
  306. [@message_frag_lens]
  307. );
  308. $message->parse();
  309. } elsif ($mt == MT_CERTIFICATE) {
  310. $message = TLSProxy::Certificate->new(
  311. $server,
  312. $data,
  313. [@message_rec_list],
  314. $startoffset,
  315. [@message_frag_lens]
  316. );
  317. $message->parse();
  318. } elsif ($mt == MT_CERTIFICATE_REQUEST) {
  319. $message = TLSProxy::CertificateRequest->new(
  320. $server,
  321. $data,
  322. [@message_rec_list],
  323. $startoffset,
  324. [@message_frag_lens]
  325. );
  326. $message->parse();
  327. } elsif ($mt == MT_CERTIFICATE_VERIFY) {
  328. $message = TLSProxy::CertificateVerify->new(
  329. $server,
  330. $data,
  331. [@message_rec_list],
  332. $startoffset,
  333. [@message_frag_lens]
  334. );
  335. $message->parse();
  336. } elsif ($mt == MT_SERVER_KEY_EXCHANGE) {
  337. $message = TLSProxy::ServerKeyExchange->new(
  338. $server,
  339. $data,
  340. [@message_rec_list],
  341. $startoffset,
  342. [@message_frag_lens]
  343. );
  344. $message->parse();
  345. } elsif ($mt == MT_NEW_SESSION_TICKET) {
  346. $message = TLSProxy::NewSessionTicket->new(
  347. $server,
  348. $data,
  349. [@message_rec_list],
  350. $startoffset,
  351. [@message_frag_lens]
  352. );
  353. $message->parse();
  354. } else {
  355. #Unknown message type
  356. $message = TLSProxy::Message->new(
  357. $server,
  358. $mt,
  359. $data,
  360. [@message_rec_list],
  361. $startoffset,
  362. [@message_frag_lens]
  363. );
  364. }
  365. return $message;
  366. }
  367. sub end
  368. {
  369. my $class = shift;
  370. return $end;
  371. }
  372. sub success
  373. {
  374. my $class = shift;
  375. return $success;
  376. }
  377. sub fail
  378. {
  379. my $class = shift;
  380. return !$success && $end;
  381. }
  382. sub alert
  383. {
  384. return $alert;
  385. }
  386. sub new
  387. {
  388. my $class = shift;
  389. my ($server,
  390. $mt,
  391. $data,
  392. $records,
  393. $startoffset,
  394. $message_frag_lens) = @_;
  395. my $self = {
  396. server => $server,
  397. data => $data,
  398. records => $records,
  399. mt => $mt,
  400. startoffset => $startoffset,
  401. message_frag_lens => $message_frag_lens,
  402. dupext => -1
  403. };
  404. return bless $self, $class;
  405. }
  406. sub ciphersuite
  407. {
  408. my $class = shift;
  409. if (@_) {
  410. $ciphersuite = shift;
  411. }
  412. return $ciphersuite;
  413. }
  414. #Update all the underlying records with the modified data from this message
  415. #Note: Only supports TLSv1.3 and ETM encryption
  416. sub repack
  417. {
  418. my $self = shift;
  419. my $msgdata;
  420. my $numrecs = $#{$self->records};
  421. $self->set_message_contents();
  422. my $lenhi;
  423. my $lenlo;
  424. $lenlo = length($self->data) & 0xff;
  425. $lenhi = length($self->data) >> 8;
  426. $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data;
  427. if ($numrecs == 0) {
  428. #The message is fully contained within one record
  429. my ($rec) = @{$self->records};
  430. my $recdata = $rec->decrypt_data;
  431. my $old_length;
  432. # We use empty message_frag_lens to indicates that pre-repacking,
  433. # the message wasn't present. The first fragment length doesn't include
  434. # the TLS header, so we need to check and compute the right length.
  435. if (@{$self->message_frag_lens}) {
  436. $old_length = ${$self->message_frag_lens}[0] +
  437. TLS_MESSAGE_HEADER_LENGTH;
  438. } else {
  439. $old_length = 0;
  440. }
  441. my $prefix = substr($recdata, 0, $self->startoffset);
  442. my $suffix = substr($recdata, $self->startoffset + $old_length);
  443. $rec->decrypt_data($prefix.($msgdata).($suffix));
  444. # TODO(openssl-team): don't keep explicit lengths.
  445. # (If a length override is ever needed to construct invalid packets,
  446. # use an explicit override field instead.)
  447. $rec->decrypt_len(length($rec->decrypt_data));
  448. # Only support re-encryption for TLSv1.3 and ETM.
  449. if ($rec->encrypted()) {
  450. if (TLSProxy::Proxy->is_tls13()) {
  451. #Add content type (1 byte) and 16 tag bytes
  452. $rec->data($rec->decrypt_data
  453. .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16));
  454. } elsif ($rec->etm()) {
  455. my $data = $rec->decrypt_data;
  456. #Add padding
  457. my $padval = length($data) % 16;
  458. $padval = 15 - $padval;
  459. for (0..$padval) {
  460. $data .= pack("C", $padval);
  461. }
  462. #Add MAC. Assumed to be 20 bytes
  463. foreach my $macval (0..19) {
  464. $data .= pack("C", $macval);
  465. }
  466. if ($rec->version() >= TLSProxy::Record::VERS_TLS_1_1) {
  467. #Explicit IV
  468. $data = ("\0"x16).$data;
  469. }
  470. $rec->data($data);
  471. } else {
  472. die "Unsupported encryption: No ETM";
  473. }
  474. } else {
  475. $rec->data($rec->decrypt_data);
  476. }
  477. $rec->len(length($rec->data));
  478. #Update the fragment len in case we changed it above
  479. ${$self->message_frag_lens}[0] = length($msgdata)
  480. - TLS_MESSAGE_HEADER_LENGTH;
  481. return;
  482. }
  483. #Note we don't currently support changing a fragmented message length
  484. my $recctr = 0;
  485. my $datadone = 0;
  486. foreach my $rec (@{$self->records}) {
  487. my $recdata = $rec->decrypt_data;
  488. if ($recctr == 0) {
  489. #This is the first record
  490. my $remainlen = length($recdata) - $self->startoffset;
  491. $rec->data(substr($recdata, 0, $self->startoffset)
  492. .substr(($msgdata), 0, $remainlen));
  493. $datadone += $remainlen;
  494. } elsif ($recctr + 1 == $numrecs) {
  495. #This is the last record
  496. $rec->data(substr($msgdata, $datadone));
  497. } else {
  498. #This is a middle record
  499. $rec->data(substr($msgdata, $datadone, length($rec->data)));
  500. $datadone += length($rec->data);
  501. }
  502. $recctr++;
  503. }
  504. }
  505. #To be overridden by sub-classes
  506. sub set_message_contents
  507. {
  508. }
  509. #Read only accessors
  510. sub server
  511. {
  512. my $self = shift;
  513. return $self->{server};
  514. }
  515. #Read/write accessors
  516. sub mt
  517. {
  518. my $self = shift;
  519. if (@_) {
  520. $self->{mt} = shift;
  521. }
  522. return $self->{mt};
  523. }
  524. sub data
  525. {
  526. my $self = shift;
  527. if (@_) {
  528. $self->{data} = shift;
  529. }
  530. return $self->{data};
  531. }
  532. sub records
  533. {
  534. my $self = shift;
  535. if (@_) {
  536. $self->{records} = shift;
  537. }
  538. return $self->{records};
  539. }
  540. sub startoffset
  541. {
  542. my $self = shift;
  543. if (@_) {
  544. $self->{startoffset} = shift;
  545. }
  546. return $self->{startoffset};
  547. }
  548. sub message_frag_lens
  549. {
  550. my $self = shift;
  551. if (@_) {
  552. $self->{message_frag_lens} = shift;
  553. }
  554. return $self->{message_frag_lens};
  555. }
  556. sub encoded_length
  557. {
  558. my $self = shift;
  559. return TLS_MESSAGE_HEADER_LENGTH + length($self->data);
  560. }
  561. sub dupext
  562. {
  563. my $self = shift;
  564. if (@_) {
  565. $self->{dupext} = shift;
  566. }
  567. return $self->{dupext};
  568. }
  569. sub successondata
  570. {
  571. my $class = shift;
  572. if (@_) {
  573. $successondata = shift;
  574. }
  575. return $successondata;
  576. }
  577. 1;