Update the TLSv1.3 version indicator for draft-19
[openssl.git] / util / TLSProxy / Record.pm
index a4e7adcf8248698472a8b7d17f955145b532d8fa..358c1ce63ffab5948605facb7d977729a9e59caf 100644 (file)
@@ -11,8 +11,8 @@ use TLSProxy::Proxy;
 
 package TLSProxy::Record;
 
-my $server_ccs_seen = 0;
-my $client_ccs_seen = 0;
+my $server_encrypting = 0;
+my $client_encrypting = 0;
 my $etm = 0;
 
 use constant TLS_RECORD_HEADER_LENGTH => 5;
@@ -35,12 +35,14 @@ my %record_type = (
 );
 
 use constant {
-    VERS_TLS_1_3 => 772,
-    VERS_TLS_1_2 => 771,
-    VERS_TLS_1_1 => 770,
-    VERS_TLS_1_0 => 769,
-    VERS_SSL_3_0 => 768,
-    VERS_SSL_LT_3_0 => 767
+    VERS_TLS_1_4 => 0x0305,
+    VERS_TLS_1_3_DRAFT => 0x7f13,
+    VERS_TLS_1_3 => 0x0304,
+    VERS_TLS_1_2 => 0x0303,
+    VERS_TLS_1_1 => 0x0302,
+    VERS_TLS_1_0 => 0x0301,
+    VERS_SSL_3_0 => 0x0300,
+    VERS_SSL_LT_3_0 => 0x02ff
 };
 
 my %tls_version = (
@@ -107,13 +109,19 @@ sub get_records
                 substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real)
             );
 
-            if (($server && $server_ccs_seen)
-                     || (!$server && $client_ccs_seen)) {
-                if ($version != VERS_TLS_1_3() && $etm) {
+            if (($server && $server_encrypting)
+                     || (!$server && $client_encrypting)) {
+                if (!TLSProxy::Proxy->is_tls13() && $etm) {
                     $record->decryptETM();
                 } else {
                     $record->decrypt();
                 }
+                $record->encrypted(1);
+            }
+
+            if (TLSProxy::Proxy->is_tls13()) {
+                print "  Inner content type: "
+                      .$record_type{$record->content_type()}."\n";
             }
 
             push @record_list, $record;
@@ -132,26 +140,26 @@ sub get_records
 
 sub clear
 {
-    $server_ccs_seen = 0;
-    $client_ccs_seen = 0;
+    $server_encrypting = 0;
+    $client_encrypting = 0;
 }
 
 #Class level accessors
-sub server_ccs_seen
+sub server_encrypting
 {
     my $class = shift;
     if (@_) {
-      $server_ccs_seen = shift;
+      $server_encrypting = shift;
     }
-    return $server_ccs_seen;
+    return $server_encrypting;
 }
-sub client_ccs_seen
+sub client_encrypting
 {
     my $class = shift;
     if (@_) {
-      $client_ccs_seen = shift;
+      $client_encrypting= shift;
     }
-    return $client_ccs_seen;
+    return $client_encrypting;
 }
 #Enable/Disable Encrypt-then-MAC
 sub etm
@@ -186,7 +194,9 @@ sub new
         decrypt_len => $decrypt_len,
         data => $data,
         decrypt_data => $decrypt_data,
-        orig_decrypt_data => $decrypt_data
+        orig_decrypt_data => $decrypt_data,
+        encrypted => 0,
+        outer_content_type => RT_APPLICATION_DATA
     };
 
     return bless $self, $class;
@@ -227,9 +237,19 @@ sub decrypt()
     my $data = $self->data;
 
     #Throw away any IVs
-    if ($self->version >= VERS_TLS_1_3()) {
-        #8 bytes for a GCM IV
-        $data = substr($data, 8);
+    if (TLSProxy::Proxy->is_tls13()) {
+        #A TLS1.3 client, when processing the server's initial flight, could
+        #respond with either an encrypted or an unencrypted alert.
+        if ($self->content_type() == RT_ALERT) {
+            #TODO(TLS1.3): Eventually it is sufficient just to check the record
+            #content type. If an alert is encrypted it will have a record
+            #content type of application data. However we haven't done the
+            #record layer changes yet, so it's a bit more complicated. For now
+            #we will additionally check if the data length is 2 (1 byte for
+            #alert level, 1 byte for alert description). If it is, then this is
+            #an unecrypted alert, so don't try to decrypt
+            return $data if (length($data) == 2);
+        }
         $mactaglen = 16;
     } elsif ($self->version >= VERS_TLS_1_1()) {
         #16 bytes for a standard IV
@@ -245,6 +265,13 @@ sub decrypt()
     #Throw away the MAC or TAG
     $data = substr($data, 0, length($data) - $mactaglen);
 
+    if (TLSProxy::Proxy->is_tls13()) {
+        #Get the content type
+        my $content_type = unpack("C", substr($data, length($data) - 1));
+        $self->content_type($content_type);
+        $data = substr($data, 0, length($data) - 1);
+    }
+
     $self->decrypt_data($data);
     $self->decrypt_len(length($data));
 
@@ -255,15 +282,29 @@ sub decrypt()
 sub reconstruct_record
 {
     my $self = shift;
+    my $server = shift;
     my $data;
+    my $tls13_enc = 0;
 
     if ($self->sslv2) {
         $data = pack('n', $self->len | 0x8000);
     } else {
-        $data = pack('Cnn', $self->content_type, $self->version, $self->len);
+        if (TLSProxy::Proxy->is_tls13() && $self->encrypted) {
+            $data = pack('Cnn', $self->outer_content_type, $self->version,
+                         $self->len + 1);
+            $tls13_enc = 1;
+        } else {
+            $data = pack('Cnn', $self->content_type, $self->version,
+                         $self->len);
+        }
+
     }
     $data .= $self->data;
 
+    if ($tls13_enc) {
+        $data .= pack('C', $self->content_type);
+    }
+
     return $data;
 }
 
@@ -273,11 +314,6 @@ sub flight
     my $self = shift;
     return $self->{flight};
 }
-sub content_type
-{
-    my $self = shift;
-    return $self->{content_type};
-}
 sub sslv2
 {
     my $self = shift;
@@ -335,4 +371,28 @@ sub version
     }
     return $self->{version};
 }
+sub content_type
+{
+    my $self = shift;
+    if (@_) {
+      $self->{content_type} = shift;
+    }
+    return $self->{content_type};
+}
+sub encrypted
+{
+    my $self = shift;
+    if (@_) {
+      $self->{encrypted} = shift;
+    }
+    return $self->{encrypted};
+}
+sub outer_content_type
+{
+    my $self = shift;
+    if (@_) {
+      $self->{outer_content_type} = shift;
+    }
+    return $self->{outer_content_type};
+}
 1;