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