Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Group Key Distribution Protocol functions
4 :
5 : Copyright (C) Catalyst.Net Ltd 2023
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include <gnutls/gnutls.h>
23 : #include <gnutls/crypto.h>
24 :
25 : #include "lib/crypto/gnutls_helpers.h"
26 :
27 : #include "lib/util/bytearray.h"
28 :
29 : #include "librpc/ndr/libndr.h"
30 : #include "librpc/gen_ndr/ndr_security.h"
31 : #include "librpc/gen_ndr/gkdi.h"
32 : #include "librpc/gen_ndr/ndr_gkdi.h"
33 :
34 : #include "lib/crypto/gkdi.h"
35 : #include "lib/util/data_blob.h"
36 :
37 : static const uint8_t kds_service[] = {
38 : /* “KDS service” as a NULL‐terminated UTF‐16LE string. */
39 : 'K', 0, 'D', 0, 'S', 0, ' ', 0, 's', 0, 'e', 0,
40 : 'r', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 0, 0,
41 : };
42 :
43 35 : static struct Gkid gkid_from_u32_indices(const uint32_t l0_idx,
44 : const uint32_t l1_idx,
45 : const uint32_t l2_idx)
46 : {
47 : /* Catch out‐of‐range indices. */
48 35 : if (l0_idx > INT32_MAX || l1_idx > INT8_MAX || l2_idx > INT8_MAX) {
49 0 : return invalid_gkid;
50 : }
51 :
52 35 : return Gkid(l0_idx, l1_idx, l2_idx);
53 : }
54 :
55 43 : NTSTATUS gkdi_pull_KeyEnvelope(TALLOC_CTX *mem_ctx,
56 : const DATA_BLOB *key_env_blob,
57 : struct KeyEnvelope *key_env_out)
58 : {
59 43 : NTSTATUS status = NT_STATUS_OK;
60 0 : enum ndr_err_code err;
61 :
62 43 : if (key_env_blob == NULL) {
63 0 : return NT_STATUS_INVALID_PARAMETER;
64 : }
65 :
66 43 : if (key_env_out == NULL) {
67 0 : return NT_STATUS_INVALID_PARAMETER;
68 : }
69 :
70 43 : err = ndr_pull_struct_blob(key_env_blob,
71 : mem_ctx,
72 : key_env_out,
73 : (ndr_pull_flags_fn_t)ndr_pull_KeyEnvelope);
74 43 : status = ndr_map_error2ntstatus(err);
75 43 : if (!NT_STATUS_IS_OK(status)) {
76 0 : return status;
77 : }
78 :
79 : /* If we felt so inclined, we could check the version field here. */
80 :
81 43 : return status;
82 : }
83 :
84 : /*
85 : * Retrieve the GKID and root key ID from a KeyEnvelope blob. The returned
86 : * structure is guaranteed to have a valid GKID.
87 : */
88 35 : const struct KeyEnvelopeId *gkdi_pull_KeyEnvelopeId(
89 : const DATA_BLOB key_env_blob,
90 : struct KeyEnvelopeId *key_env_out)
91 : {
92 35 : TALLOC_CTX *tmp_ctx = NULL;
93 0 : struct KeyEnvelope key_env;
94 35 : const struct KeyEnvelopeId *key_env_ret = NULL;
95 0 : NTSTATUS status;
96 :
97 35 : if (key_env_out == NULL) {
98 0 : goto out;
99 : }
100 :
101 35 : tmp_ctx = talloc_new(NULL);
102 35 : if (tmp_ctx == NULL) {
103 0 : goto out;
104 : }
105 :
106 35 : status = gkdi_pull_KeyEnvelope(tmp_ctx, &key_env_blob, &key_env);
107 35 : if (!NT_STATUS_IS_OK(status)) {
108 0 : goto out;
109 : }
110 :
111 : {
112 35 : const struct Gkid gkid = gkid_from_u32_indices(
113 : key_env.l0_index, key_env.l1_index, key_env.l2_index);
114 35 : if (!gkid_is_valid(gkid)) {
115 : /* The KeyId is not valid: we can’t use it. */
116 0 : goto out;
117 : }
118 :
119 35 : *key_env_out = (struct KeyEnvelopeId){
120 : .root_key_id = key_env.root_key_id, .gkid = gkid};
121 : }
122 :
123 : /* Return a pointer to the buffer passed in by the caller. */
124 35 : key_env_ret = key_env_out;
125 :
126 35 : out:
127 35 : TALLOC_FREE(tmp_ctx);
128 35 : return key_env_ret;
129 : }
130 :
131 101 : NTSTATUS ProvRootKey(TALLOC_CTX *mem_ctx,
132 : const struct GUID root_key_id,
133 : const int32_t version,
134 : const DATA_BLOB root_key_data,
135 : const NTTIME create_time,
136 : const NTTIME use_start_time,
137 : const char *const domain_id,
138 : const struct KdfAlgorithm kdf_algorithm,
139 : const struct ProvRootKey **const root_key_out)
140 : {
141 101 : NTSTATUS status = NT_STATUS_OK;
142 101 : struct ProvRootKey *root_key = NULL;
143 :
144 101 : if (root_key_out == NULL) {
145 0 : return NT_STATUS_INVALID_PARAMETER;
146 : }
147 101 : *root_key_out = NULL;
148 :
149 101 : root_key = talloc(mem_ctx, struct ProvRootKey);
150 101 : if (root_key == NULL) {
151 0 : return NT_STATUS_NO_MEMORY;
152 : }
153 :
154 101 : *root_key = (struct ProvRootKey){
155 : .id = root_key_id,
156 101 : .data = {.data = talloc_steal(root_key, root_key_data.data),
157 101 : .length = root_key_data.length},
158 : .create_time = create_time,
159 : .use_start_time = use_start_time,
160 101 : .domain_id = talloc_steal(root_key, domain_id),
161 : .kdf_algorithm = kdf_algorithm,
162 : .version = version,
163 : };
164 :
165 101 : *root_key_out = root_key;
166 101 : return status;
167 : }
168 :
169 176 : struct Gkid gkdi_get_interval_id(const NTTIME time)
170 : {
171 351 : return Gkid(time / (gkdi_l1_key_iteration * gkdi_l2_key_iteration *
172 : gkdi_key_cycle_duration),
173 176 : time / (gkdi_l2_key_iteration * gkdi_key_cycle_duration) %
174 : gkdi_l1_key_iteration,
175 176 : time / gkdi_key_cycle_duration % gkdi_l2_key_iteration);
176 : }
177 :
178 35 : bool gkdi_get_key_start_time(const struct Gkid gkid, NTTIME *start_time_out)
179 : {
180 35 : if (!gkid_is_valid(gkid)) {
181 0 : return false;
182 : }
183 :
184 : {
185 35 : enum GkidType key_type = gkid_key_type(gkid);
186 35 : if (key_type != GKID_L2_SEED_KEY) {
187 0 : return false;
188 : }
189 : }
190 :
191 : {
192 : /*
193 : * Make sure that the GKID is not so large its start time can’t
194 : * be represented in NTTIME.
195 : */
196 0 : static const struct Gkid max_gkid = {
197 : UINT64_MAX /
198 : (gkdi_l1_key_iteration * gkdi_l2_key_iteration *
199 : gkdi_key_cycle_duration),
200 : UINT64_MAX /
201 : (gkdi_l2_key_iteration *
202 : gkdi_key_cycle_duration) %
203 : gkdi_l1_key_iteration,
204 : UINT64_MAX / gkdi_key_cycle_duration %
205 : gkdi_l2_key_iteration};
206 35 : if (!gkid_less_than_or_equal_to(gkid, max_gkid)) {
207 0 : return false;
208 : }
209 : }
210 :
211 35 : *start_time_out = ((uint64_t)gkid.l0_idx * gkdi_l1_key_iteration *
212 35 : gkdi_l2_key_iteration +
213 35 : (uint64_t)gkid.l1_idx * gkdi_l2_key_iteration +
214 35 : (uint64_t)gkid.l2_idx) *
215 : gkdi_key_cycle_duration;
216 35 : return true;
217 : }
218 :
219 : /*
220 : * This returns the equivalent of
221 : * gkdi_get_key_start_time(gkdi_get_interval_id(time)).
222 : */
223 0 : NTTIME gkdi_get_interval_start_time(const NTTIME time)
224 : {
225 0 : return time / gkdi_key_cycle_duration * gkdi_key_cycle_duration;
226 : }
227 :
228 137 : bool gkid_less_than_or_equal_to(const struct Gkid g1, const struct Gkid g2)
229 : {
230 137 : if (g1.l0_idx != g2.l0_idx) {
231 35 : return g1.l0_idx < g2.l0_idx;
232 : }
233 :
234 102 : if (g1.l1_idx != g2.l1_idx) {
235 13 : return g1.l1_idx < g2.l1_idx;
236 : }
237 :
238 89 : return g1.l2_idx <= g2.l2_idx;
239 : }
240 :
241 35 : bool gkdi_rollover_interval(const int64_t managed_password_interval,
242 : NTTIME *result)
243 : {
244 : /*
245 : * This is actually a conservative reckoning. The interval could be one
246 : * higher than this maximum and not overflow. But there’s no reason to
247 : * support intervals that high (and Windows will start producing strange
248 : * results for intervals beyond that).
249 : */
250 35 : const int64_t maximum_interval = UINT64_MAX / gkdi_key_cycle_duration *
251 35 : 10 / 24;
252 :
253 35 : if (managed_password_interval < 0 ||
254 : managed_password_interval > maximum_interval)
255 : {
256 0 : return false;
257 : }
258 :
259 35 : *result = (uint64_t)managed_password_interval * 24 / 10 *
260 : gkdi_key_cycle_duration;
261 35 : return true;
262 : }
263 :
264 : struct GkdiContextShort {
265 : uint8_t buf[sizeof((struct GUID_ndr_buf){}.buf) + sizeof(int32_t) +
266 : sizeof(int32_t) + sizeof(int32_t)];
267 : };
268 :
269 3558 : static NTSTATUS make_gkdi_context(const struct GkdiDerivationCtx *ctx,
270 : struct GkdiContextShort *out_ctx)
271 : {
272 323 : enum ndr_err_code ndr_err;
273 3558 : DATA_BLOB b = {.data = out_ctx->buf, .length = sizeof out_ctx->buf};
274 :
275 3558 : if (ctx->target_security_descriptor.length) {
276 0 : return NT_STATUS_INVALID_PARAMETER;
277 : }
278 :
279 3558 : ndr_err = ndr_push_struct_into_fixed_blob(
280 : &b, ctx, (ndr_push_flags_fn_t)ndr_push_GkdiDerivationCtx);
281 3558 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
282 0 : return ndr_map_error2ntstatus(ndr_err);
283 : }
284 :
285 3558 : return NT_STATUS_OK;
286 : }
287 :
288 114 : static NTSTATUS make_gkdi_context_security_descriptor(
289 : TALLOC_CTX *mem_ctx,
290 : const struct GkdiDerivationCtx *ctx,
291 : const DATA_BLOB security_descriptor,
292 : DATA_BLOB *out_ctx)
293 : {
294 13 : enum ndr_err_code ndr_err;
295 114 : struct GkdiDerivationCtx ctx_with_sd = *ctx;
296 :
297 114 : if (ctx_with_sd.target_security_descriptor.length != 0) {
298 0 : return NT_STATUS_INVALID_PARAMETER;
299 : }
300 :
301 114 : ctx_with_sd.target_security_descriptor = security_descriptor;
302 :
303 114 : ndr_err = ndr_push_struct_blob(out_ctx,
304 : mem_ctx,
305 : &ctx_with_sd,
306 : (ndr_push_flags_fn_t)
307 : ndr_push_GkdiDerivationCtx);
308 114 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
309 0 : return ndr_map_error2ntstatus(ndr_err);
310 : }
311 :
312 114 : return NT_STATUS_OK;
313 : }
314 :
315 : struct GkdiContext {
316 : struct GkdiDerivationCtx ctx;
317 : gnutls_mac_algorithm_t algorithm;
318 : };
319 :
320 217 : gnutls_mac_algorithm_t get_sp800_108_mac_algorithm(
321 : const struct KdfAlgorithm kdf_algorithm)
322 : {
323 217 : switch (kdf_algorithm.id) {
324 217 : case KDF_ALGORITHM_SP800_108_CTR_HMAC:
325 217 : switch (kdf_algorithm.param.sp800_108) {
326 0 : case KDF_PARAM_SHA1:
327 0 : return GNUTLS_MAC_SHA1;
328 0 : case KDF_PARAM_SHA256:
329 0 : return GNUTLS_MAC_SHA256;
330 0 : case KDF_PARAM_SHA384:
331 0 : return GNUTLS_MAC_SHA384;
332 202 : case KDF_PARAM_SHA512:
333 202 : return GNUTLS_MAC_SHA512;
334 : }
335 0 : break;
336 : }
337 :
338 0 : return GNUTLS_MAC_UNKNOWN;
339 : }
340 :
341 118 : static NTSTATUS GkdiContext(const struct ProvRootKey *const root_key,
342 : struct GkdiContext *const ctx)
343 : {
344 118 : NTSTATUS status = NT_STATUS_OK;
345 118 : gnutls_mac_algorithm_t algorithm = GNUTLS_MAC_UNKNOWN;
346 :
347 118 : if (ctx == NULL) {
348 0 : status = NT_STATUS_INVALID_PARAMETER;
349 0 : goto out;
350 : }
351 :
352 118 : if (root_key == NULL) {
353 0 : status = NT_STATUS_INVALID_PARAMETER;
354 0 : goto out;
355 : }
356 :
357 118 : if (root_key->version != root_key_version_1) {
358 2 : status = NT_STATUS_NOT_SUPPORTED;
359 2 : goto out;
360 : }
361 :
362 116 : if (root_key->data.length != GKDI_KEY_LEN) {
363 1 : status = NT_STATUS_NOT_SUPPORTED;
364 1 : goto out;
365 : }
366 :
367 115 : algorithm = get_sp800_108_mac_algorithm(root_key->kdf_algorithm);
368 115 : if (algorithm == GNUTLS_MAC_UNKNOWN) {
369 1 : status = NT_STATUS_NOT_SUPPORTED;
370 1 : goto out;
371 : }
372 :
373 : /*
374 : * The context comprises the GUID corresponding to the root key, the
375 : * GKID (which we shall initialize to zero), and the encoded target
376 : * security descriptor (which will initially be empty).
377 : */
378 114 : *ctx = (struct GkdiContext){
379 101 : .ctx = {.guid = root_key->id,
380 : .l0_idx = 0,
381 : .l1_idx = 0,
382 : .l2_idx = 0,
383 : .target_security_descriptor = {}},
384 : .algorithm = algorithm,
385 : };
386 118 : out:
387 118 : return status;
388 : }
389 :
390 114 : static NTSTATUS compute_l1_seed_key(TALLOC_CTX *mem_ctx,
391 : struct GkdiContext *ctx,
392 : const DATA_BLOB security_descriptor,
393 : const struct ProvRootKey *const root_key,
394 : const struct Gkid gkid,
395 : uint8_t key[static const GKDI_KEY_LEN])
396 : {
397 114 : NTSTATUS status = NT_STATUS_OK;
398 13 : struct GkdiContextShort short_ctx;
399 13 : int8_t n;
400 :
401 114 : ctx->ctx.l0_idx = gkid.l0_idx;
402 114 : ctx->ctx.l1_idx = -1;
403 114 : ctx->ctx.l2_idx = -1;
404 :
405 114 : status = make_gkdi_context(&ctx->ctx, &short_ctx);
406 114 : if (!NT_STATUS_IS_OK(status)) {
407 0 : goto out;
408 : }
409 :
410 : /* Derive an L0 seed key with GKID = (L0, −1, −1). */
411 :
412 127 : status = samba_gnutls_sp800_108_derive_key(root_key->data.data,
413 114 : root_key->data.length,
414 : NULL,
415 : 0,
416 : kds_service,
417 : sizeof kds_service,
418 : short_ctx.buf,
419 : sizeof short_ctx.buf,
420 : ctx->algorithm,
421 : key,
422 : GKDI_KEY_LEN);
423 114 : if (!NT_STATUS_IS_OK(status)) {
424 0 : goto out;
425 : }
426 :
427 : /* Derive an L1 seed key with GKID = (L0, 31, −1). */
428 :
429 114 : ctx->ctx.l1_idx = 31;
430 :
431 : {
432 13 : DATA_BLOB security_descriptor_ctx;
433 :
434 114 : status = make_gkdi_context_security_descriptor(
435 : mem_ctx,
436 101 : &ctx->ctx,
437 : security_descriptor,
438 : &security_descriptor_ctx);
439 114 : if (!NT_STATUS_IS_OK(status)) {
440 0 : goto out;
441 : }
442 :
443 127 : status = samba_gnutls_sp800_108_derive_key(
444 : key,
445 : GKDI_KEY_LEN,
446 : NULL,
447 : 0,
448 : kds_service,
449 : sizeof kds_service,
450 114 : security_descriptor_ctx.data,
451 : security_descriptor_ctx.length,
452 : ctx->algorithm,
453 : key,
454 : GKDI_KEY_LEN);
455 114 : data_blob_free(&security_descriptor_ctx);
456 114 : if (!NT_STATUS_IS_OK(status)) {
457 0 : goto out;
458 : }
459 : }
460 :
461 1816 : for (n = 30; n >= gkid.l1_idx; --n) {
462 : /* Derive an L1 seed key with GKID = (L0, n, −1). */
463 :
464 1702 : ctx->ctx.l1_idx = n;
465 :
466 1702 : status = make_gkdi_context(&ctx->ctx, &short_ctx);
467 1702 : if (!NT_STATUS_IS_OK(status)) {
468 0 : goto out;
469 : }
470 :
471 1702 : status = samba_gnutls_sp800_108_derive_key(key,
472 : GKDI_KEY_LEN,
473 : NULL,
474 : 0,
475 : kds_service,
476 : sizeof kds_service,
477 : short_ctx.buf,
478 : sizeof short_ctx.buf,
479 : ctx->algorithm,
480 : key,
481 : GKDI_KEY_LEN);
482 1702 : if (!NT_STATUS_IS_OK(status)) {
483 0 : goto out;
484 : }
485 : }
486 :
487 114 : out:
488 114 : return status;
489 : }
490 :
491 108 : static NTSTATUS derive_l2_seed_key(struct GkdiContext *ctx,
492 : const struct Gkid gkid,
493 : uint8_t key[static const GKDI_KEY_LEN])
494 : {
495 108 : NTSTATUS status = NT_STATUS_OK;
496 7 : int8_t n;
497 :
498 108 : ctx->ctx.l0_idx = gkid.l0_idx;
499 108 : ctx->ctx.l1_idx = gkid.l1_idx;
500 :
501 1850 : for (n = 31; n >= gkid.l2_idx; --n) {
502 126 : struct GkdiContextShort short_ctx;
503 :
504 : /* Derive an L2 seed key with GKID = (L0, L1, n). */
505 :
506 1742 : ctx->ctx.l2_idx = n;
507 :
508 1742 : status = make_gkdi_context(&ctx->ctx, &short_ctx);
509 1742 : if (!NT_STATUS_IS_OK(status)) {
510 0 : goto out;
511 : }
512 :
513 1742 : status = samba_gnutls_sp800_108_derive_key(key,
514 : GKDI_KEY_LEN,
515 : NULL,
516 : 0,
517 : kds_service,
518 : sizeof kds_service,
519 : short_ctx.buf,
520 : sizeof short_ctx.buf,
521 : ctx->algorithm,
522 : key,
523 : GKDI_KEY_LEN);
524 1742 : if (!NT_STATUS_IS_OK(status)) {
525 0 : goto out;
526 : }
527 : }
528 :
529 108 : out:
530 108 : return status;
531 : }
532 :
533 257 : enum GkidType gkid_key_type(const struct Gkid gkid)
534 : {
535 257 : if (gkid.l0_idx == -1) {
536 0 : return GKID_DEFAULT;
537 : }
538 :
539 256 : if (gkid.l1_idx == -1) {
540 0 : return GKID_L0_SEED_KEY;
541 : }
542 :
543 255 : if (gkid.l2_idx == -1) {
544 6 : return GKID_L1_SEED_KEY;
545 : }
546 :
547 237 : return GKID_L2_SEED_KEY;
548 : }
549 :
550 299 : bool gkid_is_valid(const struct Gkid gkid)
551 : {
552 299 : if (gkid.l0_idx < -1) {
553 0 : return false;
554 : }
555 :
556 298 : if (gkid.l1_idx < -1 || gkid.l1_idx >= gkdi_l1_key_iteration) {
557 0 : return false;
558 : }
559 :
560 296 : if (gkid.l2_idx < -1 || gkid.l2_idx >= gkdi_l2_key_iteration) {
561 0 : return false;
562 : }
563 :
564 294 : if (gkid.l0_idx == -1 && gkid.l1_idx != -1) {
565 0 : return false;
566 : }
567 :
568 293 : if (gkid.l1_idx == -1 && gkid.l2_idx != -1) {
569 1 : return false;
570 : }
571 :
572 272 : return true;
573 : }
574 :
575 127 : NTSTATUS compute_seed_key(TALLOC_CTX *mem_ctx,
576 : const DATA_BLOB target_security_descriptor,
577 : const struct ProvRootKey *const root_key,
578 : const struct Gkid gkid,
579 : uint8_t key[static const GKDI_KEY_LEN])
580 : {
581 127 : NTSTATUS status = NT_STATUS_OK;
582 26 : enum GkidType gkid_type;
583 26 : struct GkdiContext ctx;
584 :
585 127 : if (!gkid_is_valid(gkid)) {
586 7 : status = NT_STATUS_INVALID_PARAMETER;
587 7 : goto out;
588 : }
589 :
590 120 : gkid_type = gkid_key_type(gkid);
591 120 : if (gkid_type < GKID_L1_SEED_KEY) {
592 : /* Don’t allow derivation of L0 seed keys. */
593 2 : status = NT_STATUS_INVALID_PARAMETER;
594 2 : goto out;
595 : }
596 :
597 118 : status = GkdiContext(root_key, &ctx);
598 118 : if (!NT_STATUS_IS_OK(status)) {
599 4 : goto out;
600 : }
601 :
602 114 : status = compute_l1_seed_key(
603 : mem_ctx, &ctx, target_security_descriptor, root_key, gkid, key);
604 114 : if (!NT_STATUS_IS_OK(status)) {
605 0 : goto out;
606 : }
607 :
608 114 : if (gkid_type == GKID_L2_SEED_KEY) {
609 108 : status = derive_l2_seed_key(&ctx, gkid, key);
610 108 : if (!NT_STATUS_IS_OK(status)) {
611 0 : goto out;
612 : }
613 : }
614 :
615 114 : out:
616 127 : return status;
617 : }
618 :
619 198 : NTSTATUS kdf_sp_800_108_from_params(
620 : const DATA_BLOB *const kdf_param,
621 : struct KdfAlgorithm *const kdf_algorithm_out)
622 : {
623 198 : TALLOC_CTX *tmp_ctx = NULL;
624 198 : NTSTATUS status = NT_STATUS_OK;
625 22 : enum ndr_err_code err;
626 198 : enum KdfSp800_108Param sp800_108_param = KDF_PARAM_SHA256;
627 22 : struct KdfParameters kdf_parameters;
628 :
629 198 : if (kdf_param != NULL) {
630 198 : tmp_ctx = talloc_new(NULL);
631 198 : if (tmp_ctx == NULL) {
632 0 : status = NT_STATUS_NO_MEMORY;
633 0 : goto out;
634 : }
635 :
636 198 : err = ndr_pull_struct_blob(kdf_param,
637 : tmp_ctx,
638 : &kdf_parameters,
639 : (ndr_pull_flags_fn_t)
640 : ndr_pull_KdfParameters);
641 198 : if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
642 0 : status = ndr_map_error2ntstatus(err);
643 0 : DBG_WARNING("KdfParameters pull failed: %s\n",
644 : nt_errstr(status));
645 0 : goto out;
646 : }
647 :
648 198 : if (kdf_parameters.hash_algorithm == NULL) {
649 0 : status = NT_STATUS_NOT_SUPPORTED;
650 0 : goto out;
651 : }
652 :
653 : /* These string comparisons are case‐sensitive. */
654 198 : if (strcmp(kdf_parameters.hash_algorithm, "SHA1") == 0) {
655 0 : sp800_108_param = KDF_PARAM_SHA1;
656 198 : } else if (strcmp(kdf_parameters.hash_algorithm, "SHA256") == 0)
657 : {
658 0 : sp800_108_param = KDF_PARAM_SHA256;
659 198 : } else if (strcmp(kdf_parameters.hash_algorithm, "SHA384") == 0)
660 : {
661 0 : sp800_108_param = KDF_PARAM_SHA384;
662 198 : } else if (strcmp(kdf_parameters.hash_algorithm, "SHA512") == 0)
663 : {
664 176 : sp800_108_param = KDF_PARAM_SHA512;
665 : } else {
666 0 : status = NT_STATUS_NOT_SUPPORTED;
667 0 : goto out;
668 : }
669 : }
670 :
671 198 : *kdf_algorithm_out = (struct KdfAlgorithm){
672 : .id = KDF_ALGORITHM_SP800_108_CTR_HMAC,
673 : .param.sp800_108 = sp800_108_param,
674 : };
675 198 : out:
676 198 : talloc_free(tmp_ctx);
677 198 : return status;
678 : }
679 :
680 199 : NTSTATUS kdf_algorithm_from_params(const char *const kdf_algorithm_id,
681 : const DATA_BLOB *const kdf_param,
682 : struct KdfAlgorithm *const kdf_algorithm_out)
683 : {
684 199 : if (kdf_algorithm_id == NULL) {
685 0 : return NT_STATUS_INVALID_PARAMETER;
686 : }
687 :
688 : /* This string comparison is case‐sensitive. */
689 199 : if (strcmp(kdf_algorithm_id, "SP800_108_CTR_HMAC") == 0) {
690 198 : return kdf_sp_800_108_from_params(kdf_param, kdf_algorithm_out);
691 : }
692 :
693 : /* Unknown algorithm. */
694 1 : return NT_STATUS_NOT_SUPPORTED;
695 : }
|