2
0

Message.pm 18 KB

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