diff mbox series

[cifs-utils] smbinfo: add support for new key dump ioctl

Message ID 20210521152940.23072-1-aaptel@suse.com
State New
Headers show
Series [cifs-utils] smbinfo: add support for new key dump ioctl | expand

Commit Message

Aurélien Aptel May 21, 2021, 3:29 p.m. UTC
From: Aurelien Aptel <aaptel@suse.com>

* try new one first, fall back on old one otherwise => retrocompatible
* use better cipher descriptions

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
---
 smbinfo | 79 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 63 insertions(+), 16 deletions(-)

Comments

Pavel Shilovsky July 8, 2021, 11:14 p.m. UTC | #1
пт, 21 мая 2021 г. в 08:29, Aurélien Aptel <aaptel@suse.com>:
>
> From: Aurelien Aptel <aaptel@suse.com>
>
> * try new one first, fall back on old one otherwise => retrocompatible
> * use better cipher descriptions
>
> Signed-off-by: Aurelien Aptel <aaptel@suse.com>
> ---
>  smbinfo | 79 +++++++++++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 63 insertions(+), 16 deletions(-)
>
> diff --git a/smbinfo b/smbinfo
> index b96fdbc..73c5bb3 100755
> --- a/smbinfo
> +++ b/smbinfo
> @@ -34,6 +34,7 @@ VERBOSE = False
>  CIFS_QUERY_INFO          = 0xc018cf07
>  CIFS_ENUMERATE_SNAPSHOTS = 0x800ccf06
>  CIFS_DUMP_KEY            = 0xc03acf08
> +CIFS_DUMP_FULL_KEY       = 0xc011cf0a
>
>  # large enough input buffer length
>  INPUT_BUFFER_LENGTH = 16384
> @@ -192,9 +193,11 @@ ACE_FLAGS = [
>  ]
>
>  CIPHER_TYPES = [
> -    (0x00, "SMB3.0 CCM encryption"),
> -    (0x01, "CCM encryption"),
> -    (0x02, "GCM encryption"),
> +    (0x00, "AES-128-CCM"),
> +    (0x01, "AES-128-CCM"),
> +    (0x02, "AES-128-GCM"),
> +    (0x03, "AES-256-CCM"),
> +    (0x04, "AES-256-GCM"),
>  ]
>
>  def main():
> @@ -799,35 +802,79 @@ class KeyDebugInfoStruct:
>      def __init__(self):
>          self.suid = bytearray()
>          self.cipher = 0
> -        self.auth_key = bytearray()
> +        self.session_key = bytearray()
>          self.enc_key = bytearray()
>          self.dec_key = bytearray()
>
>      def ioctl(self, fd):
>          buf = bytearray()
>          buf.extend(struct.pack("= 8s H 16s 16s 16s", self.suid, self.cipher,
> -                               self.auth_key, self.enc_key, self.dec_key))
> +                               self.session_key, self.enc_key, self.dec_key))
>          fcntl.ioctl(fd, CIFS_DUMP_KEY, buf, True)
> -        (self.suid, self.cipher, self.auth_key,
> +        (self.suid, self.cipher, self.session_key,
>           self.enc_key, self.dec_key) = struct.unpack_from('= 8s H 16s 16s 16s', buf, 0)
>
> +class FullKeyDebugInfoStruct:
> +    def __init__(self):
> +        # lets pick something large to be future proof
> +        # 17 + 3*32 would be strict minimum as of linux 5.13
> +        self.in_size = 1024
> +        self.suid = bytearray()
> +        self.cipher = 0
> +        self.session_key_len = 0
> +        self.server_in_key_len = 0
> +        self.server_out_key_len = 0
> +
> +    def ioctl(self, fd):
> +        fmt = "= I 8s H B B B"
> +        size = struct.calcsize(fmt)
> +        buf = bytearray()
> +        buf.extend(struct.pack(fmt, self.in_size, self.suid, self.cipher,
> +                               self.session_key_len, self.server_in_key_len, self.server_out_key_len))
> +        buf.extend(bytearray(self.in_size-size))
> +        fcntl.ioctl(fd, CIFS_DUMP_FULL_KEY, buf, True)
> +        (self.in_size, self.suid, self.cipher,
> +         self.session_key_len, self.server_in_key_len,
> +         self.server_out_key_len) = struct.unpack_from(fmt, buf, 0)
> +
> +        end = size
> +        self.session_key = buf[end:end+self.session_key_len]
> +        end += self.session_key_len
> +        self.server_in_key = buf[end:end+self.server_in_key_len]
> +        end += self.server_in_key_len
> +        self.server_out_key = buf[end:end+self.server_out_key_len]
> +
>  def bytes_to_hex(buf):
>      return " ".join(["%02x"%x for x in buf])
>
>  def cmd_keys(args):
> -    kd = KeyDebugInfoStruct()
> +    fd = os.open(args.file, os.O_RDONLY)
> +    kd = FullKeyDebugInfoStruct()
> +
>      try:
> -        fd = os.open(args.file, os.O_RDONLY)
> +        # try new call first
>          kd.ioctl(fd)
>      except Exception as e:
> -        print("syscall failed: %s"%e)
> -        return False
> -
> -    print("Session Id: %s"%bytes_to_hex(kd.suid))
> -    print("Cipher: %s"%type_to_str(kd.cipher, CIPHER_TYPES, verbose=True))
> -    print("Session Key: %s"%bytes_to_hex(kd.auth_key))
> -    print("Encryption key: %s"%bytes_to_hex(kd.enc_key))
> -    print("Decryption key: %s"%bytes_to_hex(kd.dec_key))
> +        # new failed, try old call
> +        kd = KeyDebugInfoStruct()
> +        try:
> +            kd.ioctl(fd)
> +        except Exception as e:
> +            # both new and old call failed
> +            print("syscall failed: %s"%e)
> +            return False
> +        print("Session Id: %s"%bytes_to_hex(kd.suid))
> +        print("Cipher: %s"%type_to_str(kd.cipher, CIPHER_TYPES, verbose=True))
> +        print("Session Key: %s"%bytes_to_hex(kd.session_key))
> +        print("Encryption key: %s"%bytes_to_hex(kd.enc_key))
> +        print("Decryption key: %s"%bytes_to_hex(kd.dec_key))
> +    else:
> +        # no exception, new call succeeded
> +        print("Session Id: %s"%bytes_to_hex(kd.suid))
> +        print("Cipher: %s"%type_to_str(kd.cipher, CIPHER_TYPES, verbose=True))
> +        print("Session Key: %s"%bytes_to_hex(kd.session_key))
> +        print("ServerIn  Key: %s"%bytes_to_hex(kd.server_in_key))
> +        print("ServerOut key: %s"%bytes_to_hex(kd.server_out_key))
>
>  if __name__ == '__main__':
>      main()
> --
> 2.31.1
>

Merged. Thanks!
--
Best regards,
Pavel Shilovsky
diff mbox series

Patch

diff --git a/smbinfo b/smbinfo
index b96fdbc..73c5bb3 100755
--- a/smbinfo
+++ b/smbinfo
@@ -34,6 +34,7 @@  VERBOSE = False
 CIFS_QUERY_INFO          = 0xc018cf07
 CIFS_ENUMERATE_SNAPSHOTS = 0x800ccf06
 CIFS_DUMP_KEY            = 0xc03acf08
+CIFS_DUMP_FULL_KEY       = 0xc011cf0a
 
 # large enough input buffer length
 INPUT_BUFFER_LENGTH = 16384
@@ -192,9 +193,11 @@  ACE_FLAGS = [
 ]
 
 CIPHER_TYPES = [
-    (0x00, "SMB3.0 CCM encryption"),
-    (0x01, "CCM encryption"),
-    (0x02, "GCM encryption"),
+    (0x00, "AES-128-CCM"),
+    (0x01, "AES-128-CCM"),
+    (0x02, "AES-128-GCM"),
+    (0x03, "AES-256-CCM"),
+    (0x04, "AES-256-GCM"),
 ]
 
 def main():
@@ -799,35 +802,79 @@  class KeyDebugInfoStruct:
     def __init__(self):
         self.suid = bytearray()
         self.cipher = 0
-        self.auth_key = bytearray()
+        self.session_key = bytearray()
         self.enc_key = bytearray()
         self.dec_key = bytearray()
 
     def ioctl(self, fd):
         buf = bytearray()
         buf.extend(struct.pack("= 8s H 16s 16s 16s", self.suid, self.cipher,
-                               self.auth_key, self.enc_key, self.dec_key))
+                               self.session_key, self.enc_key, self.dec_key))
         fcntl.ioctl(fd, CIFS_DUMP_KEY, buf, True)
-        (self.suid, self.cipher, self.auth_key,
+        (self.suid, self.cipher, self.session_key,
          self.enc_key, self.dec_key) = struct.unpack_from('= 8s H 16s 16s 16s', buf, 0)
 
+class FullKeyDebugInfoStruct:
+    def __init__(self):
+        # lets pick something large to be future proof
+        # 17 + 3*32 would be strict minimum as of linux 5.13
+        self.in_size = 1024
+        self.suid = bytearray()
+        self.cipher = 0
+        self.session_key_len = 0
+        self.server_in_key_len = 0
+        self.server_out_key_len = 0
+
+    def ioctl(self, fd):
+        fmt = "= I 8s H B B B"
+        size = struct.calcsize(fmt)
+        buf = bytearray()
+        buf.extend(struct.pack(fmt, self.in_size, self.suid, self.cipher,
+                               self.session_key_len, self.server_in_key_len, self.server_out_key_len))
+        buf.extend(bytearray(self.in_size-size))
+        fcntl.ioctl(fd, CIFS_DUMP_FULL_KEY, buf, True)
+        (self.in_size, self.suid, self.cipher,
+         self.session_key_len, self.server_in_key_len,
+         self.server_out_key_len) = struct.unpack_from(fmt, buf, 0)
+
+        end = size
+        self.session_key = buf[end:end+self.session_key_len]
+        end += self.session_key_len
+        self.server_in_key = buf[end:end+self.server_in_key_len]
+        end += self.server_in_key_len
+        self.server_out_key = buf[end:end+self.server_out_key_len]
+
 def bytes_to_hex(buf):
     return " ".join(["%02x"%x for x in buf])
 
 def cmd_keys(args):
-    kd = KeyDebugInfoStruct()
+    fd = os.open(args.file, os.O_RDONLY)
+    kd = FullKeyDebugInfoStruct()
+
     try:
-        fd = os.open(args.file, os.O_RDONLY)
+        # try new call first
         kd.ioctl(fd)
     except Exception as e:
-        print("syscall failed: %s"%e)
-        return False
-
-    print("Session Id: %s"%bytes_to_hex(kd.suid))
-    print("Cipher: %s"%type_to_str(kd.cipher, CIPHER_TYPES, verbose=True))
-    print("Session Key: %s"%bytes_to_hex(kd.auth_key))
-    print("Encryption key: %s"%bytes_to_hex(kd.enc_key))
-    print("Decryption key: %s"%bytes_to_hex(kd.dec_key))
+        # new failed, try old call
+        kd = KeyDebugInfoStruct()
+        try:
+            kd.ioctl(fd)
+        except Exception as e:
+            # both new and old call failed
+            print("syscall failed: %s"%e)
+            return False
+        print("Session Id: %s"%bytes_to_hex(kd.suid))
+        print("Cipher: %s"%type_to_str(kd.cipher, CIPHER_TYPES, verbose=True))
+        print("Session Key: %s"%bytes_to_hex(kd.session_key))
+        print("Encryption key: %s"%bytes_to_hex(kd.enc_key))
+        print("Decryption key: %s"%bytes_to_hex(kd.dec_key))
+    else:
+        # no exception, new call succeeded
+        print("Session Id: %s"%bytes_to_hex(kd.suid))
+        print("Cipher: %s"%type_to_str(kd.cipher, CIPHER_TYPES, verbose=True))
+        print("Session Key: %s"%bytes_to_hex(kd.session_key))
+        print("ServerIn  Key: %s"%bytes_to_hex(kd.server_in_key))
+        print("ServerOut key: %s"%bytes_to_hex(kd.server_out_key))
 
 if __name__ == '__main__':
     main()