xref: /netbsd-src/crypto/external/cpl/trousers/dist/src/tspi/tspi_ps.c (revision 7788a0781fe6ff2cce37368b4578a7ade0850cb1)
1 
2 /*
3  * Licensed Materials - Property of IBM
4  *
5  * trousers - An open source TCG Software Stack
6  *
7  * (C) Copyright International Business Machines Corp. 2004-2006
8  *
9  */
10 
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include "trousers/tss.h"
17 #include "trousers/trousers.h"
18 #include "trousers_types.h"
19 #include "trousers_types.h"
20 #include "spi_utils.h"
21 #include "capabilities.h"
22 #include "tsplog.h"
23 #include "tcs_tsp.h"
24 #include "tspps.h"
25 #include "hosttable.h"
26 #include "tcsd_wrap.h"
27 #include "tcsd.h"
28 #include "obj.h"
29 
30 TSS_UUID owner_evict_uuid = {0, 0, 0, 0, 0, {0, 0, 0, 0, 1, 0}};
31 
32 TSS_RESULT
33 Tspi_Context_LoadKeyByUUID(TSS_HCONTEXT tspContext,		/* in */
34 			   TSS_FLAG persistentStorageType,	/* in */
35 			   TSS_UUID uuidData,			/* in */
36 			   TSS_HKEY * phKey)			/* out */
37 {
38 	TSS_RESULT result;
39 	TSS_UUID parentUUID;
40 	UINT32 keyBlobSize, parentPSType;
41 	BYTE *keyBlob = NULL;
42 	TCS_KEY_HANDLE tcsKeyHandle;
43 	TSS_HKEY parentTspHandle;
44 	TCS_LOADKEY_INFO info;
45 	UINT32		ulPubKeyLength;
46 	BYTE		*rgbPubKey;
47 
48 	if (phKey == NULL)
49 		return TSPERR(TSS_E_BAD_PARAMETER);
50 
51 	if ((!obj_is_context(tspContext)))
52 		return TSPERR(TSS_E_INVALID_HANDLE);
53 
54 	/* This key is in the System Persistant storage */
55 	if (persistentStorageType == TSS_PS_TYPE_SYSTEM) {
56 #if 1
57 		memset(&info, 0, sizeof(TCS_LOADKEY_INFO));
58 
59 		result = RPC_LoadKeyByUUID(tspContext, uuidData, &info, &tcsKeyHandle);
60 
61 		if (TSS_ERROR_CODE(result) == TCS_E_KM_LOADFAILED) {
62 			TSS_HKEY keyHandle;
63 			TSS_HPOLICY hPolicy;
64 
65 			/* load failed, due to some key in the chain needing auth
66 			 * which doesn't yet exist at the TCS level. However, the
67 			 * auth may already be set in policies at the TSP level.
68 			 * To find out, get the key handle of the key requiring
69 			 * auth. First, look at the list of keys in memory. */
70 			if ((obj_rsakey_get_by_uuid(&info.parentKeyUUID, &keyHandle))) {
71 				/* If that failed, look on disk, in User PS. */
72 				if (ps_get_key_by_uuid(tspContext, &info.parentKeyUUID,
73 						       &keyHandle))
74 					return result;
75 			}
76 
77 			if (obj_rsakey_get_policy(keyHandle, TSS_POLICY_USAGE,
78 						  &hPolicy, NULL))
79 				return result;
80 
81 			if (secret_PerformAuth_OIAP(keyHandle, TPM_ORD_LoadKey, hPolicy, FALSE,
82 						    &info.paramDigest, &info.authData))
83 				return result;
84 
85 			if ((result = RPC_LoadKeyByUUID(tspContext, uuidData, &info,
86 							&tcsKeyHandle)))
87 				return result;
88 		} else if (result)
89 			return result;
90 
91 		/*check if provided UUID has an owner evict key UUID prefix */
92 		if (!memcmp(&uuidData, &owner_evict_uuid, sizeof(TSS_UUID)-1)) {
93 			if ((result = obj_rsakey_add(tspContext, TSS_RSAKEY_FLAG_OWNEREVICT,
94 						      phKey)))
95 				return result;
96 			if ((result = obj_rsakey_set_tcs_handle(*phKey, tcsKeyHandle)))
97 				return result;
98 
99 			//The cached public key portion of the owner evict key is used
100 			//further by TPM_KEY_CONTROLOWNER command for sanity check
101 			if ((result = Tspi_Key_GetPubKey(*phKey, &ulPubKeyLength, &rgbPubKey)))
102 				return result;
103 
104 			result = obj_rsakey_set_pubkey(*phKey, FALSE, rgbPubKey);
105 
106 			free(rgbPubKey);
107 			if (result != TSS_SUCCESS)
108 				return result;
109 		} else {
110 			if ((result = RPC_GetRegisteredKeyBlob(tspContext, uuidData, &keyBlobSize,
111 							       &keyBlob)))
112 				return result;
113 
114 			if ((result = obj_rsakey_add_by_key(tspContext, &uuidData, keyBlob,
115 							    TSS_OBJ_FLAG_SYSTEM_PS, phKey))) {
116 				free (keyBlob);
117 				return result;
118 			}
119 
120 			result = obj_rsakey_set_tcs_handle(*phKey, tcsKeyHandle);
121 
122 			free (keyBlob);
123 		}
124 #else
125 		if ((result = load_from_system_ps(tspContext, &uuidData, phKey)))
126 			return result;
127 #endif
128 	} else if (persistentStorageType == TSS_PS_TYPE_USER) {
129 		if ((result = ps_get_parent_uuid_by_uuid(&uuidData, &parentUUID)))
130 			return result;
131 
132 		/* If the parent is not in memory, recursively call ourselves on it */
133 		if (obj_rsakey_get_by_uuid(&parentUUID, &parentTspHandle) != TSS_SUCCESS) {
134 			if ((result = ps_get_parent_ps_type_by_uuid(&uuidData, &parentPSType)))
135 				return result;
136 
137 			if ((result = Tspi_Context_LoadKeyByUUID(tspContext, parentPSType,
138 								 parentUUID, &parentTspHandle)))
139 				return result;
140 		}
141 
142 		if ((result = ps_get_key_by_uuid(tspContext, &uuidData, phKey)))
143 			return result;
144 
145 		/* The parent is loaded and we have the parent key handle, so call the TCS to
146 		 * actually load the child. */
147 		return Tspi_Key_LoadKey(*phKey, parentTspHandle);
148 	} else {
149 		return TSPERR(TSS_E_BAD_PARAMETER);
150 	}
151 
152 	return TSS_SUCCESS;
153 }
154 
155 TSS_RESULT
156 Tspi_Context_RegisterKey(TSS_HCONTEXT tspContext,		/* in */
157 			 TSS_HKEY hKey,				/* in */
158 			 TSS_FLAG persistentStorageType,	/* in */
159 			 TSS_UUID uuidKey,			/* in */
160 			 TSS_FLAG persistentStorageTypeParent,	/* in */
161 			 TSS_UUID uuidParentKey)		/* in */
162 {
163 	BYTE *keyBlob;
164 	UINT32 keyBlobSize;
165 	TSS_RESULT result;
166 	TSS_BOOL answer;
167 
168 	if (!obj_is_context(tspContext) || !obj_is_rsakey(hKey))
169 		return TSPERR(TSS_E_INVALID_HANDLE);
170 
171 	if (persistentStorageType == TSS_PS_TYPE_SYSTEM) {
172 		if (persistentStorageTypeParent == TSS_PS_TYPE_USER) {
173 			return TSPERR(TSS_E_NOTIMPL);
174 		} else if (persistentStorageTypeParent == TSS_PS_TYPE_SYSTEM) {
175 			if ((result = obj_rsakey_get_blob(hKey, &keyBlobSize,
176 							  &keyBlob)))
177 				return result;
178 
179 			if ((result = RPC_RegisterKey(tspContext, uuidParentKey, uuidKey,
180 						      keyBlobSize, keyBlob,
181 						      strlen(PACKAGE_STRING) + 1,
182 						      (BYTE *)PACKAGE_STRING)))
183 				return result;
184 		} else {
185 			return TSPERR(TSS_E_BAD_PARAMETER);
186 		}
187 	} else if (persistentStorageType == TSS_PS_TYPE_USER) {
188 		if ((result = ps_is_key_registered(&uuidKey, &answer)))
189 			return result;
190 
191 		if (answer == TRUE)
192 			return TSPERR(TSS_E_KEY_ALREADY_REGISTERED);
193 
194 		if ((result = obj_rsakey_get_blob (hKey, &keyBlobSize, &keyBlob)))
195 			return result;
196 
197 		if ((result = ps_write_key(&uuidKey, &uuidParentKey,
198 					   persistentStorageTypeParent,
199 					   keyBlobSize, keyBlob)))
200 			return result;
201 	} else {
202 		return TSPERR(TSS_E_BAD_PARAMETER);
203 	}
204 
205 	if ((result = obj_rsakey_set_uuid(hKey, persistentStorageType, &uuidKey)))
206 		return result;
207 
208 	return TSS_SUCCESS;
209 }
210 
211 TSS_RESULT
212 Tspi_Context_UnregisterKey(TSS_HCONTEXT tspContext,		/* in */
213 			   TSS_FLAG persistentStorageType,	/* in */
214 			   TSS_UUID uuidKey,			/* in */
215 			   TSS_HKEY *phKey)			/* out */
216 {
217 	BYTE *keyBlob = NULL;
218 	UINT32 keyBlobSize;
219 	TSS_RESULT result;
220 
221 	if (phKey == NULL)
222 		return TSPERR(TSS_E_BAD_PARAMETER);
223 
224 	if ((!obj_is_context(tspContext)))
225 		return TSPERR(TSS_E_INVALID_HANDLE);
226 
227 	if (persistentStorageType == TSS_PS_TYPE_SYSTEM) {
228 		/* get the key first, so it doesn't disappear when we
229 		 * unregister it */
230 		if ((result = RPC_GetRegisteredKeyBlob(tspContext, uuidKey, &keyBlobSize,
231 						       &keyBlob)))
232 			return result;
233 
234 		if ((obj_rsakey_add_by_key(tspContext, &uuidKey, keyBlob, TSS_OBJ_FLAG_SYSTEM_PS,
235 					   phKey))) {
236 			free(keyBlob);
237 			return result;
238 		}
239 
240 		free(keyBlob);
241 
242 		/* now unregister it */
243 		if ((result = RPC_UnregisterKey(tspContext, uuidKey)))
244 			return result;
245 	} else if (persistentStorageType == TSS_PS_TYPE_USER) {
246 		/* get the key first, so it doesn't disappear when we
247 		 * unregister it */
248 		if ((result = ps_get_key_by_uuid(tspContext, &uuidKey, phKey)))
249 			return result;
250 
251 		/* now unregister it */
252 		if ((result = ps_remove_key(&uuidKey)))
253 			return result;
254 	} else {
255 		return TSPERR(TSS_E_BAD_PARAMETER);
256 	}
257 
258 	return TSS_SUCCESS;
259 }
260 
261 TSS_RESULT
262 Tspi_Context_GetKeyByUUID(TSS_HCONTEXT tspContext,		/* in */
263 			  TSS_FLAG persistentStorageType,	/* in */
264 			  TSS_UUID uuidData,			/* in */
265 			  TSS_HKEY * phKey)			/* out */
266 {
267 	TCPA_RESULT result;
268 	UINT32 keyBlobSize = 0;
269 	BYTE *keyBlob = NULL;
270 
271 	if (phKey == NULL)
272 		return TSPERR(TSS_E_BAD_PARAMETER);
273 
274 	if ((!obj_is_context(tspContext)))
275 		return TSPERR(TSS_E_INVALID_HANDLE);
276 
277 	if (persistentStorageType == TSS_PS_TYPE_SYSTEM) {
278 		if ((result = RPC_GetRegisteredKeyBlob(tspContext, uuidData, &keyBlobSize,
279 						       &keyBlob)))
280 			return result;
281 
282 		if ((obj_rsakey_add_by_key(tspContext, &uuidData, keyBlob, TSS_OBJ_FLAG_SYSTEM_PS,
283 					   phKey))) {
284 			free(keyBlob);
285 			return result;
286 		}
287 
288 		free(keyBlob);
289 	} else if (persistentStorageType == TSS_PS_TYPE_USER) {
290 		if (!obj_is_context(tspContext))
291 			return TSPERR(TSS_E_INVALID_HANDLE);
292 
293 		if ((result = ps_get_key_by_uuid(tspContext, &uuidData, phKey)))
294 			return result;
295 	} else
296 		return TSPERR(TSS_E_BAD_PARAMETER);
297 
298 	return TSS_SUCCESS;
299 }
300 
301 TSS_RESULT
302 Tspi_Context_GetKeyByPublicInfo(TSS_HCONTEXT tspContext,	/* in */
303 				TSS_FLAG persistentStorageType,	/* in */
304 				TSS_ALGORITHM_ID algID,		/* in */
305 				UINT32 ulPublicInfoLength,	/* in */
306 				BYTE * rgbPublicInfo,		/* in */
307 				TSS_HKEY * phKey)		/* out */
308 {
309 	TCPA_ALGORITHM_ID tcsAlgID;
310 	UINT32 keyBlobSize;
311 	BYTE *keyBlob;
312 	TSS_RESULT result;
313 	TSS_HKEY keyOutHandle;
314 	UINT32 flag = 0;
315 	TSS_KEY keyContainer;
316 	UINT64 offset;
317 
318 	if (phKey == NULL)
319 		return TSPERR(TSS_E_BAD_PARAMETER);
320 
321 	if (!obj_is_context(tspContext))
322 		return TSPERR(TSS_E_INVALID_HANDLE);
323 
324 	switch (algID) {
325 		case TSS_ALG_RSA:
326 			tcsAlgID = TCPA_ALG_RSA;
327 			break;
328 		default:
329 			LogError("Algorithm ID was not type RSA.");
330 			return TSPERR(TSS_E_BAD_PARAMETER);
331 	}
332 
333 	if (persistentStorageType == TSS_PS_TYPE_SYSTEM) {
334 		if ((result = RPC_GetRegisteredKeyByPublicInfo(tspContext, tcsAlgID,
335 							       ulPublicInfoLength, rgbPublicInfo,
336 							       &keyBlobSize, &keyBlob)))
337 			return result;
338 
339 	} else if (persistentStorageType == TSS_PS_TYPE_USER) {
340 		return ps_get_key_by_pub(tspContext, ulPublicInfoLength, rgbPublicInfo,
341 					 phKey);
342 	} else
343 		return TSPERR(TSS_E_BAD_PARAMETER);
344 
345 	/* need to setup the init flags of the create object based on
346 	 * the size of the blob's pubkey */
347 	offset = 0;
348 	if ((result = UnloadBlob_TSS_KEY(&offset, keyBlob, &keyContainer))) {
349 		free(keyBlob);
350 		return result;
351 	}
352 
353 	/* begin setting up the key object */
354 	switch (keyContainer.pubKey.keyLength) {
355 		case 16384/8:
356 			flag |= TSS_KEY_SIZE_16384;
357 			break;
358 		case 8192/8:
359 			flag |= TSS_KEY_SIZE_8192;
360 			break;
361 		case 4096/8:
362 			flag |= TSS_KEY_SIZE_4096;
363 			break;
364 		case 2048/8:
365 			flag |= TSS_KEY_SIZE_2048;
366 			break;
367 		case 1024/8:
368 			flag |= TSS_KEY_SIZE_1024;
369 			break;
370 		case 512/8:
371 			flag |= TSS_KEY_SIZE_512;
372 			break;
373 		default:
374 			LogError("Key was not a known keylength.");
375 			free(keyBlob);
376 			free_key_refs(&keyContainer);
377 			return TSPERR(TSS_E_INTERNAL_ERROR);
378 	}
379 
380 	if (keyContainer.keyUsage == TPM_KEY_SIGNING)
381 		flag |= TSS_KEY_TYPE_SIGNING;
382 	else if (keyContainer.keyUsage == TPM_KEY_STORAGE)
383 		flag |= TSS_KEY_TYPE_STORAGE;
384 	else if (keyContainer.keyUsage == TPM_KEY_IDENTITY)
385 		flag |= TSS_KEY_TYPE_IDENTITY;
386 	else if (keyContainer.keyUsage == TPM_KEY_AUTHCHANGE)
387 		flag |= TSS_KEY_TYPE_AUTHCHANGE;
388 	else if (keyContainer.keyUsage == TPM_KEY_BIND)
389 		flag |= TSS_KEY_TYPE_BIND;
390 	else if (keyContainer.keyUsage == TPM_KEY_LEGACY)
391 		flag |= TSS_KEY_TYPE_LEGACY;
392 
393 	if (keyContainer.authDataUsage == TPM_AUTH_NEVER)
394 		flag |= TSS_KEY_NO_AUTHORIZATION;
395 	else
396 		flag |= TSS_KEY_AUTHORIZATION;
397 
398 	if (keyContainer.keyFlags & TPM_MIGRATABLE)
399 		flag |= TSS_KEY_MIGRATABLE;
400 	else
401 		flag |= TSS_KEY_NOT_MIGRATABLE;
402 
403 	if (keyContainer.keyFlags & TPM_VOLATILE)
404 		flag |= TSS_KEY_VOLATILE;
405 	else
406 		flag |= TSS_KEY_NON_VOLATILE;
407 
408 #ifdef TSS_BUILD_CMK
409 	if (keyContainer.keyFlags & TPM_MIGRATEAUTHORITY)
410 		flag |= TSS_KEY_CERTIFIED_MIGRATABLE;
411 	else
412 		flag |= TSS_KEY_NOT_CERTIFIED_MIGRATABLE;
413 #endif
414 
415 	/* Create a new Key Object */
416 	if ((result = obj_rsakey_add(tspContext, flag, &keyOutHandle))) {
417 		free(keyBlob);
418 		free_key_refs(&keyContainer);
419 		return result;
420 	}
421 	/* Stick the info into this net KeyObject */
422 	if ((result = obj_rsakey_set_tcpakey(keyOutHandle, keyBlobSize, keyBlob))) {
423 		free(keyBlob);
424 		free_key_refs(&keyContainer);
425 		return result;
426 	}
427 
428 	free(keyBlob);
429 	free_key_refs(&keyContainer);
430 	*phKey = keyOutHandle;
431 
432 	return TSS_SUCCESS;
433 }
434 
435 TSS_RESULT
436 Tspi_Context_GetRegisteredKeysByUUID(TSS_HCONTEXT tspContext,		/* in */
437 				     TSS_FLAG persistentStorageType,	/* in */
438 				     TSS_UUID * pUuidData,		/* in */
439 				     UINT32 * pulKeyHierarchySize,	/* out */
440 				     TSS_KM_KEYINFO ** ppKeyHierarchy)	/* out */
441 {
442 	TSS_RESULT result;
443 	TSS_KM_KEYINFO *tcsHier, *tspHier;
444 	UINT32 tcsHierSize, tspHierSize;
445 	TSS_UUID tcs_uuid;
446 
447 	if (pulKeyHierarchySize == NULL || ppKeyHierarchy == NULL)
448 		return TSPERR(TSS_E_BAD_PARAMETER);
449 
450 	if (!obj_is_context(tspContext))
451 		return TSPERR(TSS_E_INVALID_HANDLE);
452 
453 	if (pUuidData) {
454 		if (persistentStorageType == TSS_PS_TYPE_SYSTEM) {
455 			if ((result = RPC_EnumRegisteredKeys(tspContext, pUuidData,
456 							     pulKeyHierarchySize,
457 							     ppKeyHierarchy)))
458 				return result;
459 		} else if (persistentStorageType == TSS_PS_TYPE_USER) {
460 			if ((result = ps_get_registered_keys(pUuidData, &tcs_uuid,
461 							     &tspHierSize, &tspHier)))
462 				return result;
463 
464 			if ((result = RPC_EnumRegisteredKeys(tspContext, &tcs_uuid, &tcsHierSize,
465 							     &tcsHier))) {
466 				free(tspHier);
467 				return result;
468 			}
469 
470 			result = merge_key_hierarchies(tspContext, tspHierSize, tspHier,
471 						       tcsHierSize, tcsHier, pulKeyHierarchySize,
472 						       ppKeyHierarchy);
473 			free(tcsHier);
474 			free(tspHier);
475 		} else
476 			return TSPERR(TSS_E_BAD_PARAMETER);
477 	} else {
478 		if ((result = RPC_EnumRegisteredKeys(tspContext, pUuidData, &tcsHierSize,
479 						     &tcsHier)))
480 			return result;
481 
482 		if ((result = ps_get_registered_keys(pUuidData, NULL, &tspHierSize, &tspHier))) {
483 			free(tcsHier);
484 			return result;
485 		}
486 
487 		result = merge_key_hierarchies(tspContext, tspHierSize, tspHier, tcsHierSize,
488 					       tcsHier, pulKeyHierarchySize, ppKeyHierarchy);
489 		free(tcsHier);
490 		free(tspHier);
491 	}
492 
493 	if ((result = __tspi_add_mem_entry(tspContext, *ppKeyHierarchy))) {
494 		free(*ppKeyHierarchy);
495 		*ppKeyHierarchy = NULL;
496 		*pulKeyHierarchySize = 0;
497 	}
498 
499 	return result;
500 }
501 
502 TSS_RESULT
503 Tspi_Context_GetRegisteredKeysByUUID2(TSS_HCONTEXT tspContext,		/* in */
504 				     TSS_FLAG persistentStorageType,	/* in */
505 				     TSS_UUID * pUuidData,		/* in */
506 				     UINT32 * pulKeyHierarchySize,	/* out */
507 				     TSS_KM_KEYINFO2 ** ppKeyHierarchy)	/* out */
508 {
509 	TSS_RESULT result;
510 	TSS_KM_KEYINFO2 *tcsHier, *tspHier;
511 	UINT32 tcsHierSize, tspHierSize;
512 	TSS_UUID tcs_uuid;
513 
514 	/* If out parameters are NULL, return error */
515 	if (pulKeyHierarchySize == NULL || ppKeyHierarchy == NULL)
516 			return TSPERR(TSS_E_BAD_PARAMETER);
517 
518 	if (!obj_is_context(tspContext))
519 			return TSPERR(TSS_E_INVALID_HANDLE);
520 
521 	if (pUuidData) {
522 		/* TSS 1.2 Spec: If a certain key UUID is provided, the returned array of
523 		 * TSS_KM_KEYINFO2 structures only contains data reflecting the path of the key
524 		 * hierarchy regarding that key. The first array entry is the key addressed by the
525 		 * given UUID followed by its parent key up to and including the root key. */
526 		if (persistentStorageType == TSS_PS_TYPE_SYSTEM) {
527 			if ((result = RPC_EnumRegisteredKeys2(tspContext, pUuidData,
528 							      pulKeyHierarchySize, ppKeyHierarchy)))
529 				return result;
530 		} else if (persistentStorageType == TSS_PS_TYPE_USER) {
531 			if ((result = ps_get_registered_keys2(pUuidData, &tcs_uuid, &tspHierSize,
532 							      &tspHier)))
533 				return result;
534 			/* The tcs_uuid returned by ps_get_registered_key2 will always be a parent
535 			 * of some key into the system ps of a user key into the user ps. This key
536 			 * needs to be searched for in the system ps to be merged */
537 			if ((result = RPC_EnumRegisteredKeys2(tspContext, &tcs_uuid, &tcsHierSize,
538 							      &tcsHier))) {
539 				free(tspHier);
540 				return result;
541 			}
542 
543 			result = merge_key_hierarchies2(tspContext, tspHierSize, tspHier,
544 							tcsHierSize, tcsHier, pulKeyHierarchySize,
545 							ppKeyHierarchy);
546 			free(tcsHier);
547 			free(tspHier);
548 		} else
549 			return TSPERR(TSS_E_BAD_PARAMETER);
550 	} else {
551 		/* If this field is set to NULL, the returned array of TSS_KM_KEYINFO2 structures
552 		 * contains data reflecting the entire key hierarchy starting with root key. The
553 		 * array will include keys from both the user and the system TSS key store. The
554 		 * persistentStorageType field will be ignored. */
555 		if ((result = RPC_EnumRegisteredKeys2(tspContext, pUuidData, &tcsHierSize,
556 						      &tcsHier)))
557 			return result;
558 
559 		if ((result = ps_get_registered_keys2(pUuidData, NULL, &tspHierSize, &tspHier))) {
560 			free(tcsHier);
561 			return result;
562 		}
563 
564 		result = merge_key_hierarchies2(tspContext, tspHierSize, tspHier, tcsHierSize,
565 						tcsHier, pulKeyHierarchySize, ppKeyHierarchy);
566 		free(tcsHier);
567 		free(tspHier);
568 	}
569 
570 	if ((result = __tspi_add_mem_entry(tspContext, *ppKeyHierarchy))) {
571 		free(*ppKeyHierarchy);
572 		*ppKeyHierarchy = NULL;
573 		*pulKeyHierarchySize = 0;
574 	}
575 
576 	return result;
577 }
578