s4:dsdb: Add functions for GKDI root key creation
[samba.git] / source4 / dsdb / gmsa / gkdi.c
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
34 static int gkdi_create_root_key(TALLOC_CTX *mem_ctx,
35                                 struct ldb_context *const ldb,
36                                 const NTTIME current_time,
37                                 const NTTIME use_start_time,
38                                 struct GUID *const root_key_id_out,
39                                 struct ldb_dn **const root_key_dn_out)
40 {
41         TALLOC_CTX *tmp_ctx = NULL;
42         struct GUID root_key_id;
43         struct ldb_message *add_msg = NULL;
44         NTSTATUS status = NT_STATUS_OK;
45         int ret = LDB_SUCCESS;
46
47         *root_key_dn_out = NULL;
48
49         tmp_ctx = talloc_new(mem_ctx);
50         if (tmp_ctx == NULL) {
51                 ret = ldb_oom(ldb);
52                 goto out;
53         }
54
55         add_msg = ldb_msg_new(tmp_ctx);
56         if (add_msg == NULL) {
57                 ret = ldb_oom(ldb);
58                 goto out;
59         }
60
61         ret = ldb_msg_append_string(add_msg,
62                                     "objectClass",
63                                     "msKds-ProvRootKey",
64                                     LDB_FLAG_MOD_ADD);
65         if (ret) {
66                 goto out;
67         }
68
69         {
70                 uint8_t root_key_data[GKDI_KEY_LEN];
71                 const DATA_BLOB root_key_data_blob = {
72                         .data = root_key_data, .length = sizeof root_key_data};
73
74                 generate_secret_buffer(root_key_data, sizeof root_key_data);
75
76                 ret = ldb_msg_append_value(add_msg,
77                                            "msKds-RootKeyData",
78                                            &root_key_data_blob,
79                                            LDB_FLAG_MOD_ADD);
80                 if (ret) {
81                         goto out;
82                 }
83         }
84
85         ret = samdb_msg_append_uint64(ldb,
86                                       tmp_ctx,
87                                       add_msg,
88                                       "msKds-CreateTime",
89                                       current_time,
90                                       LDB_FLAG_MOD_ADD);
91         if (ret) {
92                 goto out;
93         }
94
95         ret = samdb_msg_append_uint64(ldb,
96                                       tmp_ctx,
97                                       add_msg,
98                                       "msKds-UseStartTime",
99                                       use_start_time,
100                                       LDB_FLAG_MOD_ADD);
101         if (ret) {
102                 goto out;
103         }
104
105         {
106                 struct ldb_dn *domain_dn = NULL;
107
108                 ret = samdb_server_reference_dn(ldb, tmp_ctx, &domain_dn);
109                 if (ret) {
110                         goto out;
111                 }
112
113                 ret = ldb_msg_append_linearized_dn(add_msg,
114                                                    "msKds-DomainID",
115                                                    domain_dn,
116                                                    LDB_FLAG_MOD_ADD);
117                 if (ret) {
118                         goto out;
119                 }
120         }
121
122         ret = ldb_msg_append_string(add_msg,
123                                     "msKds-Version",
124                                     "1",
125                                     LDB_FLAG_MOD_ADD);
126         if (ret) {
127                 goto out;
128         }
129
130         ret = ldb_msg_append_string(add_msg,
131                                     "msKds-KDFAlgorithmID",
132                                     "SP800_108_CTR_HMAC",
133                                     LDB_FLAG_MOD_ADD);
134         if (ret) {
135                 goto out;
136         }
137
138         ret = ldb_msg_append_string(add_msg,
139                                     "msKds-SecretAgreementAlgorithmID",
140                                     "DH",
141                                     LDB_FLAG_MOD_ADD);
142         if (ret) {
143                 goto out;
144         }
145
146         {
147                 static const uint8_t ffc_dh_parameters[] = {
148                         12,  2,   0,   0,   68,  72,  80,  77,  0,   1,   0,
149                         0,   135, 168, 230, 29,  180, 182, 102, 60,  255, 187,
150                         209, 156, 101, 25,  89,  153, 140, 238, 246, 8,   102,
151                         13,  208, 242, 93,  44,  238, 212, 67,  94,  59,  0,
152                         224, 13,  248, 241, 214, 25,  87,  212, 250, 247, 223,
153                         69,  97,  178, 170, 48,  22,  195, 217, 17,  52,  9,
154                         111, 170, 59,  244, 41,  109, 131, 14,  154, 124, 32,
155                         158, 12,  100, 151, 81,  122, 189, 90,  138, 157, 48,
156                         107, 207, 103, 237, 145, 249, 230, 114, 91,  71,  88,
157                         192, 34,  224, 177, 239, 66,  117, 191, 123, 108, 91,
158                         252, 17,  212, 95,  144, 136, 185, 65,  245, 78,  177,
159                         229, 155, 184, 188, 57,  160, 191, 18,  48,  127, 92,
160                         79,  219, 112, 197, 129, 178, 63,  118, 182, 58,  202,
161                         225, 202, 166, 183, 144, 45,  82,  82,  103, 53,  72,
162                         138, 14,  241, 60,  109, 154, 81,  191, 164, 171, 58,
163                         216, 52,  119, 150, 82,  77,  142, 246, 161, 103, 181,
164                         164, 24,  37,  217, 103, 225, 68,  229, 20,  5,   100,
165                         37,  28,  202, 203, 131, 230, 180, 134, 246, 179, 202,
166                         63,  121, 113, 80,  96,  38,  192, 184, 87,  246, 137,
167                         150, 40,  86,  222, 212, 1,   10,  189, 11,  230, 33,
168                         195, 163, 150, 10,  84,  231, 16,  195, 117, 242, 99,
169                         117, 215, 1,   65,  3,   164, 181, 67,  48,  193, 152,
170                         175, 18,  97,  22,  210, 39,  110, 17,  113, 95,  105,
171                         56,  119, 250, 215, 239, 9,   202, 219, 9,   74,  233,
172                         30,  26,  21,  151, 63,  179, 44,  155, 115, 19,  77,
173                         11,  46,  119, 80,  102, 96,  237, 189, 72,  76,  167,
174                         177, 143, 33,  239, 32,  84,  7,   244, 121, 58,  26,
175                         11,  161, 37,  16,  219, 193, 80,  119, 190, 70,  63,
176                         255, 79,  237, 74,  172, 11,  181, 85,  190, 58,  108,
177                         27,  12,  107, 71,  177, 188, 55,  115, 191, 126, 140,
178                         111, 98,  144, 18,  40,  248, 194, 140, 187, 24,  165,
179                         90,  227, 19,  65,  0,   10,  101, 1,   150, 249, 49,
180                         199, 122, 87,  242, 221, 244, 99,  229, 233, 236, 20,
181                         75,  119, 125, 230, 42,  170, 184, 168, 98,  138, 195,
182                         118, 210, 130, 214, 237, 56,  100, 230, 121, 130, 66,
183                         142, 188, 131, 29,  20,  52,  143, 111, 47,  145, 147,
184                         181, 4,   90,  242, 118, 113, 100, 225, 223, 201, 103,
185                         193, 251, 63,  46,  85,  164, 189, 27,  255, 232, 59,
186                         156, 128, 208, 82,  185, 133, 209, 130, 234, 10,  219,
187                         42,  59,  115, 19,  211, 254, 20,  200, 72,  75,  30,
188                         5,   37,  136, 185, 183, 210, 187, 210, 223, 1,   97,
189                         153, 236, 208, 110, 21,  87,  205, 9,   21,  179, 53,
190                         59,  187, 100, 224, 236, 55,  127, 208, 40,  55,  13,
191                         249, 43,  82,  199, 137, 20,  40,  205, 198, 126, 182,
192                         24,  75,  82,  61,  29,  178, 70,  195, 47,  99,  7,
193                         132, 144, 240, 14,  248, 214, 71,  209, 72,  212, 121,
194                         84,  81,  94,  35,  39,  207, 239, 152, 197, 130, 102,
195                         75,  76,  15,  108, 196, 22,  89};
196                 const DATA_BLOB ffc_dh_parameters_blob = {
197                         discard_const_p(uint8_t, ffc_dh_parameters),
198                         sizeof ffc_dh_parameters};
199
200                 ret = ldb_msg_append_value(add_msg,
201                                            "msKds-SecretAgreementParam",
202                                            &ffc_dh_parameters_blob,
203                                            LDB_FLAG_MOD_ADD);
204                 if (ret) {
205                         goto out;
206                 }
207         }
208
209         ret = ldb_msg_append_string(add_msg,
210                                     "msKds-PublicKeyLength",
211                                     "2048",
212                                     LDB_FLAG_MOD_ADD);
213         if (ret) {
214                 goto out;
215         }
216
217         ret = ldb_msg_append_string(add_msg,
218                                     "msKds-PrivateKeyLength",
219                                     "512",
220                                     LDB_FLAG_MOD_ADD);
221         if (ret) {
222                 goto out;
223         }
224
225         {
226                 static const uint8_t kdf_parameters[] = {
227                         0,   0, 0,   0, 1,   0, 0,   0, 14,  0,
228                         0,   0, 0,   0, 0,   0, 'S', 0, 'H', 0,
229                         'A', 0, '5', 0, '1', 0, '2', 0, 0,   0,
230                 };
231                 const DATA_BLOB kdf_parameters_blob = {
232                         discard_const_p(uint8_t, kdf_parameters),
233                         sizeof kdf_parameters};
234
235                 ret = ldb_msg_append_value(add_msg,
236                                            "msKds-KDFParam",
237                                            &kdf_parameters_blob,
238                                            LDB_FLAG_MOD_ADD);
239                 if (ret) {
240                         goto out;
241                 }
242         }
243
244         {
245                 uint8_t guid_buf[sizeof((struct GUID_ndr_buf){}.buf)];
246                 const DATA_BLOB guid_blob = {.data = guid_buf,
247                                              .length = sizeof guid_buf};
248
249                 generate_secret_buffer(guid_buf, sizeof guid_buf);
250
251                 status = GUID_from_ndr_blob(&guid_blob, &root_key_id);
252                 if (!NT_STATUS_IS_OK(status)) {
253                         ret = ldb_operr(ldb);
254                         goto out;
255                 }
256         }
257
258         {
259                 struct ldb_dn *root_key_dn = NULL;
260
261                 root_key_dn = samdb_gkdi_root_key_dn(ldb,
262                                                      tmp_ctx,
263                                                      &root_key_id);
264                 if (root_key_dn == NULL) {
265                         ret = ldb_operr(ldb);
266                         goto out;
267                 }
268
269                 add_msg->dn = root_key_dn;
270         }
271
272         ret = dsdb_add(ldb, add_msg, 0);
273         if (ret) {
274                 goto out;
275         }
276
277         *root_key_id_out = root_key_id;
278         *root_key_dn_out = talloc_steal(mem_ctx, add_msg->dn);
279
280 out:
281         talloc_free(tmp_ctx);
282         return ret;
283 }
284
285 /*
286  * The PrivateKey, PublicKey, and SecretAgreement attributes are related to the
287  * public‐key functionality in GKDI. Samba doesn’t try to implement any of that,
288  * so we don’t bother looking at these attributes.
289  */
290 static const char *const root_key_attrs[] = {
291         "msKds-CreateTime",
292         "msKds-DomainID",
293         "msKds-KDFAlgorithmID",
294         "msKds-KDFParam",
295         /* "msKds-PrivateKeyLength", */
296         /* "msKds-PublicKeyLength", */
297         "msKds-RootKeyData",
298         /* "msKds-SecretAgreementAlgorithmID", */
299         /* "msKds-SecretAgreementParam", */
300         "msKds-UseStartTime",
301         "msKds-Version",
302         NULL,
303 };
304
305 /*
306  * Create and return a new GKDI root key.
307  *
308  * This function goes unused.
309  */
310 int gkdi_new_root_key(TALLOC_CTX *mem_ctx,
311                       struct ldb_context *const ldb,
312                       const NTTIME current_time,
313                       const NTTIME use_start_time,
314                       struct GUID *const root_key_id_out,
315                       const struct ldb_message **const root_key_out)
316 {
317         TALLOC_CTX *tmp_ctx = NULL;
318         struct ldb_dn *root_key_dn = NULL;
319         struct ldb_result *res = NULL;
320         int ret = LDB_SUCCESS;
321
322         *root_key_out = NULL;
323
324         tmp_ctx = talloc_new(mem_ctx);
325         if (tmp_ctx == NULL) {
326                 ret = ldb_oom(ldb);
327                 goto out;
328         }
329
330         ret = gkdi_create_root_key(tmp_ctx,
331                                    ldb,
332                                    current_time,
333                                    use_start_time,
334                                    root_key_id_out,
335                                    &root_key_dn);
336         if (ret) {
337                 goto out;
338         }
339
340         ret = dsdb_search_dn(
341                 ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
342         if (ret) {
343                 goto out;
344         }
345
346         if (res->count != 1) {
347                 ret = LDB_ERR_NO_SUCH_OBJECT;
348                 goto out;
349         }
350
351         *root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
352
353 out:
354         talloc_free(tmp_ctx);
355         return ret;
356 }