Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * Copyright (C) Catalyst.Net Ltd 2024
5 : *
6 : * This program is free software: you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation, either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <stdarg.h>
21 : #include <stddef.h>
22 : #include <stdint.h>
23 : #include <setjmp.h>
24 : #include <cmocka.h>
25 :
26 : #include "replace.h"
27 : #include <talloc.h>
28 : #include "libcli/util/ntstatus.h"
29 : #include "lib/crypto/gkdi.h"
30 : #include "lib/crypto/gmsa.h"
31 :
32 : #include "librpc/ndr/libndr.h"
33 : #include "librpc/gen_ndr/gmsa.h"
34 : #include "librpc/gen_ndr/ndr_gmsa.h"
35 : #include "lib/util/time.h"
36 : #include "libcli/security/dom_sid.h"
37 :
38 1 : static void test_password_based_on_key_id(void **state)
39 : {
40 1 : static const uint8_t root_key_data[] = {
41 : 152, 203, 215, 84, 113, 216, 118, 177, 81, 128, 50, 160, 148,
42 : 132, 82, 244, 65, 179, 164, 219, 209, 14, 33, 131, 178, 193,
43 : 80, 248, 126, 23, 66, 227, 45, 221, 171, 12, 247, 15, 62,
44 : 179, 164, 217, 123, 179, 106, 118, 228, 74, 12, 2, 241, 229,
45 : 139, 55, 237, 155, 220, 122, 200, 245, 129, 222, 37, 15};
46 1 : static const struct ProvRootKey root_key = {
47 : .version = root_key_version_1,
48 : .id = {.time_low = 0x170e972,
49 : .time_mid = 0xa035,
50 : .time_hi_and_version = 0xaf4c,
51 : .clock_seq = {0x99, 0x3b},
52 : .node = {0xe0, 0x52, 0xd5, 0xbd, 0x12, 0x16}},
53 : .data =
54 : {
55 : .data = discard_const_p(uint8_t, root_key_data),
56 : .length = sizeof root_key_data,
57 : },
58 : .create_time = 0,
59 : .use_start_time = 0,
60 : .domain_id = "example.com",
61 : .kdf_algorithm = {
62 : .id = KDF_ALGORITHM_SP800_108_CTR_HMAC,
63 : .param.sp800_108 = KDF_PARAM_SHA512,
64 : }};
65 1 : static const uint8_t expected[GMSA_PASSWORD_LEN] = {
66 : 114, 92, 31, 204, 138, 249, 1, 76, 192, 65, 52, 248, 247,
67 : 191, 30, 213, 25, 38, 81, 21, 183, 167, 154, 102, 190, 234,
68 : 234, 116, 114, 18, 141, 208, 143, 38, 178, 115, 195, 26, 199,
69 : 214, 176, 229, 128, 160, 147, 249, 245, 67, 165, 191, 192, 78,
70 : 224, 50, 115, 8, 207, 124, 178, 121, 67, 135, 125, 113, 79,
71 : 0, 131, 43, 74, 48, 171, 239, 183, 228, 50, 212, 202, 215,
72 : 188, 182, 94, 127, 117, 217, 91, 17, 90, 80, 158, 176, 204,
73 : 151, 244, 107, 139, 65, 94, 148, 216, 212, 97, 53, 54, 253,
74 : 6, 201, 94, 93, 250, 213, 12, 82, 162, 246, 197, 254, 205,
75 : 8, 19, 153, 66, 72, 60, 167, 28, 65, 39, 218, 147, 82,
76 : 162, 11, 177, 78, 231, 200, 66, 121, 9, 196, 240, 7, 148,
77 : 190, 151, 96, 214, 246, 7, 110, 85, 0, 246, 28, 121, 3,
78 : 61, 212, 204, 101, 153, 121, 100, 91, 65, 28, 225, 241, 123,
79 : 115, 105, 138, 74, 187, 74, 188, 59, 17, 201, 229, 158, 170,
80 : 184, 141, 237, 179, 246, 135, 104, 204, 56, 228, 156, 182, 26,
81 : 90, 151, 147, 25, 142, 47, 172, 183, 165, 222, 240, 95, 63,
82 : 79, 88, 35, 205, 76, 26, 229, 107, 46, 16, 202, 102, 196,
83 : 18, 140, 211, 242, 226, 198, 154, 97, 199, 44, 220, 186, 76,
84 : 215, 54, 196, 44, 140, 145, 252, 99, 229, 179, 74, 150, 154,
85 : 70, 226, 45, 122, 156, 156, 75, 83, 24};
86 1 : uint8_t out[GMSA_PASSWORD_NULL_TERMINATED_LEN];
87 1 : TALLOC_CTX *mem_ctx = NULL;
88 :
89 1 : mem_ctx = talloc_new(NULL);
90 1 : assert_non_null(mem_ctx);
91 :
92 : {
93 : /* An arbitrary GKID. */
94 1 : const struct Gkid gkid = {362, 0, 23};
95 : /* An arbitrary time in the past. */
96 1 : const NTTIME current_nt_time = 133524411756072082;
97 1 : struct dom_sid account_sid;
98 1 : NTSTATUS status;
99 1 : bool ok;
100 :
101 1 : ok = dom_sid_parse(
102 : "S-1-5-21-4119591868-3001629103-3445594911-48026",
103 : &account_sid);
104 1 : assert_true(ok);
105 :
106 : /* Derive a password from the root key. */
107 1 : status = gmsa_password_based_on_key_id(mem_ctx,
108 : gkid,
109 : current_nt_time,
110 : &root_key,
111 : &account_sid,
112 : out);
113 1 : assert_true(NT_STATUS_IS_OK(status));
114 1 : assert_memory_equal(expected, out, GMSA_PASSWORD_LEN);
115 : }
116 :
117 : {
118 1 : uint64_t query_interval = 0;
119 1 : uint64_t unchanged_interval = 0;
120 1 : const struct MANAGEDPASSWORD_BLOB managed_pwd = {
121 : .passwords = {
122 : .current = out,
123 : .query_interval = &query_interval,
124 : .unchanged_interval = &unchanged_interval}};
125 1 : DATA_BLOB packed_blob = {};
126 1 : enum ndr_err_code err;
127 :
128 1 : err = ndr_push_struct_blob(
129 : &packed_blob,
130 : mem_ctx,
131 : &managed_pwd,
132 : (ndr_push_flags_fn_t)ndr_push_MANAGEDPASSWORD_BLOB);
133 1 : assert_int_equal(NDR_ERR_SUCCESS, err);
134 : }
135 :
136 1 : talloc_free(mem_ctx);
137 1 : }
138 :
139 12 : static void assert_gkid_equal(const struct Gkid g1, const struct Gkid g2)
140 : {
141 12 : assert_int_equal(g1.l0_idx, g2.l0_idx);
142 12 : assert_int_equal(g1.l1_idx, g2.l1_idx);
143 12 : assert_int_equal(g1.l2_idx, g2.l2_idx);
144 12 : }
145 :
146 1 : static void test_gkdi_rollover_interval(void **state)
147 : {
148 1 : NTTIME interval;
149 1 : bool ok;
150 :
151 1 : ok = gkdi_rollover_interval(0, &interval);
152 1 : assert_true(ok);
153 1 : assert_int_equal(0, interval);
154 :
155 1 : ok = gkdi_rollover_interval(1, &interval);
156 1 : assert_true(ok);
157 1 : assert_int_equal(UINT64_C(720000000000), interval);
158 :
159 1 : ok = gkdi_rollover_interval(2, &interval);
160 1 : assert_true(ok);
161 1 : assert_int_equal(UINT64_C(1440000000000), interval);
162 :
163 1 : ok = gkdi_rollover_interval(3, &interval);
164 1 : assert_true(ok);
165 1 : assert_int_equal(UINT64_C(2520000000000), interval);
166 :
167 1 : ok = gkdi_rollover_interval(4, &interval);
168 1 : assert_true(ok);
169 1 : assert_int_equal(UINT64_C(3240000000000), interval);
170 :
171 1 : ok = gkdi_rollover_interval(5, &interval);
172 1 : assert_true(ok);
173 1 : assert_int_equal(UINT64_C(4320000000000), interval);
174 :
175 1 : ok = gkdi_rollover_interval(-1, &interval);
176 1 : assert_false(ok);
177 :
178 1 : ok = gkdi_rollover_interval(-2, &interval);
179 1 : assert_false(ok);
180 :
181 1 : ok = gkdi_rollover_interval(10675199, &interval);
182 1 : assert_true(ok);
183 1 : assert_int_equal(UINT64_C(9223371720000000000), interval);
184 :
185 1 : ok = gkdi_rollover_interval(-10675198, &interval);
186 1 : assert_false(ok);
187 :
188 1 : ok = gkdi_rollover_interval(10675200, &interval);
189 1 : assert_true(ok);
190 1 : assert_int_equal(UINT64_C(9223372800000000000), interval);
191 :
192 1 : ok = gkdi_rollover_interval(-10675199, &interval);
193 1 : assert_false(ok);
194 :
195 1 : ok = gkdi_rollover_interval(21350398, &interval);
196 : /*
197 : * If we accepted this high of an interval, the result would be
198 : * 18446743800000000000.
199 : */
200 1 : assert_false(ok);
201 :
202 1 : ok = gkdi_rollover_interval(-21350397, &interval);
203 1 : assert_false(ok);
204 :
205 1 : ok = gkdi_rollover_interval(21350399, &interval);
206 1 : assert_false(ok); /* too large to be represented */
207 :
208 1 : ok = gkdi_rollover_interval(-21350398, &interval);
209 1 : assert_false(ok); /* too small to be represented */
210 1 : }
211 :
212 12 : static void assert_get_interval_id(const NTTIME time,
213 : const struct Gkid expected_gkid)
214 : {
215 : {
216 12 : const bool valid = gkid_is_valid(expected_gkid);
217 12 : assert_true(valid);
218 : }
219 :
220 : {
221 12 : const struct Gkid interval_id = gkdi_get_interval_id(time);
222 12 : assert_gkid_equal(expected_gkid, interval_id);
223 : }
224 12 : }
225 :
226 1 : static void test_get_interval_id(void **state)
227 : {
228 1 : assert_get_interval_id(0, Gkid(0, 0, 0));
229 :
230 1 : assert_get_interval_id(gkdi_key_cycle_duration - 1, Gkid(0, 0, 0));
231 :
232 1 : assert_get_interval_id(gkdi_key_cycle_duration, Gkid(0, 0, 1));
233 :
234 1 : assert_get_interval_id(27 * gkdi_key_cycle_duration, Gkid(0, 0, 27));
235 :
236 1 : assert_get_interval_id((gkdi_l2_key_iteration - 1) *
237 : gkdi_key_cycle_duration,
238 : Gkid(0, 0, gkdi_l2_key_iteration - 1));
239 :
240 1 : assert_get_interval_id(gkdi_l2_key_iteration * gkdi_key_cycle_duration,
241 : Gkid(0, 1, 0));
242 :
243 1 : assert_get_interval_id(17 * gkdi_l2_key_iteration *
244 : gkdi_key_cycle_duration,
245 : Gkid(0, 17, 0));
246 :
247 1 : assert_get_interval_id(((gkdi_l1_key_iteration - 1) *
248 : gkdi_l2_key_iteration +
249 : 3) * gkdi_key_cycle_duration,
250 : Gkid(0, gkdi_l1_key_iteration - 1, 3));
251 :
252 1 : assert_get_interval_id(gkdi_l1_key_iteration * gkdi_l2_key_iteration *
253 : gkdi_key_cycle_duration,
254 : Gkid(1, 0, 0));
255 :
256 1 : assert_get_interval_id(((1234 * gkdi_l1_key_iteration + 8) *
257 : gkdi_l2_key_iteration +
258 : 13) * gkdi_key_cycle_duration,
259 : Gkid(1234, 8, 13));
260 :
261 1 : assert_get_interval_id(INT64_MAX, Gkid(25019, 31, 29));
262 :
263 1 : assert_get_interval_id(UINT64_MAX, Gkid(50039, 31, 27));
264 1 : }
265 :
266 1 : static void test_get_key_start_time(void **state)
267 : {
268 1 : NTTIME start_time = 0;
269 1 : bool ok;
270 :
271 : /* Try passing an invalid GKID. */
272 1 : ok = gkdi_get_key_start_time(invalid_gkid, &start_time);
273 1 : assert_false(ok);
274 :
275 : /* Try passing an L1 GKID rather than an L2 GKID. */
276 1 : ok = gkdi_get_key_start_time(Gkid(0, 0, -1), &start_time);
277 1 : assert_false(ok);
278 :
279 : /* Test some L2 GKIDs. */
280 :
281 1 : ok = gkdi_get_key_start_time(Gkid(0, 0, 0), &start_time);
282 1 : assert_true(ok);
283 1 : assert_int_equal(0, start_time);
284 :
285 1 : ok = gkdi_get_key_start_time(Gkid(0, 0, 1), &start_time);
286 1 : assert_true(ok);
287 1 : assert_int_equal(gkdi_key_cycle_duration, start_time);
288 :
289 1 : ok = gkdi_get_key_start_time(Gkid(123, 18, 2), &start_time);
290 1 : assert_true(ok);
291 1 : assert_int_equal(126530 * gkdi_key_cycle_duration, start_time);
292 :
293 1 : ok = gkdi_get_key_start_time(Gkid(25019, 31, 29), &start_time);
294 1 : assert_true(ok);
295 1 : assert_int_equal(25620477 * gkdi_key_cycle_duration, start_time);
296 :
297 1 : ok = gkdi_get_key_start_time(Gkid(25019, 31, 30), &start_time);
298 1 : assert_true(ok);
299 1 : assert_int_equal(UINT64_C(25620478) * gkdi_key_cycle_duration,
300 : start_time);
301 :
302 1 : ok = gkdi_get_key_start_time(Gkid(50039, 31, 27), &start_time);
303 1 : assert_true(ok);
304 1 : assert_int_equal(UINT64_C(51240955) * gkdi_key_cycle_duration,
305 : start_time);
306 :
307 : /*
308 : * Test GKIDs so high that their start times can’t be represented in
309 : * NTTIME.
310 : */
311 :
312 1 : ok = gkdi_get_key_start_time(Gkid(50039, 31, 28), &start_time);
313 1 : assert_false(ok);
314 :
315 1 : ok = gkdi_get_key_start_time(Gkid(INT32_MAX, 31, 31), &start_time);
316 1 : assert_false(ok);
317 1 : }
318 :
319 1 : int main(int argc, char *argv[])
320 : {
321 1 : const struct CMUnitTest tests[] = {
322 : cmocka_unit_test(test_password_based_on_key_id),
323 : cmocka_unit_test(test_gkdi_rollover_interval),
324 : cmocka_unit_test(test_get_interval_id),
325 : cmocka_unit_test(test_get_key_start_time),
326 : };
327 :
328 1 : if (argc == 2) {
329 0 : cmocka_set_test_filter(argv[1]);
330 : }
331 1 : cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
332 1 : return cmocka_run_group_tests(tests, NULL, NULL);
333 : }
|