LCOV - code coverage report
Current view: top level - lib/crypto - gkdi.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 209 274 76.3 %
Date: 2024-04-21 15:09:00 Functions: 19 20 95.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          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             : }

Generated by: LCOV version 1.14