LCOV - code coverage report
Current view: top level - lib/crypto - gkdi.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 120 261 46.0 %
Date: 2024-02-29 22:57:05 Functions: 11 20 55.0 %

          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           0 : 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           0 :         if (l0_idx > INT32_MAX || l1_idx > INT8_MAX || l2_idx > INT8_MAX) {
      49           0 :                 return invalid_gkid;
      50             :         }
      51             : 
      52           0 :         return Gkid(l0_idx, l1_idx, l2_idx);
      53             : }
      54             : 
      55           0 : NTSTATUS gkdi_pull_KeyEnvelope(TALLOC_CTX *mem_ctx,
      56             :                                const DATA_BLOB *key_env_blob,
      57             :                                struct KeyEnvelope *key_env_out)
      58             : {
      59           0 :         NTSTATUS status = NT_STATUS_OK;
      60           0 :         enum ndr_err_code err;
      61             : 
      62           0 :         if (key_env_blob == NULL) {
      63           0 :                 return NT_STATUS_INVALID_PARAMETER;
      64             :         }
      65             : 
      66           0 :         if (key_env_out == NULL) {
      67           0 :                 return NT_STATUS_INVALID_PARAMETER;
      68             :         }
      69             : 
      70           0 :         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           0 :         status = ndr_map_error2ntstatus(err);
      75           0 :         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           0 :         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           0 : const struct KeyEnvelopeId *gkdi_pull_KeyEnvelopeId(
      89             :         const DATA_BLOB key_env_blob,
      90             :         struct KeyEnvelopeId *key_env_out)
      91             : {
      92           0 :         TALLOC_CTX *tmp_ctx = NULL;
      93           0 :         struct KeyEnvelope key_env;
      94           0 :         const struct KeyEnvelopeId *key_env_ret = NULL;
      95           0 :         NTSTATUS status;
      96             : 
      97           0 :         if (key_env_out == NULL) {
      98           0 :                 goto out;
      99             :         }
     100             : 
     101           0 :         tmp_ctx = talloc_new(NULL);
     102           0 :         if (tmp_ctx == NULL) {
     103           0 :                 goto out;
     104             :         }
     105             : 
     106           0 :         status = gkdi_pull_KeyEnvelope(tmp_ctx, &key_env_blob, &key_env);
     107           0 :         if (!NT_STATUS_IS_OK(status)) {
     108           0 :                 goto out;
     109             :         }
     110             : 
     111             :         {
     112           0 :                 const struct Gkid gkid = gkid_from_u32_indices(
     113             :                         key_env.l0_index, key_env.l1_index, key_env.l2_index);
     114           0 :                 if (!gkid_is_valid(gkid)) {
     115             :                         /* The KeyId is not valid: we can’t use it. */
     116           0 :                         goto out;
     117             :                 }
     118             : 
     119           0 :                 *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           0 :         key_env_ret = key_env_out;
     125             : 
     126           0 : out:
     127           0 :         TALLOC_FREE(tmp_ctx);
     128           0 :         return key_env_ret;
     129             : }
     130             : 
     131           0 : 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           0 :         NTSTATUS status = NT_STATUS_OK;
     142           0 :         struct ProvRootKey *root_key = NULL;
     143             : 
     144           0 :         if (root_key_out == NULL) {
     145           0 :                 return NT_STATUS_INVALID_PARAMETER;
     146             :         }
     147           0 :         *root_key_out = NULL;
     148             : 
     149           0 :         root_key = talloc(mem_ctx, struct ProvRootKey);
     150           0 :         if (root_key == NULL) {
     151           0 :                 return NT_STATUS_NO_MEMORY;
     152             :         }
     153             : 
     154           0 :         *root_key = (struct ProvRootKey){
     155             :                 .id = root_key_id,
     156           0 :                 .data = {.data = talloc_steal(root_key, root_key_data.data),
     157           0 :                          .length = root_key_data.length},
     158             :                 .create_time = create_time,
     159             :                 .use_start_time = use_start_time,
     160           0 :                 .domain_id = talloc_steal(root_key, domain_id),
     161             :                 .kdf_algorithm = kdf_algorithm,
     162             :                 .version = version,
     163             :         };
     164             : 
     165           0 :         *root_key_out = root_key;
     166           0 :         return status;
     167             : }
     168             : 
     169           1 : struct Gkid gkdi_get_interval_id(const NTTIME time)
     170             : {
     171           1 :         return Gkid(time / (gkdi_l1_key_iteration * gkdi_l2_key_iteration *
     172             :                             gkdi_key_cycle_duration),
     173           1 :                     time / (gkdi_l2_key_iteration * gkdi_key_cycle_duration) %
     174             :                             gkdi_l1_key_iteration,
     175           1 :                     time / gkdi_key_cycle_duration % gkdi_l2_key_iteration);
     176             : }
     177             : 
     178           0 : NTTIME gkdi_get_key_start_time(const struct Gkid gkid)
     179             : {
     180           0 :         return (gkid.l0_idx * gkdi_l1_key_iteration * gkdi_l2_key_iteration +
     181           0 :                 gkid.l1_idx * gkdi_l2_key_iteration + gkid.l2_idx) *
     182             :                gkdi_key_cycle_duration;
     183             : }
     184             : 
     185             : /*
     186             :  * This returns the equivalent of
     187             :  * gkdi_get_key_start_time(gkdi_get_interval_id(time)).
     188             :  */
     189           0 : NTTIME gkdi_get_interval_start_time(const NTTIME time)
     190             : {
     191           0 :         return time % gkdi_key_cycle_duration;
     192             : }
     193             : 
     194           1 : bool gkid_less_than_or_equal_to(const struct Gkid g1, const struct Gkid g2)
     195             : {
     196           1 :         if (g1.l0_idx != g2.l0_idx) {
     197           0 :                 return g1.l0_idx < g2.l0_idx;
     198             :         }
     199             : 
     200           1 :         if (g1.l1_idx != g2.l1_idx) {
     201           1 :                 return g1.l1_idx < g2.l1_idx;
     202             :         }
     203             : 
     204           0 :         return g1.l2_idx <= g2.l2_idx;
     205             : }
     206             : 
     207           0 : bool gkdi_rollover_interval(const int64_t managed_password_interval,
     208             :                             NTTIME *result)
     209             : {
     210           0 :         if (managed_password_interval < 0) {
     211           0 :                 return false;
     212             :         }
     213             : 
     214           0 :         *result = (uint64_t)managed_password_interval * 24 / 10 *
     215             :                   gkdi_key_cycle_duration;
     216           0 :         return true;
     217             : }
     218             : 
     219             : struct GkdiContextShort {
     220             :         uint8_t buf[sizeof((struct GUID_ndr_buf){}.buf) + sizeof(int32_t) +
     221             :                     sizeof(int32_t) + sizeof(int32_t)];
     222             : };
     223             : 
     224         323 : static NTSTATUS make_gkdi_context(const struct GkdiDerivationCtx *ctx,
     225             :                                   struct GkdiContextShort *out_ctx)
     226             : {
     227         323 :         enum ndr_err_code ndr_err;
     228         323 :         DATA_BLOB b = {.data = out_ctx->buf, .length = sizeof out_ctx->buf};
     229             : 
     230         323 :         if (ctx->target_security_descriptor.length) {
     231           0 :                 return NT_STATUS_INVALID_PARAMETER;
     232             :         }
     233             : 
     234         323 :         ndr_err = ndr_push_struct_into_fixed_blob(
     235             :                 &b, ctx, (ndr_push_flags_fn_t)ndr_push_GkdiDerivationCtx);
     236         323 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     237           0 :                 return ndr_map_error2ntstatus(ndr_err);
     238             :         }
     239             : 
     240         323 :         return NT_STATUS_OK;
     241             : }
     242             : 
     243          13 : static NTSTATUS make_gkdi_context_security_descriptor(
     244             :         TALLOC_CTX *mem_ctx,
     245             :         const struct GkdiDerivationCtx *ctx,
     246             :         const DATA_BLOB security_descriptor,
     247             :         DATA_BLOB *out_ctx)
     248             : {
     249          13 :         enum ndr_err_code ndr_err;
     250          13 :         struct GkdiDerivationCtx ctx_with_sd = *ctx;
     251             : 
     252          13 :         if (ctx_with_sd.target_security_descriptor.length != 0) {
     253           0 :                 return NT_STATUS_INVALID_PARAMETER;
     254             :         }
     255             : 
     256          13 :         ctx_with_sd.target_security_descriptor = security_descriptor;
     257             : 
     258          13 :         ndr_err = ndr_push_struct_blob(out_ctx,
     259             :                                        mem_ctx,
     260             :                                        &ctx_with_sd,
     261             :                                        (ndr_push_flags_fn_t)
     262             :                                                ndr_push_GkdiDerivationCtx);
     263          13 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     264           0 :                 return ndr_map_error2ntstatus(ndr_err);
     265             :         }
     266             : 
     267          13 :         return NT_STATUS_OK;
     268             : }
     269             : 
     270             : struct GkdiContext {
     271             :         struct GkdiDerivationCtx ctx;
     272             :         gnutls_mac_algorithm_t algorithm;
     273             : };
     274             : 
     275          15 : gnutls_mac_algorithm_t get_sp800_108_mac_algorithm(
     276             :         const struct KdfAlgorithm kdf_algorithm)
     277             : {
     278          15 :         switch (kdf_algorithm.id) {
     279          15 :         case KDF_ALGORITHM_SP800_108_CTR_HMAC:
     280          15 :                 switch (kdf_algorithm.param.sp800_108) {
     281           0 :                 case KDF_PARAM_SHA1:
     282           0 :                         return GNUTLS_MAC_SHA1;
     283           0 :                 case KDF_PARAM_SHA256:
     284           0 :                         return GNUTLS_MAC_SHA256;
     285           0 :                 case KDF_PARAM_SHA384:
     286           0 :                         return GNUTLS_MAC_SHA384;
     287           0 :                 case KDF_PARAM_SHA512:
     288           0 :                         return GNUTLS_MAC_SHA512;
     289             :                 }
     290           0 :                 break;
     291             :         }
     292             : 
     293           0 :         return GNUTLS_MAC_UNKNOWN;
     294             : }
     295             : 
     296          17 : static NTSTATUS GkdiContext(const struct ProvRootKey *const root_key,
     297             :                             struct GkdiContext *const ctx)
     298             : {
     299          17 :         NTSTATUS status = NT_STATUS_OK;
     300          17 :         gnutls_mac_algorithm_t algorithm = GNUTLS_MAC_UNKNOWN;
     301             : 
     302          17 :         if (ctx == NULL) {
     303           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     304           0 :                 goto out;
     305             :         }
     306             : 
     307          17 :         if (root_key == NULL) {
     308           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     309           0 :                 goto out;
     310             :         }
     311             : 
     312          17 :         if (root_key->version != root_key_version_1) {
     313           2 :                 status = NT_STATUS_NOT_SUPPORTED;
     314           2 :                 goto out;
     315             :         }
     316             : 
     317          15 :         if (root_key->data.length != GKDI_KEY_LEN) {
     318           1 :                 status = NT_STATUS_NOT_SUPPORTED;
     319           1 :                 goto out;
     320             :         }
     321             : 
     322          14 :         algorithm = get_sp800_108_mac_algorithm(root_key->kdf_algorithm);
     323          14 :         if (algorithm == GNUTLS_MAC_UNKNOWN) {
     324           1 :                 status = NT_STATUS_NOT_SUPPORTED;
     325           1 :                 goto out;
     326             :         }
     327             : 
     328             :         /*
     329             :          * The context comprises the GUID corresponding to the root key, the
     330             :          * GKID (which we shall initialize to zero), and the encoded target
     331             :          * security descriptor (which will initially be empty).
     332             :          */
     333          13 :         *ctx = (struct GkdiContext){
     334           0 :                 .ctx = {.guid = root_key->id,
     335             :                         .l0_idx = 0,
     336             :                         .l1_idx = 0,
     337             :                         .l2_idx = 0,
     338             :                         .target_security_descriptor = {}},
     339             :                 .algorithm = algorithm,
     340             :         };
     341          17 : out:
     342          17 :         return status;
     343             : }
     344             : 
     345          13 : static NTSTATUS compute_l1_seed_key(TALLOC_CTX *mem_ctx,
     346             :                                     struct GkdiContext *ctx,
     347             :                                     const DATA_BLOB security_descriptor,
     348             :                                     const struct ProvRootKey *const root_key,
     349             :                                     const struct Gkid gkid,
     350             :                                     uint8_t key[static const GKDI_KEY_LEN])
     351             : {
     352          13 :         NTSTATUS status = NT_STATUS_OK;
     353          13 :         struct GkdiContextShort short_ctx;
     354          13 :         int8_t n;
     355             : 
     356          13 :         ctx->ctx.l0_idx = gkid.l0_idx;
     357          13 :         ctx->ctx.l1_idx = -1;
     358          13 :         ctx->ctx.l2_idx = -1;
     359             : 
     360          13 :         status = make_gkdi_context(&ctx->ctx, &short_ctx);
     361          13 :         if (!NT_STATUS_IS_OK(status)) {
     362           0 :                 goto out;
     363             :         }
     364             : 
     365             :         /* Derive an L0 seed key with GKID = (L0, −1, −1). */
     366             : 
     367          26 :         status = samba_gnutls_sp800_108_derive_key(root_key->data.data,
     368          13 :                                                    root_key->data.length,
     369             :                                                    NULL,
     370             :                                                    0,
     371             :                                                    kds_service,
     372             :                                                    sizeof kds_service,
     373             :                                                    short_ctx.buf,
     374             :                                                    sizeof short_ctx.buf,
     375             :                                                    ctx->algorithm,
     376             :                                                    key,
     377             :                                                    GKDI_KEY_LEN);
     378          13 :         if (!NT_STATUS_IS_OK(status)) {
     379           0 :                 goto out;
     380             :         }
     381             : 
     382             :         /* Derive an L1 seed key with GKID = (L0, 31, −1). */
     383             : 
     384          13 :         ctx->ctx.l1_idx = 31;
     385             : 
     386             :         {
     387          13 :                 DATA_BLOB security_descriptor_ctx;
     388             : 
     389          13 :                 status = make_gkdi_context_security_descriptor(
     390             :                         mem_ctx,
     391           0 :                         &ctx->ctx,
     392             :                         security_descriptor,
     393             :                         &security_descriptor_ctx);
     394          13 :                 if (!NT_STATUS_IS_OK(status)) {
     395           0 :                         goto out;
     396             :                 }
     397             : 
     398          26 :                 status = samba_gnutls_sp800_108_derive_key(
     399             :                         key,
     400             :                         GKDI_KEY_LEN,
     401             :                         NULL,
     402             :                         0,
     403             :                         kds_service,
     404             :                         sizeof kds_service,
     405          13 :                         security_descriptor_ctx.data,
     406             :                         security_descriptor_ctx.length,
     407             :                         ctx->algorithm,
     408             :                         key,
     409             :                         GKDI_KEY_LEN);
     410          13 :                 data_blob_free(&security_descriptor_ctx);
     411          13 :                 if (!NT_STATUS_IS_OK(status)) {
     412           0 :                         goto out;
     413             :                 }
     414             :         }
     415             : 
     416         197 :         for (n = 30; n >= gkid.l1_idx; --n) {
     417             :                 /* Derive an L1 seed key with GKID = (L0, n, −1). */
     418             : 
     419         184 :                 ctx->ctx.l1_idx = n;
     420             : 
     421         184 :                 status = make_gkdi_context(&ctx->ctx, &short_ctx);
     422         184 :                 if (!NT_STATUS_IS_OK(status)) {
     423           0 :                         goto out;
     424             :                 }
     425             : 
     426         184 :                 status = samba_gnutls_sp800_108_derive_key(key,
     427             :                                                            GKDI_KEY_LEN,
     428             :                                                            NULL,
     429             :                                                            0,
     430             :                                                            kds_service,
     431             :                                                            sizeof kds_service,
     432             :                                                            short_ctx.buf,
     433             :                                                            sizeof short_ctx.buf,
     434             :                                                            ctx->algorithm,
     435             :                                                            key,
     436             :                                                            GKDI_KEY_LEN);
     437         184 :                 if (!NT_STATUS_IS_OK(status)) {
     438           0 :                         goto out;
     439             :                 }
     440             :         }
     441             : 
     442          13 : out:
     443          13 :         return status;
     444             : }
     445             : 
     446           7 : static NTSTATUS derive_l2_seed_key(struct GkdiContext *ctx,
     447             :                                    const struct Gkid gkid,
     448             :                                    uint8_t key[static const GKDI_KEY_LEN])
     449             : {
     450           7 :         NTSTATUS status = NT_STATUS_OK;
     451           7 :         int8_t n;
     452             : 
     453           7 :         ctx->ctx.l0_idx = gkid.l0_idx;
     454           7 :         ctx->ctx.l1_idx = gkid.l1_idx;
     455             : 
     456         133 :         for (n = 31; n >= gkid.l2_idx; --n) {
     457         126 :                 struct GkdiContextShort short_ctx;
     458             : 
     459             :                 /* Derive an L2 seed key with GKID = (L0, L1, n). */
     460             : 
     461         126 :                 ctx->ctx.l2_idx = n;
     462             : 
     463         126 :                 status = make_gkdi_context(&ctx->ctx, &short_ctx);
     464         126 :                 if (!NT_STATUS_IS_OK(status)) {
     465           0 :                         goto out;
     466             :                 }
     467             : 
     468         126 :                 status = samba_gnutls_sp800_108_derive_key(key,
     469             :                                                            GKDI_KEY_LEN,
     470             :                                                            NULL,
     471             :                                                            0,
     472             :                                                            kds_service,
     473             :                                                            sizeof kds_service,
     474             :                                                            short_ctx.buf,
     475             :                                                            sizeof short_ctx.buf,
     476             :                                                            ctx->algorithm,
     477             :                                                            key,
     478             :                                                            GKDI_KEY_LEN);
     479         126 :                 if (!NT_STATUS_IS_OK(status)) {
     480           0 :                         goto out;
     481             :                 }
     482             :         }
     483             : 
     484           7 : out:
     485           7 :         return status;
     486             : }
     487             : 
     488          20 : enum GkidType gkid_key_type(const struct Gkid gkid)
     489             : {
     490          20 :         if (gkid.l0_idx == -1) {
     491           0 :                 return GKID_DEFAULT;
     492             :         }
     493             : 
     494          19 :         if (gkid.l1_idx == -1) {
     495           0 :                 return GKID_L0_SEED_KEY;
     496             :         }
     497             : 
     498          18 :         if (gkid.l2_idx == -1) {
     499           6 :                 return GKID_L1_SEED_KEY;
     500             :         }
     501             : 
     502           0 :         return GKID_L2_SEED_KEY;
     503             : }
     504             : 
     505          27 : bool gkid_is_valid(const struct Gkid gkid)
     506             : {
     507          27 :         if (gkid.l0_idx < -1) {
     508           0 :                 return false;
     509             :         }
     510             : 
     511          26 :         if (gkid.l1_idx < -1 || gkid.l1_idx >= gkdi_l1_key_iteration) {
     512           0 :                 return false;
     513             :         }
     514             : 
     515          24 :         if (gkid.l2_idx < -1 || gkid.l2_idx >= gkdi_l2_key_iteration) {
     516           0 :                 return false;
     517             :         }
     518             : 
     519          22 :         if (gkid.l0_idx == -1 && gkid.l1_idx != -1) {
     520           0 :                 return false;
     521             :         }
     522             : 
     523          21 :         if (gkid.l1_idx == -1 && gkid.l2_idx != -1) {
     524           1 :                 return false;
     525             :         }
     526             : 
     527           0 :         return true;
     528             : }
     529             : 
     530          26 : NTSTATUS compute_seed_key(TALLOC_CTX *mem_ctx,
     531             :                           const DATA_BLOB target_security_descriptor,
     532             :                           const struct ProvRootKey *const root_key,
     533             :                           const struct Gkid gkid,
     534             :                           uint8_t key[static const GKDI_KEY_LEN])
     535             : {
     536          26 :         NTSTATUS status = NT_STATUS_OK;
     537          26 :         enum GkidType gkid_type;
     538          26 :         struct GkdiContext ctx;
     539             : 
     540          26 :         if (!gkid_is_valid(gkid)) {
     541           7 :                 status = NT_STATUS_INVALID_PARAMETER;
     542           7 :                 goto out;
     543             :         }
     544             : 
     545          19 :         gkid_type = gkid_key_type(gkid);
     546          19 :         if (gkid_type < GKID_L1_SEED_KEY) {
     547             :                 /* Don’t allow derivation of L0 seed keys. */
     548           2 :                 status = NT_STATUS_INVALID_PARAMETER;
     549           2 :                 goto out;
     550             :         }
     551             : 
     552          17 :         status = GkdiContext(root_key, &ctx);
     553          17 :         if (!NT_STATUS_IS_OK(status)) {
     554           4 :                 goto out;
     555             :         }
     556             : 
     557          13 :         status = compute_l1_seed_key(
     558             :                 mem_ctx, &ctx, target_security_descriptor, root_key, gkid, key);
     559          13 :         if (!NT_STATUS_IS_OK(status)) {
     560           0 :                 goto out;
     561             :         }
     562             : 
     563          13 :         if (gkid_type == GKID_L2_SEED_KEY) {
     564           7 :                 status = derive_l2_seed_key(&ctx, gkid, key);
     565           7 :                 if (!NT_STATUS_IS_OK(status)) {
     566           0 :                         goto out;
     567             :                 }
     568             :         }
     569             : 
     570          13 : out:
     571          26 :         return status;
     572             : }
     573             : 
     574           0 : NTSTATUS kdf_sp_800_108_from_params(
     575             :         const DATA_BLOB *const kdf_param,
     576             :         struct KdfAlgorithm *const kdf_algorithm_out)
     577             : {
     578           0 :         TALLOC_CTX *tmp_ctx = NULL;
     579           0 :         NTSTATUS status = NT_STATUS_OK;
     580           0 :         enum ndr_err_code err;
     581           0 :         enum KdfSp800_108Param sp800_108_param = KDF_PARAM_SHA256;
     582           0 :         struct KdfParameters kdf_parameters;
     583             : 
     584           0 :         if (kdf_param != NULL) {
     585           0 :                 tmp_ctx = talloc_new(NULL);
     586           0 :                 if (tmp_ctx == NULL) {
     587           0 :                         status = NT_STATUS_NO_MEMORY;
     588           0 :                         goto out;
     589             :                 }
     590             : 
     591           0 :                 err = ndr_pull_struct_blob(kdf_param,
     592             :                                            tmp_ctx,
     593             :                                            &kdf_parameters,
     594             :                                            (ndr_pull_flags_fn_t)
     595             :                                                    ndr_pull_KdfParameters);
     596           0 :                 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
     597           0 :                         status = ndr_map_error2ntstatus(err);
     598           0 :                         DBG_WARNING("KdfParameters pull failed: %s\n",
     599             :                                     nt_errstr(status));
     600           0 :                         goto out;
     601             :                 }
     602             : 
     603           0 :                 if (kdf_parameters.hash_algorithm == NULL) {
     604           0 :                         status = NT_STATUS_NOT_SUPPORTED;
     605           0 :                         goto out;
     606             :                 }
     607             : 
     608             :                 /* These string comparisons are case‐sensitive. */
     609           0 :                 if (strcmp(kdf_parameters.hash_algorithm, "SHA1") == 0) {
     610           0 :                         sp800_108_param = KDF_PARAM_SHA1;
     611           0 :                 } else if (strcmp(kdf_parameters.hash_algorithm, "SHA256") == 0)
     612             :                 {
     613           0 :                         sp800_108_param = KDF_PARAM_SHA256;
     614           0 :                 } else if (strcmp(kdf_parameters.hash_algorithm, "SHA384") == 0)
     615             :                 {
     616           0 :                         sp800_108_param = KDF_PARAM_SHA384;
     617           0 :                 } else if (strcmp(kdf_parameters.hash_algorithm, "SHA512") == 0)
     618             :                 {
     619           0 :                         sp800_108_param = KDF_PARAM_SHA512;
     620             :                 } else {
     621           0 :                         status = NT_STATUS_NOT_SUPPORTED;
     622           0 :                         goto out;
     623             :                 }
     624             :         }
     625             : 
     626           0 :         *kdf_algorithm_out = (struct KdfAlgorithm){
     627             :                 .id = KDF_ALGORITHM_SP800_108_CTR_HMAC,
     628             :                 .param.sp800_108 = sp800_108_param,
     629             :         };
     630           0 : out:
     631           0 :         talloc_free(tmp_ctx);
     632           0 :         return status;
     633             : }
     634             : 
     635           0 : NTSTATUS kdf_algorithm_from_params(const char *const kdf_algorithm_id,
     636             :                                    const DATA_BLOB *const kdf_param,
     637             :                                    struct KdfAlgorithm *const kdf_algorithm_out)
     638             : {
     639           0 :         if (kdf_algorithm_id == NULL) {
     640           0 :                 return NT_STATUS_INVALID_PARAMETER;
     641             :         }
     642             : 
     643             :         /* This string comparison is case‐sensitive. */
     644           0 :         if (strcmp(kdf_algorithm_id, "SP800_108_CTR_HMAC") == 0) {
     645           0 :                 return kdf_sp_800_108_from_params(kdf_param, kdf_algorithm_out);
     646             :         }
     647             : 
     648             :         /* Unknown algorithm. */
     649           0 :         return NT_STATUS_NOT_SUPPORTED;
     650             : }

Generated by: LCOV version 1.14