s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / lib / crypto / test_gkdi.c
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 static void test_password_based_on_key_id(void **state)
39 {
40         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         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         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         uint8_t out[GMSA_PASSWORD_NULL_TERMINATED_LEN];
87         TALLOC_CTX *mem_ctx = NULL;
88
89         mem_ctx = talloc_new(NULL);
90         assert_non_null(mem_ctx);
91
92         {
93                 /* An arbitrary GKID. */
94                 const struct Gkid gkid = {362, 0, 23};
95                 /* An arbitrary time in the past. */
96                 const NTTIME current_nt_time = 133524411756072082;
97                 struct dom_sid account_sid;
98                 NTSTATUS status;
99                 bool ok;
100
101                 ok = dom_sid_parse(
102                         "S-1-5-21-4119591868-3001629103-3445594911-48026",
103                         &account_sid);
104                 assert_true(ok);
105
106                 /* Derive a password from the root key. */
107                 status = gmsa_password_based_on_key_id(mem_ctx,
108                                                        gkid,
109                                                        current_nt_time,
110                                                        &root_key,
111                                                        &account_sid,
112                                                        out);
113                 assert_true(NT_STATUS_IS_OK(status));
114                 assert_memory_equal(expected, out, GMSA_PASSWORD_LEN);
115         }
116
117         {
118                 uint64_t query_interval = 0;
119                 uint64_t unchanged_interval = 0;
120                 const struct MANAGEDPASSWORD_BLOB managed_pwd = {
121                         .passwords = {
122                                 .current = out,
123                                 .query_interval = &query_interval,
124                                 .unchanged_interval = &unchanged_interval}};
125                 DATA_BLOB packed_blob = {};
126                 enum ndr_err_code err;
127
128                 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                 assert_int_equal(NDR_ERR_SUCCESS, err);
134         }
135
136         talloc_free(mem_ctx);
137 }
138
139 static void assert_gkid_equal(const struct Gkid g1, const struct Gkid g2)
140 {
141         assert_int_equal(g1.l0_idx, g2.l0_idx);
142         assert_int_equal(g1.l1_idx, g2.l1_idx);
143         assert_int_equal(g1.l2_idx, g2.l2_idx);
144 }
145
146 static void test_gkdi_rollover_interval(void **state)
147 {
148         NTTIME interval;
149         bool ok;
150
151         ok = gkdi_rollover_interval(0, &interval);
152         assert_true(ok);
153         assert_int_equal(0, interval);
154
155         ok = gkdi_rollover_interval(1, &interval);
156         assert_true(ok);
157         assert_int_equal(UINT64_C(720000000000), interval);
158
159         ok = gkdi_rollover_interval(2, &interval);
160         assert_true(ok);
161         assert_int_equal(UINT64_C(1440000000000), interval);
162
163         ok = gkdi_rollover_interval(3, &interval);
164         assert_true(ok);
165         assert_int_equal(UINT64_C(2520000000000), interval);
166
167         ok = gkdi_rollover_interval(4, &interval);
168         assert_true(ok);
169         assert_int_equal(UINT64_C(3240000000000), interval);
170
171         ok = gkdi_rollover_interval(5, &interval);
172         assert_true(ok);
173         assert_int_equal(UINT64_C(4320000000000), interval);
174
175         ok = gkdi_rollover_interval(-1, &interval);
176         assert_false(ok);
177
178         ok = gkdi_rollover_interval(-2, &interval);
179         assert_false(ok);
180
181         ok = gkdi_rollover_interval(10675199, &interval);
182         assert_true(ok);
183         assert_int_equal(UINT64_C(9223371720000000000), interval);
184
185         ok = gkdi_rollover_interval(-10675198, &interval);
186         assert_false(ok);
187
188         ok = gkdi_rollover_interval(10675200, &interval);
189         assert_true(ok);
190         assert_int_equal(UINT64_C(9223372800000000000), interval);
191
192         ok = gkdi_rollover_interval(-10675199, &interval);
193         assert_false(ok);
194
195         ok = gkdi_rollover_interval(21350398, &interval);
196         /*
197          * If we accepted this high of an interval, the result would be
198          * 18446743800000000000.
199          */
200         assert_false(ok);
201
202         ok = gkdi_rollover_interval(-21350397, &interval);
203         assert_false(ok);
204
205         ok = gkdi_rollover_interval(21350399, &interval);
206         assert_false(ok); /* too large to be represented */
207
208         ok = gkdi_rollover_interval(-21350398, &interval);
209         assert_false(ok); /* too small to be represented */
210 }
211
212 static void assert_get_interval_id(const NTTIME time,
213                                    const struct Gkid expected_gkid)
214 {
215         {
216                 const bool valid = gkid_is_valid(expected_gkid);
217                 assert_true(valid);
218         }
219
220         {
221                 const struct Gkid interval_id = gkdi_get_interval_id(time);
222                 assert_gkid_equal(expected_gkid, interval_id);
223         }
224 }
225
226 static void test_get_interval_id(void **state)
227 {
228         assert_get_interval_id(0, Gkid(0, 0, 0));
229
230         assert_get_interval_id(gkdi_key_cycle_duration - 1, Gkid(0, 0, 0));
231
232         assert_get_interval_id(gkdi_key_cycle_duration, Gkid(0, 0, 1));
233
234         assert_get_interval_id(27 * gkdi_key_cycle_duration, Gkid(0, 0, 27));
235
236         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         assert_get_interval_id(gkdi_l2_key_iteration * gkdi_key_cycle_duration,
241                                Gkid(0, 1, 0));
242
243         assert_get_interval_id(17 * gkdi_l2_key_iteration *
244                                        gkdi_key_cycle_duration,
245                                Gkid(0, 17, 0));
246
247         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         assert_get_interval_id(gkdi_l1_key_iteration * gkdi_l2_key_iteration *
253                                        gkdi_key_cycle_duration,
254                                Gkid(1, 0, 0));
255
256         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         assert_get_interval_id(INT64_MAX, Gkid(25019, 31, 29));
262
263         assert_get_interval_id(UINT64_MAX, Gkid(50039, 31, 27));
264 }
265
266 static void test_get_key_start_time(void **state)
267 {
268         NTTIME start_time = 0;
269         bool ok;
270
271         /* Try passing an invalid GKID. */
272         ok = gkdi_get_key_start_time(invalid_gkid, &start_time);
273         assert_false(ok);
274
275         /* Try passing an L1 GKID rather than an L2 GKID. */
276         ok = gkdi_get_key_start_time(Gkid(0, 0, -1), &start_time);
277         assert_false(ok);
278
279         /* Test some L2 GKIDs. */
280
281         ok = gkdi_get_key_start_time(Gkid(0, 0, 0), &start_time);
282         assert_true(ok);
283         assert_int_equal(0, start_time);
284
285         ok = gkdi_get_key_start_time(Gkid(0, 0, 1), &start_time);
286         assert_true(ok);
287         assert_int_equal(gkdi_key_cycle_duration, start_time);
288
289         ok = gkdi_get_key_start_time(Gkid(123, 18, 2), &start_time);
290         assert_true(ok);
291         assert_int_equal(126530 * gkdi_key_cycle_duration, start_time);
292
293         ok = gkdi_get_key_start_time(Gkid(25019, 31, 29), &start_time);
294         assert_true(ok);
295         assert_int_equal(25620477 * gkdi_key_cycle_duration, start_time);
296
297         ok = gkdi_get_key_start_time(Gkid(25019, 31, 30), &start_time);
298         assert_true(ok);
299         assert_int_equal(UINT64_C(25620478) * gkdi_key_cycle_duration,
300                          start_time);
301
302         ok = gkdi_get_key_start_time(Gkid(50039, 31, 27), &start_time);
303         assert_true(ok);
304         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         ok = gkdi_get_key_start_time(Gkid(50039, 31, 28), &start_time);
313         assert_false(ok);
314
315         ok = gkdi_get_key_start_time(Gkid(INT32_MAX, 31, 31), &start_time);
316         assert_false(ok);
317 }
318
319 int main(int argc, char *argv[])
320 {
321         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         if (argc == 2) {
329                 cmocka_set_test_filter(argv[1]);
330         }
331         cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
332         return cmocka_run_group_tests(tests, NULL, NULL);
333 }