LCOV - code coverage report
Current view: top level - source4/dsdb/gmsa - gkdi.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 202 262 77.1 %
Date: 2024-05-31 13:13:24 Functions: 5 6 83.3 %

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

Generated by: LCOV version 1.14