1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00
samba-mirror/python/samba/tests/krb5/gkdi_tests.py
Jo Sutton 1381581334 tests/gkdi: Change ‘current_gkid’ parameter to ‘current_time’
Signed-off-by: Jo Sutton <josutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2024-04-16 03:58:31 +00:00

747 lines
26 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 <https://www.gnu.org/licenses/>.
#
import sys
import os
sys.path.insert(0, "bin/python")
os.environ["PYTHONUNBUFFERED"] = "1"
import secrets
from typing import ClassVar, Optional
from samba.dcerpc import gkdi, misc
from samba.gkdi import (
Algorithm,
Gkid,
KEY_CYCLE_DURATION,
KEY_LEN_BYTES,
MAX_CLOCK_SKEW,
NtTime,
NtTimeDelta,
SeedKeyPair,
)
from samba.hresult import HRES_E_INVALIDARG, HRES_NTE_BAD_KEY, HRES_NTE_NO_KEY
from samba.nt_time import timedelta_from_nt_time_delta
from samba.tests.gkdi import GetKeyError, GkdiBaseTest, ROOT_KEY_START_TIME
from samba.tests.krb5.kdc_base_test import KDCBaseTest
class GkdiKdcBaseTest(GkdiBaseTest, KDCBaseTest):
def new_root_key(self, *args, **kwargs) -> misc.GUID:
samdb = self.get_samdb()
domain_dn = self.get_server_dn(samdb)
return self.create_root_key(samdb, domain_dn, *args, **kwargs)
def gkdi_conn(self) -> gkdi.gkdi:
# The seed keys used by Group Managed Service Accounts correspond to the
# Enterprise DCs SID (S-1-5-9); as such they can be retrieved only by
# server accounts.
return self.gkdi_connect(
self.dc_host,
self.get_lp(),
self.get_cached_creds(account_type=self.AccountType.SERVER),
)
def check_rpc_get_key(
self, root_key_id: Optional[misc.GUID], gkid: Gkid
) -> SeedKeyPair:
got_key_pair = self.rpc_get_key(
self.gkdi_conn(), self.gmsa_sd, root_key_id, gkid
)
expected_key_pair = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
gkid,
root_key_id_hint=got_key_pair.root_key_id if root_key_id is None else None,
)
self.assertEqual(
got_key_pair.root_key_id,
expected_key_pair.root_key_id,
"root key IDs must match",
)
self.assertEqual(got_key_pair, expected_key_pair, "key pairs must match")
return got_key_pair
class GkdiExplicitRootKeyTests(GkdiKdcBaseTest):
def test_current_l0_idx(self):
"""Request a key with the current L0 index. This index is regularly
incremented every 427 days or so."""
root_key_id = self.new_root_key()
# It actually doesnt matter what we specify for the L1 and L2 indices.
# Well get the same result regardless — they just cannot specify a key
# from the future.
current_gkid = self.current_gkid(self.get_samdb())
key = self.check_rpc_get_key(root_key_id, current_gkid)
self.assertEqual(current_gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
def test_previous_l0_idx(self):
"""Request a key with a previous L0 index."""
root_key_id = self.new_root_key(use_start_time=ROOT_KEY_START_TIME)
# It actually doesnt matter what we specify for the L1 and L2 indices.
# Well get the same result regardless.
previous_l0_idx = self.current_gkid(self.get_samdb()).l0_idx - 1
key = self.check_rpc_get_key(root_key_id, Gkid(previous_l0_idx, 0, 0))
# Expect to get an L1 seed key.
self.assertIsNotNone(key.l1_key)
self.assertIsNone(key.l2_key)
self.assertEqual(Gkid(previous_l0_idx, 31, 31), key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
def test_algorithm_sha1(self):
"""Test with the SHA1 algorithm."""
key = self.check_rpc_get_key(
self.new_root_key(hash_algorithm=Algorithm.SHA1),
self.current_gkid(self.get_samdb()),
)
self.assertIs(Algorithm.SHA1, key.hash_algorithm)
def test_algorithm_sha256(self):
"""Test with the SHA256 algorithm."""
key = self.check_rpc_get_key(
self.new_root_key(hash_algorithm=Algorithm.SHA256),
self.current_gkid(self.get_samdb()),
)
self.assertIs(Algorithm.SHA256, key.hash_algorithm)
def test_algorithm_sha384(self):
"""Test with the SHA384 algorithm."""
key = self.check_rpc_get_key(
self.new_root_key(hash_algorithm=Algorithm.SHA384),
self.current_gkid(self.get_samdb()),
)
self.assertIs(Algorithm.SHA384, key.hash_algorithm)
def test_algorithm_sha512(self):
"""Test with the SHA512 algorithm."""
key = self.check_rpc_get_key(
self.new_root_key(hash_algorithm=Algorithm.SHA512),
self.current_gkid(self.get_samdb()),
)
self.assertIs(Algorithm.SHA512, key.hash_algorithm)
def test_algorithm_none(self):
"""Test without a specified algorithm."""
key = self.check_rpc_get_key(
self.new_root_key(hash_algorithm=None),
self.current_gkid(self.get_samdb()),
)
self.assertIs(Algorithm.SHA256, key.hash_algorithm)
def test_future_key(self):
"""Try to request a key from the future."""
root_key_id = self.new_root_key(use_start_time=ROOT_KEY_START_TIME)
future_gkid = self.current_gkid(
self.get_samdb(),
offset=timedelta_from_nt_time_delta(
NtTimeDelta(KEY_CYCLE_DURATION + MAX_CLOCK_SKEW)
)
)
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, root_key_id, future_gkid)
self.assertEqual(
HRES_E_INVALIDARG,
err.exception.args[0],
"requesting a key from the future should fail with INVALID_PARAMETER",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, root_key_id, future_gkid)
self.assertEqual(
HRES_E_INVALIDARG,
rpc_err.exception.args[0],
"requesting a key from the future should fail with INVALID_PARAMETER",
)
def test_root_key_use_start_time_zero(self):
"""Attempt to use a root key with an effective time of zero."""
root_key_id = self.new_root_key(use_start_time=NtTime(0))
gkid = self.current_gkid(self.get_samdb())
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_NTE_BAD_KEY,
err.exception.args[0],
"using a root key with an effective time of zero should fail with BAD_KEY",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_NTE_BAD_KEY,
rpc_err.exception.args[0],
"using a root key with an effective time of zero should fail with BAD_KEY",
)
def test_root_key_use_start_time_too_low(self):
"""Attempt to use a root key with an effective time set too low."""
root_key_id = self.new_root_key(use_start_time=NtTime(ROOT_KEY_START_TIME - 1))
gkid = self.current_gkid(self.get_samdb())
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
err.exception.args[0],
"using a root key with too low effective time should fail with"
" INVALID_PARAMETER",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
rpc_err.exception.args[0],
"using a root key with too low effective time should fail with"
" INVALID_PARAMETER",
)
def test_before_valid(self):
"""Attempt to use a key before it is valid."""
gkid = self.current_gkid(self.get_samdb())
valid_start_time = NtTime(
gkid.start_nt_time() + KEY_CYCLE_DURATION + MAX_CLOCK_SKEW
)
# Using a valid root key is allowed.
valid_root_key_id = self.new_root_key(use_start_time=valid_start_time)
self.check_rpc_get_key(valid_root_key_id, gkid)
# But attempting to use a root key that is not yet valid will result in
# an INVALID_PARAMETER error.
invalid_root_key_id = self.new_root_key(use_start_time=valid_start_time + 1)
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, invalid_root_key_id, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
err.exception.args[0],
"using a key before it is valid should fail with INVALID_PARAMETER",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, invalid_root_key_id, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
rpc_err.exception.args[0],
"using a key before it is valid should fail with INVALID_PARAMETER",
)
def test_non_existent_root_key(self):
"""Attempt to use a nonexistent root key."""
root_key_id = misc.GUID(secrets.token_bytes(16))
gkid = self.current_gkid(self.get_samdb())
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_NTE_NO_KEY,
err.exception.args[0],
"using a nonexistent root key should fail with NO_KEY",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_NTE_NO_KEY,
rpc_err.exception.args[0],
"using a nonexistent root key should fail with NO_KEY",
)
def test_root_key_wrong_length(self):
"""Attempt to use a root key that is the wrong length."""
root_key_id = self.new_root_key(data=bytes(KEY_LEN_BYTES // 2))
gkid = self.current_gkid(self.get_samdb())
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_NTE_BAD_KEY,
err.exception.args[0],
"using a root key that is the wrong length should fail with BAD_KEY",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, root_key_id, gkid)
self.assertEqual(
HRES_NTE_BAD_KEY,
rpc_err.exception.args[0],
"using a root key that is the wrong length should fail with BAD_KEY",
)
class GkdiImplicitRootKeyTests(GkdiKdcBaseTest):
_root_key: ClassVar[misc.GUID]
@classmethod
def setUpClass(cls) -> None:
super().setUpClass()
cls._root_key = None
def setUp(self) -> None:
super().setUp()
if self._root_key is None:
# GKDI requires a root key to operate. Creating a root key here
# saves creating one before every test.
#
# We cannot delete this key after the tests have run, as Windows
# might have decided to cache it to be used in subsequent runs. It
# will keep a root key cached even if the corresponding AD object
# has been deleted, leading to various problems later.
cls = type(self)
cls._root_key = self.new_root_key(use_start_time=ROOT_KEY_START_TIME)
def test_l1_seed_key(self):
"""Request a key and expect to receive an L1 seed key."""
gkid = Gkid(300, 0, 31)
key = self.check_rpc_get_key(None, gkid)
# Expect to get an L1 seed key.
self.assertIsNotNone(key.l1_key)
self.assertIsNone(key.l2_key)
self.assertEqual(gkid, key.gkid)
def test_l2_seed_key(self):
"""Request a key and expect to receive an L2 seed key."""
gkid = Gkid(300, 0, 0)
key = self.check_rpc_get_key(None, gkid)
# Expect to get an L2 seed key.
self.assertIsNone(key.l1_key)
self.assertIsNotNone(key.l2_key)
self.assertEqual(gkid, key.gkid)
def test_both_seed_keys(self):
"""Request a key and expect to receive L1 and L2 seed keys."""
gkid = Gkid(300, 1, 0)
key = self.check_rpc_get_key(None, gkid)
# Expect to get both L1 and L2 seed keys.
self.assertIsNotNone(key.l1_key)
self.assertIsNotNone(key.l2_key)
self.assertEqual(gkid, key.gkid)
def test_both_seed_keys_no_hint(self):
"""Request a key, but dont specify root_key_id_hint."""
gkid = Gkid(300, 1, 0)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
None,
gkid,
)
# Expect to get both L1 and L2 seed keys.
self.assertIsNotNone(key.l1_key)
self.assertIsNotNone(key.l2_key)
self.assertEqual(gkid, key.gkid)
def test_request_l0_seed_key(self):
"""Attempt to request an L0 seed key."""
gkid = Gkid.l0_seed_key(300)
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, None, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
err.exception.args[0],
"requesting an L0 seed key should fail with INVALID_PARAMETER",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, None, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
rpc_err.exception.args[0],
"requesting an L0 seed key should fail with INVALID_PARAMETER",
)
def test_request_l1_seed_key(self):
"""Attempt to request an L1 seed key."""
gkid = Gkid.l1_seed_key(300, 0)
with self.assertRaises(GetKeyError) as err:
self.get_key(self.get_samdb(), self.gmsa_sd, None, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
err.exception.args[0],
"requesting an L1 seed key should fail with INVALID_PARAMETER",
)
with self.assertRaises(GetKeyError) as rpc_err:
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, None, gkid)
self.assertEqual(
HRES_E_INVALIDARG,
rpc_err.exception.args[0],
"requesting an L1 seed key should fail with INVALID_PARAMETER",
)
def test_request_default_seed_key(self):
"""Try to make a request with the default GKID."""
gkid = Gkid.default()
self.assertRaises(
NotImplementedError,
self.get_key,
self.get_samdb(),
self.gmsa_sd,
None,
gkid,
)
self.rpc_get_key(self.gkdi_conn(), self.gmsa_sd, None, gkid)
class GkdiSelfTests(GkdiKdcBaseTest):
def test_current_l0_idx_l1_seed_key(self):
"""Request a key with the current L0 index, expecting to receive an L1
seed key."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA512,
guid=misc.GUID("89f70521-9d66-441f-c314-1b462f9b1052"),
data=bytes.fromhex(
"a6ef87dbbbf86b6bbe55750b941f13ca99efe5185e2e2bded5b838d8a0e77647"
"0537e68cae45a7a0f4b1d6c9bf5494c3f879e172e326557cdbb6a56e8799a722"
),
)
current_gkid = Gkid(255, 24, 31)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
Gkid(255, 2, 5),
current_time=current_gkid.start_nt_time(),
)
# Expect to get an L1 seed key.
self.assertEqual(current_gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA512, key.hash_algorithm)
self.assertEqual(
bytes.fromhex(
"bd538a073490f3cf9451c933025de9b22c97eaddaffa94b379e2b919a4bed147"
"5bc67f6a9175b139c69204c57d4300a0141ffe34d12ced84614593b1aa13af1c"
),
key.l1_key,
)
self.assertIsNone(key.l2_key)
def test_current_l0_idx_l2_seed_key(self):
"""Request a key with the current L0 index, expecting to receive an L2
seed key."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA512,
guid=misc.GUID("1a3d6c30-aa81-cb7f-d3fe-80775d135dfe"),
data=bytes.fromhex(
"dfd95be3153a0805c65694e7d284aace5ab0aa493350025eb8dbc6df0b4e9256"
"fb4cbfbe6237ce3732694e2608760076b67082d39abd3c0fedba1b8873645064"
),
)
current_gkid = Gkid(321, 0, 12)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
Gkid(321, 0, 1),
current_time=current_gkid.start_nt_time(),
)
# Expect to get an L2 seed key.
self.assertEqual(current_gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA512, key.hash_algorithm)
self.assertIsNone(key.l1_key)
self.assertEqual(
bytes.fromhex(
"bbbd9376cd16c247ed40f5912d1908218c08f0915bae02fe02cbfb3753bde406"
"f9c553acd95143cf63906a0440e3cf237d2335ae4e4b9cd2d946a71351ebcb7b"
),
key.l2_key,
)
def test_current_l0_idx_both_seed_keys(self):
"""Request a key with the current L0 index, expecting to receive L1 and
L2 seed keys."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA512,
guid=misc.GUID("09de0b38-c743-7abf-44ea-7a3c3e404314"),
data=bytes.fromhex(
"d5912d0eb3bd60e1371b1e525dd83be7fc5baf77018b0dba6bd948b7a98ebe5a"
"f37674332506a46c52c108a62f2a3e89251ad1bde6d539004679c0658853bb68"
),
)
current_gkid = Gkid(123, 21, 0)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
Gkid(123, 2, 1),
current_time=current_gkid.start_nt_time(),
)
# Expect to get both L1 and L2 seed keys.
self.assertEqual(current_gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA512, key.hash_algorithm)
self.assertEqual(
bytes.fromhex(
"b1f7c5896e7dc791d9c0aaf8ca7dbab8c172a4f8b873db488a3c4cbd0f559b11"
"52ffba39d4aff2d9e8aada90b27a3c94a5af996f4b8f584a4f37ccab4d505d3d"
),
key.l1_key,
)
self.assertEqual(
bytes.fromhex(
"133c9bbd20d9227aeb38dfcd3be6bcbfc5983ba37202088ff5c8a70511214506"
"a69c195a8807cd844bcb955e9569c8e4d197759f28577cc126d15f16a7da4ee0"
),
key.l2_key,
)
def test_previous_l0_idx(self):
"""Request a key with a previous L0 index."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA512,
guid=misc.GUID("27136e8f-e093-6fe3-e57f-1d915b102e1c"),
data=bytes.fromhex(
"b41118c60a19cafa5ecf858d1a2a2216527b2daedf386e9d599e42a46add6c7d"
"c93868619761c880ff3674a77c6e5fbf3434d130a9727bb2cd2a2557bdcfc752"
),
)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
Gkid(100, 20, 30),
current_time=Gkid(101, 2, 3).start_nt_time(),
)
# Expect to get an L1 seed key.
self.assertEqual(Gkid(100, 31, 31), key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA512, key.hash_algorithm)
self.assertEqual(
bytes.fromhex(
"935cbdc06198eb28fa44b8d8278f51072c4613999236585041ede8e72d02fe95"
"e3454f046382cbc0a700779b79474dd7e080509d76302d2937407e96e3d3d022"
),
key.l1_key,
)
self.assertIsNone(key.l2_key)
def test_sha1(self):
"""Request a key derived with SHA1."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA1,
guid=misc.GUID("970abad6-fe55-073a-caf1-b801d3f26bd3"),
data=bytes.fromhex(
"3bed03bf0fb7d4013149154f24ca2d59b98db6d588cb1f54eca083855e25eb28"
"d3562a01adc78c4b70e0b72a59515863e7732b853fba02dd7646e63108441211"
),
)
current_gkid = Gkid(1, 2, 3)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
Gkid(1, 1, 1),
current_time=current_gkid.start_nt_time(),
)
# Expect to get both L1 and L2 seed keys.
self.assertEqual(current_gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA1, key.hash_algorithm)
self.assertEqual(
bytes.fromhex(
"576cb68f2e52eb739f817b488c3590d86f1c2c365f3fc9201d9c7fee7494853d"
"58746ee13e48f18aa6fa69f7157de3d07de34e13836792b7c088ffb6914a89c2"
),
key.l1_key,
)
self.assertEqual(
bytes.fromhex(
"3ffb825adaf116b6533207d568a30ed3d3f21c68840941c9456684f9afa11b05"
"6e0c59391b4d88c495d984c3d680029cc5c594630f34179119c1c5acaae5e90e"
),
key.l2_key,
)
def test_sha256(self):
"""Request a key derived with SHA256."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA256,
guid=misc.GUID("45e26207-ed33-dcd5-925a-518a0deef69e"),
data=bytes.fromhex(
"28b5b6503d3c1d24814de781bb7bfce3ef69eed1ce4809372bee2c506270c5f0"
"b5c6df597472623f256c86daa0991e8a11a1705f21b2cfdc0bb9db4ba23246a2"
),
)
current_gkid = Gkid(222, 22, 22)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
Gkid(222, 11, 0),
current_time=current_gkid.start_nt_time(),
)
# Expect to get both L1 and L2 seed keys.
self.assertEqual(current_gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA256, key.hash_algorithm)
self.assertEqual(
bytes.fromhex(
"57aced6e75f83f3af4f879b38b60f090b42e4bfa022fae3e6fd94280b469b0ec"
"15d8b853a870b5fbdf28708cce19273b74a573acbe0deda8ef515db4691e2dcb"
),
key.l1_key,
)
self.assertEqual(
bytes.fromhex(
"752a0879ae2424c0504c7493599f13e588e1bbdc252f83325ad5b1fb91c24c89"
"01d440f3ff9ffba59fcd65bb975732d9f383dd50b898174bb9393e383d25d540"
),
key.l2_key,
)
def test_sha384(self):
"""Request a key derived with SHA384."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA384,
guid=misc.GUID("66e6d9f7-4924-f3fc-fe34-605634d42ebd"),
data=bytes.fromhex(
"23e5ba86cbd88f7b432ee66dbb03bf4eebf401cbfc3df735d4d728b503c87f84"
"3207c6f6153f190dfe85a86cb8d8b74df13b25305981be8d7e29c96ee54c9630"
),
)
current_gkid = Gkid(287, 28, 27)
key = self.get_key(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
Gkid(287, 8, 7),
current_time=current_gkid.start_nt_time(),
)
# Expect to get both L1 and L2 seed keys.
self.assertEqual(current_gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA384, key.hash_algorithm)
self.assertEqual(
bytes.fromhex(
"fabadd7a9a63df57d6832df7a735aebb6e181888b2eaf301a2e4ff9a70246d38"
"ab1d2416325bf3eb726a0267bab4bd950c7291f05ea5f17197ece56992af3eb8"
),
key.l1_key,
)
self.assertEqual(
bytes.fromhex(
"ec1c65634b5694818e1d341da9996db8f2a1ef6a2c776a7126a7ebd18b37a073"
"afdac44c41b167b14e4b872d485bbb6d7b70964215d0e84a2ff142a9d943f205"
),
key.l2_key,
)
def test_derive_key_exact(self):
"""Derive a key at an exact GKID."""
root_key_id = self.new_root_key(
use_start_time=ROOT_KEY_START_TIME,
hash_algorithm=Algorithm.SHA512,
guid=misc.GUID("d95fb06f-5a9c-1829-e20d-27f3f2ecfbeb"),
data=bytes.fromhex(
"489f3531c537774d432d6b97e3bc1f43d2e8c6dc17eb0e4fd9a0870d2f1ebf92"
"e2496668a8b5bd11aea2d32d0aab716f48fe569f5c9b50ff3f9bf5deaea572fb"
),
)
gkid = Gkid(333, 22, 11)
key = self.get_key_exact(
self.get_samdb(),
self.gmsa_sd,
root_key_id,
gkid,
current_time=self.current_nt_time(self.get_samdb()),
)
self.assertEqual(gkid, key.gkid)
self.assertEqual(root_key_id, key.root_key_id)
self.assertEqual(Algorithm.SHA512, key.hash_algorithm)
self.assertEqual(
bytes.fromhex(
"d6ab3b14f4f4c8908aa3464011b39f10a8bfadb9974af90f7d9a9fede2fdc6e5"
"f68a628ec00f9994a3abd8a52ae9e2db4f68e83648311e9d7765f2535515b5e2"
),
key.key,
)
if __name__ == "__main__":
import unittest
unittest.main()