#!/usr/bin/env python3 # Unix SMB/CIFS implementation. # Copyright (C) Catalyst.Net Ltd 2023 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import sys import os sys.path.insert(0, "bin/python") os.environ["PYTHONUNBUFFERED"] = "1" from samba.dcerpc import gkdi, misc from samba.ndr import ndr_pack, ndr_unpack import samba.tests def utf16_encoded_len(s: str) -> int: """Return the number of bytes required to encode a string as null‐terminated UTF‐16.""" if "\x00" in s: raise ValueError("string contains an embedded null") return len(s.encode("utf-16-le")) + 2 class KeyEnvelopeTests(samba.tests.TestCase): key_envelope_blob = ( b"\x01\x00\x00\x00KDSK\x02\x00\x00\x00j\x01\x00\x00\x01\x00\x00\x00" b"\x0e\x00\x00\x001\"\x92\x9d'\xaf;\xb7\x10V\xae\xb1\x8e\xec\xa7\x1a" b"\x00\x00\x00\x00\x18\x00\x00\x00\x18\x00\x00\x00e\x00x\x00a\x00m\x00" b"p\x00l\x00e\x00.\x00c\x00o\x00m\x00\x00\x00e\x00x\x00a\x00m\x00p\x00l\x00" b"e\x00.\x00c\x00o\x00m\x00\x00\x00" ) root_key_id = misc.GUID("9d922231-af27-b73b-1056-aeb18eeca71a") domain_name = "example.com" forest_name = "example.com" def test_unpack(self): """Unpack a GKDI Key Envelope blob and check its fields.""" envelope = ndr_unpack(gkdi.KeyEnvelope, self.key_envelope_blob) self.assertEqual(1, envelope.version) self.assertEqual(int.from_bytes(b"KDSK", byteorder="little"), envelope.magic) self.assertEqual(gkdi.ENVELOPE_FLAG_KEY_MAY_ENCRYPT_NEW_DATA, envelope.flags) self.assertEqual(362, envelope.l0_index) self.assertEqual(1, envelope.l1_index) self.assertEqual(14, envelope.l2_index) self.assertEqual(self.root_key_id, envelope.root_key_id) self.assertEqual(0, envelope.additional_info_len) self.assertFalse(envelope.additional_info) self.assertEqual(self.domain_name, envelope.domain_name) self.assertEqual(utf16_encoded_len(self.domain_name), envelope.domain_name_len) self.assertEqual(self.forest_name, envelope.forest_name) self.assertEqual(utf16_encoded_len(self.forest_name), envelope.forest_name_len) def test_pack(self): """Create a GKDI Key Envelope object and test that it packs to the blob we expect.""" envelope = gkdi.KeyEnvelope() envelope.version = 1 envelope.flags = gkdi.ENVELOPE_FLAG_KEY_MAY_ENCRYPT_NEW_DATA envelope.l0_index = 362 envelope.l1_index = 1 envelope.l2_index = 14 envelope.root_key_id = self.root_key_id envelope.additional_info = [] envelope.additional_info_len = 0 envelope.domain_name = self.domain_name envelope.forest_name = self.forest_name self.assertEqual(self.key_envelope_blob, ndr_pack(envelope)) class GroupKeyEnvelopeTests(samba.tests.TestCase): group_key_envelope_blob = ( b"\x01\x00\x00\x00KDSK\x00\x00\x00\x00j\x01\x00\x00\x01\x00\x00\x00" b"\x0e\x00\x00\x00\x8c\xc4\x8c\xdevp\x94\x97\x05m\x897{Z\x80R&\x00\x00\x00" b"\x1e\x00\x00\x00\x06\x00\x00\x00\x0c\x02\x00\x00\x00\x02\x00\x00" b"\x00\x08\x00\x00@\x00\x00\x00@\x00\x00\x00\x18\x00\x00\x00\x18\x00\x00\x00" b"S\x00P\x008\x000\x000\x00_\x001\x000\x008\x00_\x00C\x00T\x00R\x00_\x00" b"H\x00M\x00A\x00C\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0e\x00" b"\x00\x00\x00\x00\x00\x00S\x00H\x00A\x005\x001\x002\x00\x00\x00D\x00H\x00" b"\x00\x00\x0c\x02\x00\x00DHPM\x00\x01\x00\x00\x87\xa8\xe6\x1d\xb4\xb6" b"f<\xff\xbb\xd1\x9ce\x19Y\x99\x8c\xee\xf6\x08f\r\xd0\xf2],\xee\xd4C^" b";\x00\xe0\r\xf8\xf1\xd6\x19W\xd4\xfa\xf7\xdfEa\xb2\xaa0\x16\xc3\xd9\x114\t" b"o\xaa;\xf4)m\x83\x0e\x9a| \x9e\x0cd\x97Qz\xbdZ\x8a\x9d0k\xcfg\xed\x91\xf9" b'\xe6r[GX\xc0"\xe0\xb1\xefBu\xbf{l[\xfc\x11\xd4_\x90\x88\xb9A\xf5N\xb1\xe5' b"\x9b\xb8\xbc9\xa0\xbf\x120\x7f\\O\xdbp\xc5\x81\xb2?v\xb6:\xca\xe1\xca\xa6" b"\xb7\x90-RRg5H\x8a\x0e\xf1