/src/samba/librpc/ndr/ndr_keycredlink.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | Support routines for packing and unpacking of msDS-KeyCredentialLink |
5 | | structures. |
6 | | |
7 | | See [MS-ADTS] 2.2.20 Key Credential Link Structures |
8 | | |
9 | | Copyright (C) Gary Lockyer 2025 |
10 | | |
11 | | This program is free software; you can redistribute it and/or modify |
12 | | it under the terms of the GNU General Public License as published by |
13 | | the Free Software Foundation; either version 3 of the License, or |
14 | | (at your option) any later version. |
15 | | |
16 | | This program is distributed in the hope that it will be useful, |
17 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | | GNU General Public License for more details. |
20 | | |
21 | | You should have received a copy of the GNU General Public License |
22 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 | | */ |
24 | | |
25 | | #include "lib/replace/replace.h" |
26 | | |
27 | | #include "gen_ndr/ndr_keycredlink.h" |
28 | | #include "lib/util/data_blob.h" |
29 | | #include "libndr.h" |
30 | | #include "librpc/gen_ndr/ndr_bcrypt_rsakey_blob.h" |
31 | | #include "librpc/gen_ndr/ndr_tpm20_rsakey_blob.h" |
32 | | #include "util/asn1.h" |
33 | | #include "util/data_blob.h" |
34 | | #include <assert.h> |
35 | | |
36 | | /* |
37 | | * The KEYCREDENTIALLINK_BLOB consists of the version and a series of variable |
38 | | * length KEYCREDENTIALLINK_ENTRIES. |
39 | | */ |
40 | | enum ndr_err_code ndr_pull_KEYCREDENTIALLINK_BLOB( |
41 | | struct ndr_pull *ndr, |
42 | | ndr_flags_type ndr_flags, |
43 | | struct KEYCREDENTIALLINK_BLOB *blob) |
44 | 528 | { |
45 | 528 | libndr_flags _flags_save_STRUCT = ndr->flags; |
46 | 528 | ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); |
47 | | |
48 | 528 | NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &blob->version)); |
49 | 524 | if (blob->version != 0x0200) { |
50 | 36 | return ndr_pull_error(ndr, |
51 | 36 | NDR_ERR_RANGE, |
52 | 36 | "Invalid version of (0x%04x) " |
53 | 36 | "should be 0x0200, at byte %zu\n", |
54 | 36 | blob->version, |
55 | 36 | (ndr->offset - sizeof(uint32_t))); |
56 | 36 | } |
57 | 488 | blob->count = 0; |
58 | 488 | blob->entries = talloc_array(ndr->current_mem_ctx, |
59 | 488 | struct KEYCREDENTIALLINK_ENTRY, |
60 | 488 | blob->count); |
61 | 488 | if (blob->entries == NULL) { |
62 | 0 | return ndr_pull_error(ndr, |
63 | 0 | NDR_ERR_ALLOC, |
64 | 0 | "Failed to pull KEYCREDENTIALLINK_ENTRY"); |
65 | 0 | } |
66 | 125k | while (ndr->offset < ndr->data_size) { |
67 | 125k | blob->entries = talloc_realloc(ndr->current_mem_ctx, |
68 | 125k | blob->entries, |
69 | 125k | struct KEYCREDENTIALLINK_ENTRY, |
70 | 125k | blob->count + 1); |
71 | 125k | if (blob->entries == NULL) { |
72 | 0 | return ndr_pull_error( |
73 | 0 | ndr, |
74 | 0 | NDR_ERR_ALLOC, |
75 | 0 | "Failed to pull KEYCREDENTIALLINK_ENTRY"); |
76 | 0 | } |
77 | 125k | NDR_CHECK(ndr_pull_KEYCREDENTIALLINK_ENTRY( |
78 | 125k | ndr, ndr_flags, &blob->entries[blob->count])); |
79 | 124k | blob->count++; |
80 | 124k | } |
81 | 259 | ndr->flags = _flags_save_STRUCT; |
82 | 259 | return NDR_ERR_SUCCESS; |
83 | 488 | } |
84 | | |
85 | | enum ndr_err_code ndr_push_KEYCREDENTIALLINK_BLOB( |
86 | | struct ndr_push *ndr, |
87 | | ndr_flags_type ndr_flags, |
88 | | const struct KEYCREDENTIALLINK_BLOB *blob) |
89 | 259 | { |
90 | 259 | int i = 0; |
91 | | |
92 | 259 | if (blob->version != 0x0200) { |
93 | 0 | return ndr_push_error(ndr, |
94 | 0 | NDR_ERR_RANGE, |
95 | 0 | "Invalid version of (0x%04x) " |
96 | 0 | "should be 0x0200, at byte %zu\n", |
97 | 0 | blob->version, |
98 | 0 | (ndr->offset - sizeof(uint32_t))); |
99 | 0 | } |
100 | 259 | NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, blob->version)); |
101 | | |
102 | 37.0k | for (i = 0; i < blob->count; i++) { |
103 | 36.7k | NDR_CHECK(ndr_push_KEYCREDENTIALLINK_ENTRY(ndr, |
104 | 36.7k | ndr_flags, |
105 | 36.7k | &blob->entries[i])); |
106 | 36.7k | } |
107 | 259 | return NDR_ERR_SUCCESS; |
108 | 259 | } |
109 | | |
110 | | /* |
111 | | * To pull the CUSTOM_KEY_INFORMATION the length from the enclosing |
112 | | * KEYCREDENTIALLINK_ENTRY needs to be passed in. |
113 | | * |
114 | | * CUSTOM_KEY_INFORMATION has two representations based on the size parameter |
115 | | * |
116 | | * If size is 2 only the version and flags are expected. |
117 | | * If the size is greater than 2 then |
118 | | * version, flags, volType, supportsNotification, fekKeyVersion, |
119 | | * keyStrength and the reserved bytes are expected |
120 | | * Optionally followed by a series of EncodedExtendedCKI entries |
121 | | * |
122 | | */ |
123 | | static enum ndr_err_code pull_cki(struct ndr_pull *ndr, |
124 | | ndr_flags_type ndr_flags, |
125 | | struct CUSTOM_KEY_INFORMATION *info, |
126 | | uint32_t size) |
127 | 6.81k | { |
128 | | /* Calculate the end of the CUSTOM_KEY_INFORMATION in the raw bytes */ |
129 | 6.81k | uint32_t end_offset = ndr->offset + size; |
130 | | |
131 | | /* |
132 | | * Initialise the CUSTOM_KEY_INFORMATION, in case this is the |
133 | | * short form. |
134 | | */ |
135 | 6.81k | *info = (struct CUSTOM_KEY_INFORMATION){0}; |
136 | | |
137 | 6.81k | NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &info->version)); |
138 | 6.81k | if (info->version != 0x01) { |
139 | 8 | return ndr_pull_error(ndr, |
140 | 8 | NDR_ERR_RANGE, |
141 | 8 | "Invalid version of (0x%02x) " |
142 | 8 | "should be 0x01, at byte %zu\n", |
143 | 8 | info->version, |
144 | 8 | (ndr->offset - sizeof(uint8_t))); |
145 | 8 | } |
146 | 6.80k | NDR_CHECK(ndr_pull_CUSTOM_KEY_INFO_Flags(ndr, ndr_flags, &info->flags)); |
147 | | |
148 | 6.80k | if (size == 2) { |
149 | 544 | info->isExtended = false; |
150 | 544 | return NDR_ERR_SUCCESS; |
151 | 544 | } |
152 | 6.25k | info->isExtended = true; |
153 | 6.25k | NDR_CHECK(ndr_pull_CUSTOM_KEY_INFO_VolType(ndr, |
154 | 6.25k | ndr_flags, |
155 | 6.25k | &info->volType)); |
156 | 6.23k | NDR_CHECK(ndr_pull_CUSTOM_KEY_INFO_SupportsNotification( |
157 | 6.23k | ndr, ndr_flags, &info->supportsNotification)); |
158 | 6.23k | NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &info->fekKeyVersion)); |
159 | 6.22k | if (info->fekKeyVersion != 0x01) { |
160 | 19 | return ndr_pull_error(ndr, |
161 | 19 | NDR_ERR_RANGE, |
162 | 19 | "Invalid fekKeyVersion of (0x%02x) " |
163 | 19 | "should be 0x01, at byte %zu\n", |
164 | 19 | info->fekKeyVersion, |
165 | 19 | (ndr->offset - sizeof(uint8_t))); |
166 | 19 | } |
167 | 6.20k | NDR_CHECK(ndr_pull_CUSTOM_KEY_INFO_KeyStrength(ndr, |
168 | 6.20k | ndr_flags, |
169 | 6.20k | &info->keyStrength)); |
170 | 6.20k | NDR_CHECK(ndr_pull_array_uint8(ndr, ndr_flags, info->reserved, 10)); |
171 | | |
172 | | /* Pull the EncodedExtendedCKI values */ |
173 | 6.19k | info->count = 0; |
174 | 6.19k | info->cki = talloc_array(ndr->current_mem_ctx, |
175 | 6.19k | struct EncodedExtendedCKI, |
176 | 6.19k | info->count); |
177 | 6.19k | if (info->cki == NULL) { |
178 | 0 | return ndr_pull_error(ndr, |
179 | 0 | NDR_ERR_ALLOC, |
180 | 0 | "Failed to pull EncodedExtendCKI"); |
181 | 0 | } |
182 | 300k | while (ndr->offset < end_offset) { |
183 | 294k | info->cki = talloc_realloc(ndr->current_mem_ctx, |
184 | 294k | info->cki, |
185 | 294k | struct EncodedExtendedCKI, |
186 | 294k | info->count + 1); |
187 | 294k | if (info->cki == NULL) { |
188 | 0 | return ndr_pull_error( |
189 | 0 | ndr, |
190 | 0 | NDR_ERR_ALLOC, |
191 | 0 | "Failed to pull EncodedExtendedCKI"); |
192 | 0 | } |
193 | 294k | NDR_CHECK(ndr_pull_EncodedExtendedCKI(ndr, |
194 | 294k | ndr_flags, |
195 | 294k | &info->cki[info->count])); |
196 | 294k | info->count++; |
197 | 294k | } |
198 | 6.11k | return NDR_ERR_SUCCESS; |
199 | 6.19k | } |
200 | | |
201 | | /* |
202 | | * CUSTOM_KEY-INFORMATION has two representations with differing sizes |
203 | | * the flag isExtended controls which version is written. |
204 | | */ |
205 | | enum ndr_err_code ndr_push_CUSTOM_KEY_INFORMATION( |
206 | | struct ndr_push *ndr, |
207 | | ndr_flags_type ndr_flags, |
208 | | const struct CUSTOM_KEY_INFORMATION *info) |
209 | 2.96k | { |
210 | 2.96k | int i = 0; |
211 | | |
212 | 2.96k | if (info->version != 0x01) { |
213 | 0 | return ndr_push_error(ndr, |
214 | 0 | NDR_ERR_RANGE, |
215 | 0 | "Invalid version of (0x%02x) " |
216 | 0 | "should be 0x01, at byte %zu\n", |
217 | 0 | info->version, |
218 | 0 | (ndr->offset - sizeof(uint8_t))); |
219 | 0 | } |
220 | 2.96k | NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, info->version)); |
221 | 2.96k | NDR_CHECK(ndr_push_CUSTOM_KEY_INFO_Flags(ndr, ndr_flags, info->flags)); |
222 | 2.96k | if (!info->isExtended) { |
223 | 1.01k | return NDR_ERR_SUCCESS; |
224 | 1.01k | } |
225 | | |
226 | 1.94k | NDR_CHECK(ndr_push_CUSTOM_KEY_INFO_VolType(ndr, |
227 | 1.94k | ndr_flags, |
228 | 1.94k | info->volType)); |
229 | 1.94k | NDR_CHECK(ndr_push_CUSTOM_KEY_INFO_SupportsNotification( |
230 | 1.94k | ndr, ndr_flags, info->supportsNotification)); |
231 | 1.94k | if (info->fekKeyVersion != 0x01) { |
232 | 0 | return ndr_push_error(ndr, |
233 | 0 | NDR_ERR_RANGE, |
234 | 0 | "Invalid fekKeyVersion of (0x%02x) " |
235 | 0 | "should be 0x01, at byte %zu\n", |
236 | 0 | info->fekKeyVersion, |
237 | 0 | (ndr->offset - sizeof(uint8_t))); |
238 | 0 | } |
239 | 1.94k | NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, info->fekKeyVersion)); |
240 | 1.94k | NDR_CHECK(ndr_push_CUSTOM_KEY_INFO_KeyStrength(ndr, |
241 | 1.94k | ndr_flags, |
242 | 1.94k | info->keyStrength)); |
243 | 1.94k | NDR_CHECK(ndr_push_array_uint8(ndr, ndr_flags, info->reserved, 10)); |
244 | | |
245 | 215k | for (i = 0; i < info->count; i++) { |
246 | 214k | NDR_CHECK(ndr_push_EncodedExtendedCKI(ndr, |
247 | 214k | ndr_flags, |
248 | 214k | &info->cki[i])); |
249 | 214k | } |
250 | 1.94k | return NDR_ERR_SUCCESS; |
251 | 1.94k | } |
252 | | |
253 | | /* |
254 | | * To pull a KEYCREDENTIALLINK_Value the length from the enclosing |
255 | | * KEYCREDENTIALLINK_ENTRY needs to be passed in. |
256 | | * |
257 | | */ |
258 | | static enum ndr_err_code ndr_pull_value(struct ndr_pull *ndr, |
259 | | ndr_flags_type ndr_flags, |
260 | | union KEYCREDENTIALLINK_ENTRY_Value *r, |
261 | | uint32_t size) |
262 | 125k | { |
263 | 125k | uint32_t level; |
264 | 125k | const size_t header_len = sizeof(uint16_t) + sizeof(uint8_t); |
265 | 125k | const size_t identifier_len = sizeof(uint8_t); |
266 | 125k | libndr_flags flags_save = ndr->flags; |
267 | | |
268 | | /* this function should only be called if NDR_SCALARS is set */ |
269 | 125k | assert(ndr_flags & NDR_SCALARS); |
270 | | |
271 | 125k | ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); |
272 | | |
273 | | /* This token is not used again */ |
274 | 125k | NDR_CHECK(ndr_pull_steal_switch_value(ndr, r, &level)); |
275 | | |
276 | 125k | switch (level) { |
277 | 278 | case KeyID: { |
278 | 278 | if (size != 32) { |
279 | 17 | return ndr_pull_error(ndr, |
280 | 17 | NDR_ERR_ARRAY_SIZE, |
281 | 17 | "Invalid size of (%" PRIu32 |
282 | 17 | ") for KeyID " |
283 | 17 | "should be (32), at byte %zu\n", |
284 | 17 | size, |
285 | 17 | (ndr->offset - header_len)); |
286 | 17 | } |
287 | 261 | NDR_CHECK( |
288 | 261 | ndr_pull_array_uint8(ndr, NDR_SCALARS, r->keyId, size)); |
289 | 260 | break; |
290 | 261 | } |
291 | | |
292 | 278 | case KeyHash: { |
293 | 278 | if (size != 32) { |
294 | 19 | return ndr_pull_error(ndr, |
295 | 19 | NDR_ERR_ARRAY_SIZE, |
296 | 19 | "Invalid size of (%" PRIu32 |
297 | 19 | ") for KeyHash " |
298 | 19 | "should be (32), at byte %zu\n", |
299 | 19 | size, |
300 | 19 | (ndr->offset - header_len)); |
301 | 19 | } |
302 | 259 | NDR_CHECK(ndr_pull_array_uint8( |
303 | 259 | ndr, NDR_SCALARS, r->keyHash, size)); |
304 | 258 | break; |
305 | 259 | } |
306 | | |
307 | 25.4k | case KeyUsage: { |
308 | 25.4k | if (size != 1) { |
309 | 18 | return ndr_pull_error(ndr, |
310 | 18 | NDR_ERR_LENGTH, |
311 | 18 | "Invalid length of (%" PRIu32 |
312 | 18 | ") for KeyUsage " |
313 | 18 | "should be (1), at byte %zu\n", |
314 | 18 | size, |
315 | 18 | (ndr->offset - header_len)); |
316 | 18 | } |
317 | 25.4k | NDR_CHECK(ndr_pull_KEYCREDENTIALLINK_ENTRY_KeyUsage( |
318 | 25.4k | ndr, NDR_SCALARS, &r->keyUsage)); |
319 | 25.4k | break; |
320 | 25.4k | } |
321 | | |
322 | 40.1k | case KeySource: { |
323 | 40.1k | if (size != 1) { |
324 | 20 | return ndr_pull_error(ndr, |
325 | 20 | NDR_ERR_LENGTH, |
326 | 20 | "Invalid length of (%" PRIu32 |
327 | 20 | ") for KeySource " |
328 | 20 | "should be (1), at byte %zu\n", |
329 | 20 | size, |
330 | 20 | (ndr->offset - header_len)); |
331 | 20 | } |
332 | 40.1k | NDR_CHECK(ndr_pull_KEYCREDENTIALLINK_ENTRY_KeySource( |
333 | 40.1k | ndr, NDR_SCALARS, &r->keySource)); |
334 | 40.1k | break; |
335 | 40.1k | } |
336 | | |
337 | 40.1k | case KeyMaterial: { |
338 | 15.4k | if (size == 0) { |
339 | 1 | return ndr_pull_error( |
340 | 1 | ndr, |
341 | 1 | NDR_ERR_LENGTH, |
342 | 1 | "Invalid length of (%" PRIu32 |
343 | 1 | ") for keyMaterial " |
344 | 1 | "should be non zero, at byte %zu\n", |
345 | 1 | size, |
346 | 1 | (ndr->offset - header_len)); |
347 | 1 | } |
348 | 15.4k | NDR_PULL_NEED_BYTES(ndr, size); |
349 | 15.4k | r->keyMaterial = data_blob_talloc(ndr->current_mem_ctx, |
350 | 15.4k | ndr->data + ndr->offset, |
351 | 15.4k | size); |
352 | 15.4k | if (r->keyMaterial.data == NULL) { |
353 | 0 | return ndr_pull_error(ndr, |
354 | 0 | NDR_ERR_ALLOC, |
355 | 0 | "Failed to pull keyMaterial"); |
356 | 0 | } |
357 | 15.4k | ndr->offset += size; |
358 | 15.4k | break; |
359 | 15.4k | } |
360 | | |
361 | 302 | case DeviceId: { |
362 | 302 | if (size != 16) { |
363 | 16 | return ndr_pull_error(ndr, |
364 | 16 | NDR_ERR_ARRAY_SIZE, |
365 | 16 | "Invalid size of (%" PRIu32 |
366 | 16 | ") for KeySource " |
367 | 16 | "should be (1), at byte %zu\n", |
368 | 16 | size, |
369 | 16 | (ndr->offset - header_len)); |
370 | 16 | } |
371 | 286 | NDR_CHECK(ndr_pull_array_uint8( |
372 | 286 | ndr, NDR_SCALARS, r->deviceId, size)); |
373 | 285 | break; |
374 | 286 | } |
375 | | |
376 | 6.81k | case CustomKeyInformation: { |
377 | 6.81k | NDR_CHECK(pull_cki( |
378 | 6.81k | ndr, NDR_SCALARS, &r->customKeyInformation, size)); |
379 | 6.65k | break; |
380 | 6.81k | } |
381 | | |
382 | 6.65k | case KeyApproximateLastLogonTimeStamp: { |
383 | 980 | if (size != 8) { |
384 | 18 | return ndr_pull_error( |
385 | 18 | ndr, |
386 | 18 | NDR_ERR_LENGTH, |
387 | 18 | "Invalid length of (%" PRIu32 ") for " |
388 | 18 | "KeyApproximateLastLogonTimeStamp " |
389 | 18 | "should be (8), at byte %zu\n", |
390 | 18 | size, |
391 | 18 | (ndr->offset - header_len)); |
392 | 18 | } |
393 | 962 | NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->lastLogon)); |
394 | 947 | break; |
395 | 962 | } |
396 | | |
397 | 35.7k | case KeyCreationTime: { |
398 | 35.7k | if (size != 8) { |
399 | 17 | return ndr_pull_error(ndr, |
400 | 17 | NDR_ERR_RANGE, |
401 | 17 | "Invalid size of (%" PRIu32 |
402 | 17 | ") for " |
403 | 17 | "KeyCreationTime " |
404 | 17 | "should be (8), at byte %zu\n", |
405 | 17 | size, |
406 | 17 | (ndr->offset - header_len)); |
407 | 17 | } |
408 | 35.7k | NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->created)); |
409 | 35.7k | break; |
410 | 35.7k | } |
411 | | |
412 | 35.7k | default: |
413 | 58 | return ndr_pull_error(ndr, |
414 | 125k | NDR_ERR_BAD_SWITCH, |
415 | 125k | "Bad switch value %02x at byte %zu", |
416 | 125k | level, |
417 | 125k | ndr->offset - identifier_len); |
418 | 125k | } |
419 | 125k | ndr->flags = flags_save; |
420 | 125k | return NDR_ERR_SUCCESS; |
421 | 125k | } |
422 | | |
423 | | /* |
424 | | * Need to pass the length element of the KEYCREDENTIALLINK_ENTRY down to |
425 | | * ndr_pull_value, the code that pulls the KEYCREDENTIALLINK_ENTRY_Value. |
426 | | */ |
427 | | enum ndr_err_code ndr_pull_KEYCREDENTIALLINK_ENTRY( |
428 | | struct ndr_pull *ndr, |
429 | | ndr_flags_type ndr_flags, |
430 | | struct KEYCREDENTIALLINK_ENTRY *r) |
431 | 125k | { |
432 | 125k | libndr_flags _flags_save_STRUCT = ndr->flags; |
433 | 125k | ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); |
434 | 125k | if (ndr_flags & NDR_SCALARS) { |
435 | 125k | NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length)); |
436 | 125k | NDR_CHECK(ndr_pull_KEYCREDENTIALLINK_ENTRY_Identifier( |
437 | 125k | ndr, NDR_SCALARS, &r->identifier)); |
438 | 125k | NDR_CHECK(ndr_pull_set_switch_value(ndr, |
439 | 125k | &r->value, |
440 | 125k | r->identifier)); |
441 | 125k | NDR_CHECK( |
442 | 125k | ndr_pull_value(ndr, NDR_SCALARS, &r->value, r->length)); |
443 | 125k | } |
444 | 125k | ndr->flags = _flags_save_STRUCT; |
445 | 125k | return NDR_ERR_SUCCESS; |
446 | 125k | } |
447 | | |
448 | | /* @brief Check that the AlgorithmIdentifier element is correct |
449 | | * |
450 | | * AlgorithmIdentifier ::= SEQUENCE { |
451 | | * algorithm OBJECT IDENTIFIER, |
452 | | * parameters ANY DEFINED BY algorithm OPTIONAL |
453 | | * -- Should be NULL for RSA |
454 | | * } |
455 | | * |
456 | | * @param[in] ndr ndr pull context |
457 | | * @param[in,out] asn ASN data context |
458 | | * |
459 | | * @return NDR_ERR_SUCCESS if the element is valid. |
460 | | */ |
461 | | static enum ndr_err_code check_algorithm_identifier(struct ndr_pull *ndr, |
462 | | struct asn1_data *asn) |
463 | 242 | { |
464 | 242 | static const char *RSA_ENCRYPTION_OID = "1.2.840.113549.1.1.1"; |
465 | 242 | uint8_t asn1_null[2]; |
466 | 242 | if (!asn1_start_tag(asn, ASN1_SEQUENCE(0))) { |
467 | 27 | return ndr_pull_error( |
468 | 27 | ndr, |
469 | 27 | NDR_ERR_VALIDATE, |
470 | 27 | "Invalid ASN1 tag, expecting SEQUENCE 0x30"); |
471 | 27 | } |
472 | 215 | if (!asn1_check_OID(asn, RSA_ENCRYPTION_OID)) { |
473 | 215 | return ndr_pull_error( |
474 | 215 | ndr, |
475 | 215 | NDR_ERR_VALIDATE, |
476 | 215 | "Invalid ASN1 algorithm OID, expecting %s", |
477 | 215 | RSA_ENCRYPTION_OID); |
478 | 215 | } |
479 | | |
480 | | /* For an RSA public key, parameters should be null 0x0500 */ |
481 | 0 | if (!asn1_read(asn, asn1_null, 2)) { |
482 | 0 | return ndr_pull_error( |
483 | 0 | ndr, |
484 | 0 | NDR_ERR_VALIDATE, |
485 | 0 | "Unexpected ASN1 element, expecting NULL 0x05"); |
486 | 0 | } |
487 | 0 | if (!asn1_end_tag(asn)) { /* AlgorithmIdentifier */ |
488 | 0 | return ndr_pull_error(ndr, |
489 | 0 | NDR_ERR_UNREAD_BYTES, |
490 | 0 | "ASN1 element AlgorithmIdentifier"); |
491 | 0 | } |
492 | 0 | return NDR_ERR_SUCCESS; |
493 | 0 | } |
494 | | |
495 | | /** |
496 | | * @brief start processing a BIT STRING |
497 | | * |
498 | | * The caller will need to call asn1_end_tag |
499 | | * |
500 | | * @param[in] ndr ndr pull context |
501 | | * @param[in,out] asn ASN data context |
502 | | * @param[out] unused_bits the number of unused bits in the least |
503 | | * significant byte (LSB) of the BIT String |
504 | | * |
505 | | * @return NDR_ERR_SUCCESS if successful |
506 | | * The contents of unused_bits are undefined on an error |
507 | | */ |
508 | | static enum ndr_err_code start_bit_string(struct ndr_pull *ndr, |
509 | | struct asn1_data *asn, |
510 | | uint8_t *unused_bits) |
511 | 0 | { |
512 | 0 | if (!asn1_start_tag(asn, ASN1_BIT_STRING)) { |
513 | 0 | return ndr_pull_error( |
514 | 0 | ndr, |
515 | 0 | NDR_ERR_VALIDATE, |
516 | 0 | "Invalid ASN1 tag, expecting BIT STRING 0x03"); |
517 | 0 | } |
518 | | |
519 | | /* |
520 | | * The first byte of a BIT STRING contains the number of unused bits |
521 | | * in the final byte. |
522 | | */ |
523 | 0 | if (!asn1_read_uint8(asn, unused_bits)) { |
524 | 0 | return ndr_pull_error(ndr, |
525 | 0 | NDR_ERR_VALIDATE, |
526 | 0 | "Invalid ASN1 BIT STRING, unable to read " |
527 | 0 | "number of unused bits"); |
528 | 0 | } |
529 | 0 | if (*unused_bits > 8) { |
530 | 0 | return ndr_pull_error(ndr, |
531 | 0 | NDR_ERR_RANGE, |
532 | 0 | "Invalid ASN1 BIT STRING, " |
533 | 0 | "number of unused bits exceeds 9"); |
534 | 0 | } |
535 | 0 | return NDR_ERR_SUCCESS; |
536 | 0 | } |
537 | | |
538 | | /** |
539 | | * @brief Read a DER encoded INTEGER into a data_blob |
540 | | * |
541 | | * @param[in] mem_ctx memory context to allocate the data_blob data on |
542 | | * @param[in] ndr ndr pull context |
543 | | * @param[in,out] asn ASN data context |
544 | | * @param[in] name the name of the INTEGER for diagnostic messages |
545 | | * @param[out] blob the data blob to populate |
546 | | * using mem_ctx for allocation |
547 | | * |
548 | | * @return NDR_ERR_SUCCESS if successful |
549 | | * The contents of blob are undefined on an error |
550 | | */ |
551 | | static enum ndr_err_code read_integer(TALLOC_CTX *mem_ctx, |
552 | | struct ndr_pull *ndr, |
553 | | struct asn1_data *asn, |
554 | | const char *name, |
555 | | DATA_BLOB *blob) |
556 | 0 | { |
557 | 0 | static const int MAX_SIZE = 2 * 2048; /* 16384 bits */ |
558 | 0 | uint8_t msb = 0; |
559 | 0 | int tag_size = 0; |
560 | |
|
561 | 0 | if (!asn1_start_tag(asn, ASN1_INTEGER)) { |
562 | 0 | return ndr_pull_error( |
563 | 0 | ndr, |
564 | 0 | NDR_ERR_VALIDATE, |
565 | 0 | "Invalid ASN1 tag, expecting INTEGER 0x02"); |
566 | 0 | } |
567 | 0 | if (!asn1_peek_uint8(asn, &msb)) { |
568 | 0 | return ndr_pull_error( |
569 | 0 | ndr, |
570 | 0 | NDR_ERR_VALIDATE, |
571 | 0 | "Invalid ASN1 tag, unable to inspect first byte of %s", |
572 | 0 | name); |
573 | 0 | } |
574 | | /* skip a leading 0 byte if present */ |
575 | 0 | if (msb == 0) { |
576 | 0 | if (!asn1_read_uint8(asn, &msb)) { |
577 | 0 | return ndr_pull_error(ndr, |
578 | 0 | NDR_ERR_VALIDATE, |
579 | 0 | "Invalid ASN1 tag, unable to " |
580 | 0 | "read first byte of %s", |
581 | 0 | name); |
582 | 0 | } |
583 | 0 | } |
584 | | |
585 | 0 | tag_size = asn1_tag_remaining(asn); |
586 | 0 | if (tag_size > MAX_SIZE) { |
587 | 0 | return ndr_pull_error(ndr, |
588 | 0 | NDR_ERR_LENGTH, |
589 | 0 | "INTEGER %s size of %d " |
590 | 0 | "bytes is too large", |
591 | 0 | name, |
592 | 0 | tag_size); |
593 | 0 | } |
594 | 0 | if (tag_size <= 0) { |
595 | 0 | return ndr_pull_error(ndr, |
596 | 0 | NDR_ERR_LENGTH, |
597 | 0 | "INTEGER %s size of %d " |
598 | 0 | "bytes is too small", |
599 | 0 | name, |
600 | 0 | tag_size); |
601 | 0 | } |
602 | 0 | *blob = data_blob_talloc(mem_ctx, NULL, tag_size); |
603 | 0 | if (blob->data == NULL) { |
604 | 0 | return ndr_pull_error(ndr, |
605 | 0 | NDR_ERR_ALLOC, |
606 | 0 | "Unable to allocate DATA_BLOB for %s", |
607 | 0 | name); |
608 | 0 | } |
609 | | |
610 | 0 | if (!asn1_read(asn, blob->data, tag_size)) { |
611 | 0 | return ndr_pull_error(ndr, |
612 | 0 | NDR_ERR_VALIDATE, |
613 | 0 | "Unable to read %s", |
614 | 0 | name); |
615 | 0 | } |
616 | 0 | if (!asn1_end_tag(asn)) { |
617 | 0 | return ndr_pull_error(ndr, |
618 | 0 | NDR_ERR_UNREAD_BYTES, |
619 | 0 | "ASN1 INTEGER element %s", |
620 | 0 | name); |
621 | 0 | } |
622 | 0 | return NDR_ERR_SUCCESS; |
623 | 0 | } |
624 | | |
625 | | /** |
626 | | * @brief Convert a DER encoded X509 PublicKey into the Internal public key |
627 | | * representation |
628 | | * |
629 | | * publicKey BIT STRING -- containing an RSAPublicKey |
630 | | * RSAPublicKey ::= SEQUENCE { |
631 | | * modulus INTEGER, |
632 | | * publicExponent INTEGER |
633 | | * } |
634 | | * |
635 | | * @param[in,out] ndr ndr pull context |
636 | | * @param[in] ndr_flags |
637 | | * @param[out] kmi the KeyMaterialInternal structure to populate |
638 | | * |
639 | | * @return NDR_ERR_SUCCESS if successful |
640 | | * The contents of kmi are undefined on an error |
641 | | */ |
642 | | static enum ndr_err_code read_public_key(struct ndr_pull *ndr, |
643 | | struct asn1_data *asn, |
644 | | struct KeyMaterialInternal *kmi) |
645 | 0 | { |
646 | 0 | uint8_t unused_bits = 0; |
647 | | |
648 | | /* |
649 | | * publicKey BIT STRING |
650 | | * The RSAPublicKey is encoded in a BIT STRING |
651 | | */ |
652 | 0 | NDR_CHECK(start_bit_string(ndr, asn, &unused_bits)); |
653 | | |
654 | | /* RSAPublicKey ::= SEQUENCE { |
655 | | * modulus INTEGER, -- n |
656 | | * publicExponent INTEGER } -- e |
657 | | */ |
658 | 0 | if (!asn1_start_tag(asn, ASN1_SEQUENCE(0))) { |
659 | 0 | return ndr_pull_error( |
660 | 0 | ndr, |
661 | 0 | NDR_ERR_VALIDATE, |
662 | 0 | "Invalid ASN1 tag, expecting SEQUENCE 0x30"); |
663 | 0 | } |
664 | | |
665 | | /* modulus INTEGER */ |
666 | 0 | NDR_CHECK(read_integer( |
667 | 0 | ndr->current_mem_ctx, ndr, asn, "MODULUS", &kmi->modulus)); |
668 | 0 | kmi->bit_size = (kmi->modulus.length * 8) - unused_bits; |
669 | | |
670 | | /* public exponent INTEGER */ |
671 | 0 | NDR_CHECK(read_integer( |
672 | 0 | ndr->current_mem_ctx, ndr, asn, "EXPONENT", &kmi->exponent)); |
673 | | |
674 | 0 | if (!asn1_end_tag(asn)) { /* RSAPublicKey */ |
675 | 0 | return ndr_pull_error(ndr, |
676 | 0 | NDR_ERR_UNREAD_BYTES, |
677 | 0 | "ASN1 element RSAPublicKey"); |
678 | 0 | } |
679 | 0 | if (!asn1_end_tag(asn)) { /* PublicKey */ |
680 | 0 | return ndr_pull_error(ndr, |
681 | 0 | NDR_ERR_UNREAD_BYTES, |
682 | 0 | "ASN1 element PublicKey"); |
683 | 0 | } |
684 | 0 | return NDR_ERR_SUCCESS; |
685 | 0 | } |
686 | | |
687 | | /** |
688 | | * @brief Convert a DER encoded X509 public key into the Internal public key |
689 | | * representation |
690 | | * |
691 | | * @param[in,out] ndr ndr pull context |
692 | | * @param[in] ndr_flags |
693 | | * @param[out] kmi the KeyMaterialInternal structure to populate |
694 | | * @param[in] size number of bytes to process from the ndr context |
695 | | * |
696 | | * @return NDR_ERR_SUCCESS if successful |
697 | | * The contents of r are undefined on an error |
698 | | */ |
699 | | static enum ndr_err_code pull_DER_RSA_KEY(struct ndr_pull *ndr, |
700 | | ndr_flags_type ndr_flags, |
701 | | struct KeyMaterialInternal *kmi, |
702 | | uint32_t size) |
703 | 417 | { |
704 | 417 | enum ndr_err_code ret = NDR_ERR_SUCCESS; |
705 | 417 | struct asn1_data *asn = NULL; |
706 | | |
707 | 417 | TALLOC_CTX *tmp_ctx = talloc_new(ndr->current_mem_ctx); |
708 | 417 | if (tmp_ctx == NULL) { |
709 | 0 | return ndr_pull_error(ndr, |
710 | 0 | NDR_ERR_ALLOC, |
711 | 0 | "Unable to allocate temporary memory " |
712 | 0 | "context"); |
713 | 0 | } |
714 | 417 | asn = asn1_init(tmp_ctx, 5); |
715 | 417 | if (asn == NULL) { |
716 | 0 | TALLOC_FREE(tmp_ctx); |
717 | 0 | return ndr_pull_error(ndr, |
718 | 0 | NDR_ERR_ALLOC, |
719 | 0 | "Unable to initialize ASN1 context"); |
720 | 0 | } |
721 | 417 | asn1_load_nocopy(asn, ndr->data, size); |
722 | | |
723 | | /* |
724 | | * PublicKeyInfo ::= SEQUENCE { |
725 | | * algorithm AlgorithmIdentifier, |
726 | | * publicKey BIT STRING |
727 | | * } |
728 | | */ |
729 | 417 | if (!asn1_start_tag(asn, ASN1_SEQUENCE(0))) { |
730 | 175 | ret = ndr_pull_error( |
731 | 175 | ndr, |
732 | 175 | NDR_ERR_VALIDATE, |
733 | 175 | "Invalid ASN1 tag, expecting SEQUENCE 0x30"); |
734 | 175 | goto out; |
735 | 175 | } |
736 | | |
737 | 242 | ret = check_algorithm_identifier(ndr, asn); |
738 | 242 | if (ret != NDR_ERR_SUCCESS) { |
739 | 242 | goto out; |
740 | 242 | } |
741 | | |
742 | 0 | ret = read_public_key(ndr, asn, kmi); |
743 | 0 | if (ret != NDR_ERR_SUCCESS) { |
744 | 0 | goto out; |
745 | 0 | } |
746 | 0 | if (!asn1_end_tag(asn)) { /* PublicKeyInfo */ |
747 | 0 | ret = ndr_pull_error(ndr, |
748 | 0 | NDR_ERR_UNREAD_BYTES, |
749 | 0 | "ASN1 element PublicKeyInfo"); |
750 | 0 | goto out; |
751 | 0 | } |
752 | | |
753 | | /* Successfully parsed the key data */ |
754 | 0 | ret = NDR_ERR_SUCCESS; |
755 | 0 | ndr->offset += size; /* signal to NDR that the data has been consumed */ |
756 | |
|
757 | 417 | out: |
758 | 417 | asn1_free(asn); |
759 | 417 | TALLOC_FREE(tmp_ctx); |
760 | 417 | return ret; |
761 | 0 | } |
762 | | |
763 | | /** |
764 | | * @brief Convert a TPM20_RSA_KEY_BLOB into the Internal public key |
765 | | * representation |
766 | | * @param[in,out] ndr ndr pull context |
767 | | * @param[in] ndr_flags |
768 | | * @param[out] kmi the KeyMaterialInternal structure to populate |
769 | | * |
770 | | * @return NDR_ERR_SUCCESS if successful |
771 | | * The contents of kmi are undefined on an error |
772 | | */ |
773 | | static enum ndr_err_code pull_TPM20_RSAKEY_BLOB(struct ndr_pull *ndr, |
774 | | ndr_flags_type ndr_flags, |
775 | | struct KeyMaterialInternal *kmi) |
776 | 268 | { |
777 | 268 | enum ndr_err_code ret = NDR_ERR_SUCCESS; |
778 | 268 | struct TPM20_RSAKEY_BLOB *km = NULL; |
779 | | |
780 | 268 | TALLOC_CTX *tmp_ctx = talloc_new(ndr->current_mem_ctx); |
781 | 268 | if (tmp_ctx == NULL) { |
782 | 0 | return ndr_pull_error( |
783 | 0 | ndr, |
784 | 0 | NDR_ERR_ALLOC, |
785 | 0 | "Unable to allocate temporary memory context"); |
786 | 0 | } |
787 | | |
788 | 268 | km = talloc_zero(tmp_ctx, struct TPM20_RSAKEY_BLOB); |
789 | 268 | if (km == NULL) { |
790 | 0 | ret = ndr_pull_error(ndr, |
791 | 0 | NDR_ERR_ALLOC, |
792 | 0 | "Unable to allocate TPM20_RSAKEY_BLOB"); |
793 | 0 | goto out; |
794 | 0 | } |
795 | | |
796 | 268 | ret = ndr_pull_TPM20_RSAKEY_BLOB(ndr, ndr_flags, km); |
797 | 268 | if (ret != NDR_ERR_SUCCESS) { |
798 | 187 | goto out_km; |
799 | 187 | } |
800 | 81 | kmi->bit_size = km->public_key.rsa_detail.keyBits; |
801 | 81 | kmi->modulus = data_blob_talloc(ndr->current_mem_ctx, |
802 | 81 | km->public_key.rsa.buffer, |
803 | 81 | km->public_key.rsa.size); |
804 | 81 | if (kmi->modulus.data == NULL) { |
805 | 0 | ret = ndr_pull_error( |
806 | 0 | ndr, |
807 | 0 | NDR_ERR_ALLOC, |
808 | 0 | "Unable to allocate TPM20_RSAKEY_BLOB modulus"); |
809 | 0 | goto out_km; |
810 | 0 | } |
811 | | |
812 | 81 | kmi->exponent = data_blob_talloc(ndr->current_mem_ctx, |
813 | 81 | km->public_key.rsa_detail.exponent, |
814 | 81 | TPM_RSA_EXPONENT_SIZE); |
815 | 81 | if (kmi->exponent.data == NULL) { |
816 | 0 | ret = ndr_pull_error( |
817 | 0 | ndr, |
818 | 0 | NDR_ERR_ALLOC, |
819 | 0 | "Unable to allocate TPM20_RSAKEY_BLOB exponent"); |
820 | 0 | goto out_km; |
821 | 0 | } |
822 | 81 | ret = NDR_ERR_SUCCESS; |
823 | | |
824 | 268 | out_km: |
825 | 268 | TALLOC_FREE(km); |
826 | 268 | out: |
827 | 268 | TALLOC_FREE(tmp_ctx); |
828 | 268 | return ret; |
829 | 268 | } |
830 | | |
831 | | |
832 | | /** |
833 | | * @brief Convert a BCRYPT_RSAPUBLIC_BLOB public key into the Internal public key |
834 | | * representation |
835 | | * |
836 | | * @param[in,out] ndr ndr pull context |
837 | | * @param[in] ndr_flags |
838 | | * @param[out] kmi the KeyMaterialInternal structure to populate |
839 | | * |
840 | | * @return NDR_ERR_SUCCESS if successful |
841 | | * The contents of kmi are undefined on an error |
842 | | */ |
843 | | static enum ndr_err_code pull_BCRYPT_RSAPUBLIC_BLOB( |
844 | | struct ndr_pull *ndr, |
845 | | ndr_flags_type ndr_flags, |
846 | | struct KeyMaterialInternal *kmi) |
847 | 253 | { |
848 | 253 | enum ndr_err_code ret = NDR_ERR_SUCCESS; |
849 | 253 | struct BCRYPT_RSAPUBLIC_BLOB *km = NULL; |
850 | | |
851 | 253 | TALLOC_CTX *tmp_ctx = talloc_new(ndr->current_mem_ctx); |
852 | 253 | if (tmp_ctx == NULL) { |
853 | 0 | return ndr_pull_error( |
854 | 0 | ndr, |
855 | 0 | NDR_ERR_ALLOC, |
856 | 0 | "Unable to allocate temporary memory context"); |
857 | 0 | } |
858 | | |
859 | 253 | km = talloc_zero(tmp_ctx, struct BCRYPT_RSAPUBLIC_BLOB); |
860 | 253 | if (km == NULL) { |
861 | 0 | ret = ndr_pull_error(ndr, |
862 | 0 | NDR_ERR_ALLOC, |
863 | 0 | "Unable to allocate BCRYPT_RSAPUBLIC_BLOB"); |
864 | 0 | goto out; |
865 | 0 | } |
866 | | |
867 | 253 | ret = ndr_pull_BCRYPT_RSAPUBLIC_BLOB(ndr, ndr_flags, km); |
868 | 253 | if (ret != NDR_ERR_SUCCESS) { |
869 | 243 | goto out_km; |
870 | 243 | } |
871 | | |
872 | 10 | kmi->bit_size = km->bit_length; |
873 | | |
874 | 10 | kmi->modulus = data_blob_talloc(ndr->current_mem_ctx, |
875 | 10 | km->modulus, |
876 | 10 | km->modulus_len); |
877 | 10 | if (kmi->modulus.data == NULL) { |
878 | 0 | ret = ndr_pull_error( |
879 | 0 | ndr, |
880 | 0 | NDR_ERR_ALLOC, |
881 | 0 | "Unable to allocate BCRYPT_RSAPUBLIC_BLOB modulus"); |
882 | 0 | goto out_km; |
883 | 0 | } |
884 | | |
885 | 10 | kmi->exponent = data_blob_talloc(ndr->current_mem_ctx, |
886 | 10 | km->public_exponent, |
887 | 10 | km->public_exponent_len); |
888 | 10 | if (kmi->exponent.data == NULL) { |
889 | 0 | ret = ndr_pull_error( |
890 | 0 | ndr, |
891 | 0 | NDR_ERR_ALLOC, |
892 | 0 | "Unable to allocate BCRYPT_RSAPUBLIC_BLOB exponent"); |
893 | 0 | goto out_km; |
894 | 0 | } |
895 | | |
896 | 10 | ret = NDR_ERR_SUCCESS; |
897 | | |
898 | 253 | out_km: |
899 | 253 | TALLOC_FREE(km); |
900 | 253 | out: |
901 | 253 | TALLOC_FREE(tmp_ctx); |
902 | 253 | return ret; |
903 | 253 | } |
904 | | |
905 | | |
906 | | /** |
907 | | * @brief Convert a KeyMaterial blob into the Internal public key |
908 | | * representation KeyMaterialInternal |
909 | | * |
910 | | * @param[in,out] ndr ndr pull context |
911 | | * @param[in] ndr_flags |
912 | | * @param[out] kmi the KeyMaterialInternal structure to populate |
913 | | * |
914 | | * @return NDR_ERR_SUCCESS if successful |
915 | | * The contents of kmi are undefined on an error |
916 | | */ |
917 | | enum ndr_err_code ndr_pull_KeyMaterialInternal(struct ndr_pull *ndr, |
918 | | ndr_flags_type ndr_flags, |
919 | | struct KeyMaterialInternal *kmi) |
920 | 985 | { |
921 | 985 | static const uint8_t BCRYPT_HEADER[] = {'R', 'S', 'A', '1'}; |
922 | 985 | static const uint8_t TPM20_HEADER[] = {'P', 'C', 'P', 'M'}; |
923 | 985 | static const uint32_t MIN_KEY_MATERIAL_SIZE = 5; |
924 | 985 | static const uint32_t MAX_KEY_MATERIAL_SIZE = 64 * 1024; |
925 | | |
926 | 985 | uint32_t size = 0; |
927 | | |
928 | 985 | if (ndr->offset > ndr->data_size) { |
929 | 0 | return ndr_pull_error(ndr, |
930 | 0 | NDR_ERR_LENGTH, |
931 | 0 | "ndr->offset (%" PRIu32 |
932 | 0 | ") is greater than " |
933 | 0 | "ndr->data_size (%" PRIu32 ")", |
934 | 0 | ndr->offset, |
935 | 0 | ndr->data_size); |
936 | 0 | } |
937 | 985 | size = ndr->data_size - ndr->offset; |
938 | 985 | if (size < MIN_KEY_MATERIAL_SIZE) { |
939 | 5 | return ndr_pull_error(ndr, |
940 | 5 | NDR_ERR_LENGTH, |
941 | 5 | "KeyMaterial size of %" PRIu32 |
942 | 5 | " bytes is too small", |
943 | 5 | size); |
944 | 5 | } |
945 | 980 | if (size > MAX_KEY_MATERIAL_SIZE) { |
946 | 10 | return ndr_pull_error(ndr, |
947 | 10 | NDR_ERR_LENGTH, |
948 | 10 | "KeyMaterial size of %" PRIu32 |
949 | 10 | " bytes is too large", |
950 | 10 | size); |
951 | 10 | } |
952 | | |
953 | 970 | if (memcmp(BCRYPT_HEADER, ndr->data, sizeof(BCRYPT_HEADER)) == 0) { |
954 | 253 | return pull_BCRYPT_RSAPUBLIC_BLOB(ndr, ndr_flags, kmi); |
955 | 717 | } else if (memcmp(TPM20_HEADER, ndr->data, sizeof(TPM20_HEADER)) == 0) { |
956 | 268 | return pull_TPM20_RSAKEY_BLOB(ndr, ndr_flags, kmi); |
957 | 449 | } else if (*ndr->data == ASN1_SEQUENCE(0)) { |
958 | | /* |
959 | | * If the first byte is an ASN1 sequence marker assume that |
960 | | * this is an x509 public key |
961 | | */ |
962 | 417 | return pull_DER_RSA_KEY(ndr, ndr_flags, kmi, size); |
963 | 417 | } else { |
964 | 32 | return ndr_pull_error( |
965 | 32 | ndr, |
966 | 32 | NDR_ERR_VALIDATE, |
967 | 32 | "Unknown KeyMaterial type, could not be decoded"); |
968 | 32 | } |
969 | 970 | } |
970 | | |
971 | | /** |
972 | | * @brief Push a representation of a KeyMaterialInternal onto the |
973 | | * ndr_push context. |
974 | | * |
975 | | * @param[in,out] ndr ndr push context |
976 | | * @param[in] ndr_flags |
977 | | * @param[out] kmi the KeyMaterialInternal structure to populate |
978 | | * |
979 | | * @note This is not currently implemented and will always return |
980 | | * NDR_ERR_VALIDATE |
981 | | * |
982 | | * @return NDR_ERR_VALIDATE |
983 | | * |
984 | | */ |
985 | | enum ndr_err_code ndr_push_KeyMaterialInternal( |
986 | | struct ndr_push *ndr, |
987 | | ndr_flags_type ndr_flags, |
988 | | const struct KeyMaterialInternal *kmi) |
989 | 91 | { |
990 | | return ndr_push_error( |
991 | 91 | ndr, |
992 | 91 | NDR_ERR_VALIDATE, |
993 | 91 | "NDR Push for KeyMaterialInternal not currently supported"); |
994 | 91 | } |