ctdb-server: Remove duplicate logic
[samba4-gss.git] / source4 / dsdb / gmsa / gkdi.c
blob7acc1b4996e1c59980e58fc0772ee0900e58a259
1 /*
2 Unix SMB/CIFS implementation.
3 Group Key Distribution Protocol functions
5 Copyright (C) Catalyst.Net Ltd 2024
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include <ldb.h>
23 #include <ldb_errors.h>
24 #include <ldb_module.h>
25 #include "lib/crypto/gkdi.h"
26 #include "lib/util/data_blob.h"
27 #include "lib/util/samba_util.h"
28 #include "lib/util/util_str_hex.h"
29 #include "librpc/ndr/libndr.h"
30 #include "dsdb/gmsa/gkdi.h"
31 #include "dsdb/samdb/ldb_modules/util.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "dsdb/common/proto.h"
34 #include "librpc/gen_ndr/gkdi.h"
35 #include "librpc/gen_ndr/ndr_gkdi.h"
37 NTSTATUS gkdi_root_key_from_msg(TALLOC_CTX *mem_ctx,
38 const struct GUID root_key_id,
39 const struct ldb_message *const msg,
40 const struct ProvRootKey **const root_key_out)
42 NTSTATUS status = NT_STATUS_OK;
43 struct ldb_val root_key_data = {};
44 struct KdfAlgorithm kdf_algorithm = {};
46 const int version = ldb_msg_find_attr_as_int(msg, "msKds-Version", 0);
47 const NTTIME create_time = samdb_result_nttime(msg,
48 "msKds-CreateTime",
49 0);
50 const NTTIME use_start_time = samdb_result_nttime(msg,
51 "msKds-UseStartTime",
52 0);
53 const char *domain_id = ldb_msg_find_attr_as_string(msg,
54 "msKds-DomainID",
55 NULL);
58 const struct ldb_val *root_key_val = ldb_msg_find_ldb_val(
59 msg, "msKds-RootKeyData");
60 if (root_key_val != NULL) {
61 root_key_data = *root_key_val;
66 const char *algorithm_id = ldb_msg_find_attr_as_string(
67 msg, "msKds-KDFAlgorithmID", NULL);
68 const struct ldb_val *kdf_param_val = ldb_msg_find_ldb_val(
69 msg, "msKds-KDFParam");
70 status = kdf_algorithm_from_params(algorithm_id,
71 kdf_param_val,
72 &kdf_algorithm);
73 if (!NT_STATUS_IS_OK(status)) {
74 goto out;
78 status = ProvRootKey(mem_ctx,
79 root_key_id,
80 version,
81 root_key_data,
82 create_time,
83 use_start_time,
84 domain_id,
85 kdf_algorithm,
86 root_key_out);
87 if (!NT_STATUS_IS_OK(status)) {
88 goto out;
91 out:
92 return status;
96 * Calculate an appropriate useStartTime for a root key created at
97 * ‘current_time’.
99 * This function goes unused.
101 NTTIME gkdi_root_key_use_start_time(const NTTIME current_time)
103 const NTTIME start_time = gkdi_get_interval_start_time(current_time);
105 return start_time + gkdi_key_cycle_duration + gkdi_max_clock_skew;
108 static int gkdi_create_root_key(TALLOC_CTX *mem_ctx,
109 struct ldb_context *const ldb,
110 const NTTIME current_time,
111 const NTTIME use_start_time,
112 struct GUID *const root_key_id_out,
113 struct ldb_dn **const root_key_dn_out)
115 TALLOC_CTX *tmp_ctx = NULL;
116 struct GUID root_key_id;
117 struct ldb_dn *server_config_dn = NULL;
118 struct ldb_result *server_config_res = NULL;
119 struct ldb_message *server_config_msg = NULL;
120 uint64_t server_config_version;
121 const struct ldb_val *server_config_version_val = NULL;
122 const char *server_config_KDFAlgorithmID = NULL;
123 const struct ldb_val *server_config_KDFParam = NULL;
124 const char *server_config_SecretAgreementAlgorithmID = NULL;
125 const struct ldb_val *server_config_SecretAgreementParam = NULL;
126 uint64_t server_config_PublicKeyLength;
127 uint64_t server_config_PrivateKeyLength;
128 struct KdfAlgorithm kdf_algorithm;
129 DATA_BLOB kdf_parameters_blob = data_blob_null;
130 struct ldb_message *add_msg = NULL;
131 uint8_t root_key_data[GKDI_KEY_LEN];
132 NTSTATUS status = NT_STATUS_OK;
133 int ret = LDB_SUCCESS;
135 static const char *server_config_attrs[] = {
136 "msKds-Version",
137 "msKds-KDFAlgorithmID",
138 "msKds-SecretAgreementAlgorithmID",
139 "msKds-SecretAgreementParam",
140 "msKds-PublicKeyLength",
141 "msKds-PrivateKeyLength",
142 "msKds-KDFParam",
143 NULL
146 *root_key_dn_out = NULL;
148 tmp_ctx = talloc_new(mem_ctx);
149 if (tmp_ctx == NULL) {
150 ret = ldb_oom(ldb);
151 goto out;
154 server_config_dn = samdb_configuration_dn(ldb,
155 mem_ctx,
156 "CN=Group Key Distribution Service Server Configuration,"
157 "CN=Server Configuration,"
158 "CN=Group Key Distribution Service,"
159 "CN=Services");
160 if (server_config_dn == NULL) {
161 ret = ldb_oom(ldb);
162 goto out;
165 ret = dsdb_search_dn(ldb,
166 tmp_ctx,
167 &server_config_res,
168 server_config_dn,
169 server_config_attrs,
172 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
173 ldb_asprintf_errstring(ldb, "Unable to create new GKDI root key as we do not have a GKDI server configuration at %s",
174 ldb_dn_get_linearized(server_config_dn));
175 goto out;
178 if (ret != LDB_SUCCESS) {
179 goto out;
182 server_config_msg = server_config_res->msgs[0];
184 server_config_version_val
185 = ldb_msg_find_ldb_val(server_config_msg,
186 "msKds-Version");
187 server_config_version
188 = ldb_msg_find_attr_as_uint64(server_config_msg,
189 "msKds-Version",
192 /* These values we assert on, so we don't create keys we can't use */
193 if (server_config_version_val == NULL) {
195 * The systemMustContain msKds-Version attribute
196 * cannot be read, so if absent we just fail with
197 * permission denied, as that is all that this can
198 * mean
200 ldb_asprintf_errstring(ldb,
201 "Unwilling to create new GKDI root key as "
202 "msKds-Version is not readable on %s\n",
203 ldb_dn_get_linearized(server_config_dn));
204 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
205 goto out;
206 } else if (server_config_version != 1) {
207 ldb_asprintf_errstring(ldb,
208 "Unwilling to create new GKDI root key as "
209 "%s has msKds-Version = %s "
210 "and we only support version 1\n",
211 ldb_dn_get_linearized(server_config_dn),
212 ldb_msg_find_attr_as_string(server_config_msg, "msKds-Version", "(missing)"));
213 ret = LDB_ERR_CONSTRAINT_VIOLATION;
214 goto out;
217 server_config_KDFAlgorithmID
218 = ldb_msg_find_attr_as_string(server_config_msg,
219 "msKds-KDFAlgorithmID",
220 SP800_108_CTR_HMAC
223 server_config_KDFParam
224 = ldb_msg_find_ldb_val(server_config_msg,
225 "msKds-KDFParam");
226 if (server_config_KDFParam == NULL) {
227 struct KdfParameters kdf_parameters = {
228 .hash_algorithm = "SHA512"
230 enum ndr_err_code err;
232 err = ndr_push_struct_blob(&kdf_parameters_blob,
233 tmp_ctx,
234 &kdf_parameters,
235 (ndr_push_flags_fn_t)
236 ndr_push_KdfParameters);
238 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
239 status = ndr_map_error2ntstatus(err);
240 ldb_asprintf_errstring(ldb,
241 "KdfParameters pull failed: %s\n",
242 nt_errstr(status));
243 ret = LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
244 goto out;
247 server_config_KDFParam = &kdf_parameters_blob;
250 status = kdf_algorithm_from_params(server_config_KDFAlgorithmID,
251 server_config_KDFParam,
252 &kdf_algorithm);
253 if (!NT_STATUS_IS_OK(status)) {
254 ldb_asprintf_errstring(ldb,
255 "Unwilling to create new GKDI root key as "
256 "%s has an unsupported msKds-KDFAlgorithmID / msKds-KDFParam combination set: %s\n",
257 ldb_dn_get_linearized(server_config_dn),
258 nt_errstr(status));
259 ret = LDB_ERR_CONSTRAINT_VIOLATION;
260 goto out;
263 server_config_SecretAgreementAlgorithmID
264 = ldb_msg_find_attr_as_string(server_config_msg,
265 "msKds-SecretAgreementAlgorithmID",
266 "DH");
268 /* Optional in msKds-ProvRootKey */
269 server_config_SecretAgreementParam
270 = ldb_msg_find_ldb_val(server_config_msg,
271 "msKds-SecretAgreementParam");
272 if (server_config_SecretAgreementParam == NULL) {
273 static const uint8_t ffc_dh_parameters[] = {
274 12, 2, 0, 0, 68, 72, 80, 77, 0, 1, 0,
275 0, 135, 168, 230, 29, 180, 182, 102, 60, 255, 187,
276 209, 156, 101, 25, 89, 153, 140, 238, 246, 8, 102,
277 13, 208, 242, 93, 44, 238, 212, 67, 94, 59, 0,
278 224, 13, 248, 241, 214, 25, 87, 212, 250, 247, 223,
279 69, 97, 178, 170, 48, 22, 195, 217, 17, 52, 9,
280 111, 170, 59, 244, 41, 109, 131, 14, 154, 124, 32,
281 158, 12, 100, 151, 81, 122, 189, 90, 138, 157, 48,
282 107, 207, 103, 237, 145, 249, 230, 114, 91, 71, 88,
283 192, 34, 224, 177, 239, 66, 117, 191, 123, 108, 91,
284 252, 17, 212, 95, 144, 136, 185, 65, 245, 78, 177,
285 229, 155, 184, 188, 57, 160, 191, 18, 48, 127, 92,
286 79, 219, 112, 197, 129, 178, 63, 118, 182, 58, 202,
287 225, 202, 166, 183, 144, 45, 82, 82, 103, 53, 72,
288 138, 14, 241, 60, 109, 154, 81, 191, 164, 171, 58,
289 216, 52, 119, 150, 82, 77, 142, 246, 161, 103, 181,
290 164, 24, 37, 217, 103, 225, 68, 229, 20, 5, 100,
291 37, 28, 202, 203, 131, 230, 180, 134, 246, 179, 202,
292 63, 121, 113, 80, 96, 38, 192, 184, 87, 246, 137,
293 150, 40, 86, 222, 212, 1, 10, 189, 11, 230, 33,
294 195, 163, 150, 10, 84, 231, 16, 195, 117, 242, 99,
295 117, 215, 1, 65, 3, 164, 181, 67, 48, 193, 152,
296 175, 18, 97, 22, 210, 39, 110, 17, 113, 95, 105,
297 56, 119, 250, 215, 239, 9, 202, 219, 9, 74, 233,
298 30, 26, 21, 151, 63, 179, 44, 155, 115, 19, 77,
299 11, 46, 119, 80, 102, 96, 237, 189, 72, 76, 167,
300 177, 143, 33, 239, 32, 84, 7, 244, 121, 58, 26,
301 11, 161, 37, 16, 219, 193, 80, 119, 190, 70, 63,
302 255, 79, 237, 74, 172, 11, 181, 85, 190, 58, 108,
303 27, 12, 107, 71, 177, 188, 55, 115, 191, 126, 140,
304 111, 98, 144, 18, 40, 248, 194, 140, 187, 24, 165,
305 90, 227, 19, 65, 0, 10, 101, 1, 150, 249, 49,
306 199, 122, 87, 242, 221, 244, 99, 229, 233, 236, 20,
307 75, 119, 125, 230, 42, 170, 184, 168, 98, 138, 195,
308 118, 210, 130, 214, 237, 56, 100, 230, 121, 130, 66,
309 142, 188, 131, 29, 20, 52, 143, 111, 47, 145, 147,
310 181, 4, 90, 242, 118, 113, 100, 225, 223, 201, 103,
311 193, 251, 63, 46, 85, 164, 189, 27, 255, 232, 59,
312 156, 128, 208, 82, 185, 133, 209, 130, 234, 10, 219,
313 42, 59, 115, 19, 211, 254, 20, 200, 72, 75, 30,
314 5, 37, 136, 185, 183, 210, 187, 210, 223, 1, 97,
315 153, 236, 208, 110, 21, 87, 205, 9, 21, 179, 53,
316 59, 187, 100, 224, 236, 55, 127, 208, 40, 55, 13,
317 249, 43, 82, 199, 137, 20, 40, 205, 198, 126, 182,
318 24, 75, 82, 61, 29, 178, 70, 195, 47, 99, 7,
319 132, 144, 240, 14, 248, 214, 71, 209, 72, 212, 121,
320 84, 81, 94, 35, 39, 207, 239, 152, 197, 130, 102,
321 75, 76, 15, 108, 196, 22, 89};
322 static const DATA_BLOB ffc_dh_parameters_blob = {
323 discard_const_p(uint8_t, ffc_dh_parameters),
324 sizeof ffc_dh_parameters};
325 server_config_SecretAgreementParam = &ffc_dh_parameters_blob;
328 server_config_PublicKeyLength
329 = ldb_msg_find_attr_as_uint64(server_config_msg,
330 "msKds-PublicKeyLength",
331 2048);
333 server_config_PrivateKeyLength
334 = ldb_msg_find_attr_as_uint64(server_config_msg,
335 "msKds-PrivateKeyLength",
336 256);
338 add_msg = ldb_msg_new(tmp_ctx);
339 if (add_msg == NULL) {
340 ret = ldb_oom(ldb);
341 goto out;
344 ret = ldb_msg_append_string(add_msg,
345 "objectClass",
346 "msKds-ProvRootKey",
347 LDB_FLAG_MOD_ADD);
348 if (ret) {
349 goto out;
353 const DATA_BLOB root_key_data_blob = {
354 .data = root_key_data, .length = sizeof root_key_data};
356 generate_secret_buffer(root_key_data, sizeof root_key_data);
358 ret = ldb_msg_append_value(add_msg,
359 "msKds-RootKeyData",
360 &root_key_data_blob,
361 LDB_FLAG_MOD_ADD);
362 if (ret) {
363 goto out;
367 ret = samdb_msg_append_uint64(ldb,
368 tmp_ctx,
369 add_msg,
370 "msKds-CreateTime",
371 current_time,
372 LDB_FLAG_MOD_ADD);
373 if (ret) {
374 goto out;
377 ret = samdb_msg_append_uint64(ldb,
378 tmp_ctx,
379 add_msg,
380 "msKds-UseStartTime",
381 use_start_time,
382 LDB_FLAG_MOD_ADD);
383 if (ret) {
384 goto out;
388 struct ldb_dn *domain_dn = NULL;
390 ret = samdb_server_reference_dn(ldb, tmp_ctx, &domain_dn);
391 if (ret) {
392 goto out;
395 ret = ldb_msg_append_linearized_dn(add_msg,
396 "msKds-DomainID",
397 domain_dn,
398 LDB_FLAG_MOD_ADD);
399 if (ret) {
400 goto out;
404 ret = samdb_msg_append_uint64(ldb,
405 tmp_ctx,
406 add_msg,
407 "msKds-Version",
408 server_config_version,
409 LDB_FLAG_MOD_ADD);
410 if (ret) {
411 goto out;
414 ret = ldb_msg_append_string(add_msg,
415 "msKds-KDFAlgorithmID",
416 server_config_KDFAlgorithmID,
417 LDB_FLAG_MOD_ADD);
418 if (ret) {
419 goto out;
422 ret = ldb_msg_append_string(add_msg,
423 "msKds-SecretAgreementAlgorithmID",
424 server_config_SecretAgreementAlgorithmID,
425 LDB_FLAG_MOD_ADD);
426 if (ret) {
427 goto out;
430 if (server_config_SecretAgreementParam != NULL) {
431 ret = ldb_msg_append_value(add_msg,
432 "msKds-SecretAgreementParam",
433 server_config_SecretAgreementParam,
434 LDB_FLAG_MOD_ADD);
435 if (ret) {
436 goto out;
440 ret = samdb_msg_append_uint64(ldb,
441 tmp_ctx,
442 add_msg,
443 "msKds-PublicKeyLength",
444 server_config_PublicKeyLength,
445 LDB_FLAG_MOD_ADD);
446 if (ret) {
447 goto out;
450 ret = samdb_msg_append_uint64(ldb,
451 tmp_ctx,
452 add_msg,
453 "msKds-PrivateKeyLength",
454 server_config_PrivateKeyLength,
455 LDB_FLAG_MOD_ADD);
457 ret = ldb_msg_append_value(add_msg,
458 "msKds-KDFParam",
459 server_config_KDFParam,
460 LDB_FLAG_MOD_ADD);
461 if (ret) {
462 goto out;
466 uint8_t guid_buf[sizeof((struct GUID_ndr_buf){}.buf)];
467 const DATA_BLOB guid_blob = {.data = guid_buf,
468 .length = sizeof guid_buf};
470 generate_secret_buffer(guid_buf, sizeof guid_buf);
472 status = GUID_from_ndr_blob(&guid_blob, &root_key_id);
473 if (!NT_STATUS_IS_OK(status)) {
474 ret = ldb_operr(ldb);
475 goto out;
480 struct ldb_dn *root_key_dn = NULL;
482 root_key_dn = samdb_gkdi_root_key_dn(ldb,
483 tmp_ctx,
484 &root_key_id);
485 if (root_key_dn == NULL) {
486 ret = ldb_operr(ldb);
487 goto out;
490 add_msg->dn = root_key_dn;
493 ret = dsdb_add(ldb, add_msg, 0);
494 if (ret) {
495 goto out;
498 *root_key_id_out = root_key_id;
499 *root_key_dn_out = talloc_steal(mem_ctx, add_msg->dn);
501 out:
502 talloc_free(tmp_ctx);
503 return ret;
507 * The PrivateKey, PublicKey, and SecretAgreement attributes are related to the
508 * public‐key functionality in GKDI. Samba doesn’t try to implement any of that,
509 * so we don’t bother looking at these attributes.
511 static const char *const root_key_attrs[] = {
512 "msKds-CreateTime",
513 "msKds-DomainID",
514 "msKds-KDFAlgorithmID",
515 "msKds-KDFParam",
516 /* "msKds-PrivateKeyLength", */
517 /* "msKds-PublicKeyLength", */
518 "msKds-RootKeyData",
519 /* "msKds-SecretAgreementAlgorithmID", */
520 /* "msKds-SecretAgreementParam", */
521 "msKds-UseStartTime",
522 "msKds-Version",
523 NULL,
527 * Create and return a new GKDI root key.
529 * This function goes unused.
531 int gkdi_new_root_key(TALLOC_CTX *mem_ctx,
532 struct ldb_context *const ldb,
533 const NTTIME current_time,
534 const NTTIME use_start_time,
535 struct GUID *const root_key_id_out,
536 const struct ldb_message **const root_key_out)
538 TALLOC_CTX *tmp_ctx = NULL;
539 struct ldb_dn *root_key_dn = NULL;
540 struct ldb_result *res = NULL;
541 int ret = LDB_SUCCESS;
543 *root_key_out = NULL;
545 tmp_ctx = talloc_new(mem_ctx);
546 if (tmp_ctx == NULL) {
547 ret = ldb_oom(ldb);
548 goto out;
551 ret = gkdi_create_root_key(tmp_ctx,
552 ldb,
553 current_time,
554 use_start_time,
555 root_key_id_out,
556 &root_key_dn);
557 if (ret) {
558 goto out;
561 ret = dsdb_search_dn(
562 ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
563 if (ret) {
564 goto out;
567 if (res->count != 1) {
568 ret = LDB_ERR_NO_SUCH_OBJECT;
569 goto out;
572 *root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
574 out:
575 talloc_free(tmp_ctx);
576 return ret;
579 int gkdi_root_key_from_id(TALLOC_CTX *mem_ctx,
580 struct ldb_context *const ldb,
581 const struct GUID *const root_key_id,
582 const struct ldb_message **const root_key_out)
584 TALLOC_CTX *tmp_ctx = NULL;
585 struct ldb_dn *root_key_dn = NULL;
586 struct ldb_result *res = NULL;
587 int ret = LDB_SUCCESS;
589 *root_key_out = NULL;
591 tmp_ctx = talloc_new(mem_ctx);
592 if (tmp_ctx == NULL) {
593 ret = ldb_oom(ldb);
594 goto out;
597 root_key_dn = samdb_gkdi_root_key_dn(ldb, tmp_ctx, root_key_id);
598 if (root_key_dn == NULL) {
599 ret = ldb_operr(ldb);
600 goto out;
603 ret = dsdb_search_dn(
604 ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
605 if (ret) {
606 goto out;
609 if (res->count != 1) {
610 ret = dsdb_werror(ldb,
611 LDB_ERR_NO_SUCH_OBJECT,
612 W_ERROR(HRES_ERROR_V(HRES_NTE_NO_KEY)),
613 "failed to find root key");
614 goto out;
617 *root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
619 out:
620 talloc_free(tmp_ctx);
621 return ret;
624 int gkdi_most_recently_created_root_key(
625 TALLOC_CTX *mem_ctx,
626 struct ldb_context *const ldb,
627 _UNUSED_ const NTTIME current_time,
628 const NTTIME not_after,
629 struct GUID *const root_key_id_out,
630 const struct ldb_message **const root_key_out)
632 TALLOC_CTX *tmp_ctx = NULL;
633 struct ldb_result *res = NULL;
634 int ret = LDB_SUCCESS;
636 *root_key_out = NULL;
638 tmp_ctx = talloc_new(mem_ctx);
639 if (tmp_ctx == NULL) {
640 ret = ldb_oom(ldb);
641 goto out;
645 struct ldb_dn *root_key_container_dn = NULL;
647 root_key_container_dn = samdb_gkdi_root_key_container_dn(
648 ldb, tmp_ctx);
649 if (root_key_container_dn == NULL) {
650 ret = ldb_operr(ldb);
651 goto out;
654 ret = dsdb_search(ldb,
655 tmp_ctx,
656 &res,
657 root_key_container_dn,
658 LDB_SCOPE_ONELEVEL,
659 root_key_attrs,
661 "(msKds-UseStartTime<=%" PRIu64 ")",
662 not_after);
663 if (ret) {
664 goto out;
669 * Windows just gives up if there are more than 1000 root keys in the
670 * container.
674 struct root_key_candidate {
675 struct GUID id;
676 const struct ldb_message *key;
677 NTTIME create_time;
678 } most_recent_key = {
679 .key = NULL,
681 unsigned i;
683 for (i = 0; i < res->count; ++i) {
684 struct root_key_candidate key = {
685 .key = res->msgs[i],
687 const struct ldb_val *rdn_val = NULL;
688 bool ok;
690 key.create_time = samdb_result_nttime(
691 key.key, "msKds-CreateTime", 0);
692 if (key.create_time < most_recent_key.create_time) {
693 /* We already have a more recent key. */
694 continue;
697 rdn_val = ldb_dn_get_rdn_val(key.key->dn);
698 if (rdn_val == NULL) {
699 continue;
702 if (rdn_val->length != 36) {
704 * Check the RDN is the right length — 36 is the
705 * length of a UUID.
707 continue;
710 ok = parse_guid_string((const char *)rdn_val->data,
711 &key.id);
712 if (!ok) {
713 /* The RDN is not a correctly formatted GUID. */
714 continue;
718 * We’ve found a new candidate for the most recent root
719 * key.
721 most_recent_key = key;
724 if (most_recent_key.key == NULL) {
726 * We were not able to find a suitable root key, but
727 * there is a possibility that a key we create now will
728 * do: if gkdi_root_key_use_start_time(current_time) ≤
729 * not_after, then a newly‐created key will satisfy our
730 * caller’s requirements.
732 * Unfortunately, with gMSAs this (I believe) will never
733 * be the case. It’s too late to call
734 * gkdi_new_root_key() — the new key will be a bit *too*
735 * new to be usable for a gMSA.
738 ret = dsdb_werror(ldb,
739 LDB_ERR_NO_SUCH_OBJECT,
740 W_ERROR(HRES_ERROR_V(
741 HRES_NTE_NO_KEY)),
742 "failed to find a suitable root key");
743 goto out;
746 /* Return the root key that we found. */
747 *root_key_id_out = most_recent_key.id;
748 *root_key_out = talloc_steal(mem_ctx, most_recent_key.key);
751 out:
752 talloc_free(tmp_ctx);
753 return ret;