/ keychain / securityd / SecKeybagSupport.c
SecKeybagSupport.c
  1  /*
  2   * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  /*
 25   *  SecKeybagSupport.c - CoreFoundation-based constants and functions for
 26      access to Security items (certificates, keys, identities, and
 27      passwords.)
 28   */
 29  
 30  #include "keychain/securityd/SecKeybagSupport.h"
 31  #include <TargetConditionals.h>
 32  
 33  #include "keychain/securityd/SecItemServer.h"
 34  
 35  #if USE_KEYSTORE
 36  #include <IOKit/IOKitLib.h>
 37  #include <libaks_acl_cf_keys.h>
 38  #include <utilities/der_plist.h>
 39  #include <corecrypto/ccder.h>
 40  #include <ACMLib.h>
 41  #else /* !USE_KEYSTORE */
 42  #include <utilities/SecInternalReleasePriv.h>
 43  #endif /* USE_KEYSTORE */
 44  
 45  #include <CommonCrypto/CommonCryptor.h>
 46  #include <CommonCrypto/CommonCryptorSPI.h>
 47  
 48  #include "OSX/utilities/SecAKSWrappers.h"
 49  
 50  /* g_keychain_handle is the keybag handle used for encrypting item in the keychain.
 51   For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */
 52  #if USE_KEYSTORE
 53  #if TARGET_OS_OSX
 54  keybag_handle_t g_keychain_keybag = session_keybag_handle;
 55  #else
 56  keybag_handle_t g_keychain_keybag = device_keybag_handle;
 57  #endif
 58  #else /* !USE_KEYSTORE */
 59  keybag_handle_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
 60  #endif /* USE_KEYSTORE */
 61  
 62  const CFStringRef kSecKSKeyData1 = CFSTR("d1");
 63  const CFStringRef kSecKSKeyData2 = CFSTR("d2");
 64  
 65  void SecItemServerSetKeychainKeybag(int32_t keybag)
 66  {
 67      g_keychain_keybag=keybag;
 68  }
 69  
 70  void SecItemServerResetKeychainKeybag(void)
 71  {
 72  #if USE_KEYSTORE
 73  #if TARGET_OS_OSX
 74      g_keychain_keybag = session_keybag_handle;
 75  #else
 76      g_keychain_keybag = device_keybag_handle;
 77  #endif
 78  #else /* !USE_KEYSTORE */
 79      g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
 80  #endif /* USE_KEYSTORE */
 81  }
 82  
 83  /* Wrap takes a 128 - 256 bit key as input and returns output of
 84   inputsize + 64 bits.
 85   In bytes this means that a
 86   16 byte (128 bit) key returns a 24 byte wrapped key
 87   24 byte (192 bit) key returns a 32 byte wrapped key
 88   32 byte (256 bit) key returns a 40 byte wrapped key  */
 89  bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag,
 90                keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, CFMutableDataRef dest, CFErrorRef *error) {
 91  #if USE_KEYSTORE
 92      kern_return_t kernResult = kAKSReturnBadArgument;
 93      
 94      int dest_len = (int)CFDataGetLength(dest);
 95      if (CFEqual(operation, kAKSKeyOpEncrypt)) {
 96          kernResult = aks_wrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len, actual_class);
 97      } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) {
 98          kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len);
 99      }
100      
101      if (kernResult != KERN_SUCCESS) {
102          if ((kernResult == kAKSReturnNoPermission) || (kernResult == kAKSReturnNotPrivileged)) {
103              const char *substatus = "";
104              if (keyclass == key_class_ck || keyclass == key_class_cku)
105                  substatus = " (hibernation?)";
106              /* Access to item attempted while keychain is locked. */
107              return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked%s."),
108                              kernResult, operation, keyclass, keybag, substatus);
109          } else if (kernResult == kAKSReturnNotFound) {
110              return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), kernResult, operation, keyclass, keybag);
111          } else if (kernResult == kAKSReturnError || kernResult == kAKSReturnDecodeError) {
112              /* Item can't be decrypted on this device, ever, so drop the item. */
113              return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."),
114                              kernResult, operation, keyclass, keybag);
115          } else {
116              return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32")"),
117                              kernResult, operation, keyclass, keybag);
118          }
119      }
120      else
121          CFDataSetLength(dest, dest_len);    
122      return true;
123  #else /* !USE_KEYSTORE */
124  
125      uint32_t dest_len = (uint32_t)CFDataGetLength(dest);
126      if (CFEqual(operation, kAKSKeyOpEncrypt)) {
127          /* The no encryption case. */
128          if (dest_len >= textLength + 8) {
129              memcpy(CFDataGetMutableBytePtr(dest), source, textLength);
130              memset(CFDataGetMutableBytePtr(dest) + textLength, 8, 8);
131              CFDataSetLength(dest, textLength + 8);
132              *actual_class = keyclass;
133          } else
134              return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass);
135      } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) {
136          if (dest_len + 8 >= textLength) {
137              memcpy(CFDataGetMutableBytePtr(dest), source, textLength - 8);
138              CFDataSetLength(dest, textLength - 8);
139          } else
140              return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass);
141      }
142      return true;
143  #endif /* USE_KEYSTORE */
144  }
145  
146  #if USE_KEYSTORE
147  bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation) {
148      if (error == NULL)
149          return false;
150  
151      if (*error && CFErrorGetCode(*error) != errSecAuthNeeded) {
152          // If we already had an error there, just leave it, no access_control specific error is needed here.
153          return false;
154      }
155  
156      // Create new error instance which adds new access control data appended to existing
157      CFMutableDictionaryRef user_info;
158      if (*error) {
159          CFDictionaryRef old_user_info = CFErrorCopyUserInfo(*error);
160          user_info = CFDictionaryCreateMutableCopy(NULL, 0, old_user_info);
161          CFRelease(old_user_info);
162          CFReleaseNull(*error);
163      } else {
164          user_info = CFDictionaryCreateMutableForCFTypes(NULL);
165      }
166  
167      if (access_control_data) {
168          CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
169          CFMutableArrayRef acls;
170          CFArrayRef old_acls = CFDictionaryGetValue(user_info, key);
171          if (old_acls)
172              acls = CFArrayCreateMutableCopy(NULL, 0, old_acls);
173          else
174              acls = CFArrayCreateMutableForCFTypes(NULL);
175  
176          CFArrayRef pair = CFArrayCreateForCFTypes(NULL, access_control_data, operation, NULL);
177          CFArrayAppendValue(acls, pair);
178          CFRelease(pair);
179  
180          CFDictionarySetValue(user_info, key, acls);
181          CFRelease(key);
182          CFRelease(acls);
183  
184          *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, user_info);
185      }
186      else
187          *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, NULL);
188  
189      CFReleaseSafe(user_info);
190      return false;
191  }
192  
193  static bool merge_der_in_to_data(const void *ed_blob, size_t ed_blob_len, const void *key_blob, size_t key_blob_len, CFMutableDataRef mergedData)
194  {
195      bool ok = false;
196      CFDataRef ed_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ed_blob, ed_blob_len, kCFAllocatorNull);
197      CFDataRef key_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, key_blob, key_blob_len, kCFAllocatorNull);
198  
199      if (ed_data && key_data) {
200          CFDictionaryRef result_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecKSKeyData1, ed_data, kSecKSKeyData2, key_data, NULL);
201  
202          CFDataSetLength(mergedData, 0);
203          CFDataRef der_data = CFPropertyListCreateDERData(kCFAllocatorDefault, result_dict, NULL);
204          if (der_data) {
205              CFDataAppend(mergedData, der_data);
206              CFRelease(der_data);
207              ok = CFDataGetLength(mergedData) > 0;
208          }
209          CFRelease(result_dict);
210      }
211  
212      CFReleaseSafe(ed_data);
213      CFReleaseSafe(key_data);
214      return ok;
215  }
216  
217  bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data)
218  {
219      bool ok = false;
220      CFDataRef tmp_ed_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData1);
221      CFDataRef tmp_key_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData2);
222  
223      if (tmp_ed_data && tmp_key_data &&
224          CFDataGetTypeID() == CFGetTypeID(tmp_ed_data) &&
225          CFDataGetTypeID() == CFGetTypeID(tmp_key_data)) {
226          *ed_data = CFRetain(tmp_ed_data);
227          *key_data = CFRetain(tmp_key_data);
228          ok = true;
229      }
230  
231      return ok;
232  }
233  
234  bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_handle_t keybag, keyclass_t keyclass, CFDataRef access_control_data, CFDataRef acm_context_data, CFErrorRef *error)
235  {
236      const char *operation_string = "";
237      if (CFEqual(operation, kAKSKeyOpDecrypt)) {
238          operation_string = "decrypt";
239      } else if (CFEqual(operation, kAKSKeyOpEncrypt)) {
240          operation_string = "encrypt";
241      } if (CFEqual(operation, kAKSKeyOpDelete)) {
242          operation_string = "delete";
243      }
244  
245      if (aks_return == kAKSReturnNoPermission) {
246          /* Keychain is locked. */
247          SecError(errSecInteractionNotAllowed, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."),
248                             aks_return, operation_string, keyclass, keybag);
249      } else if (aks_return == kAKSReturnPolicyError || aks_return == kAKSReturnBadPassword) {
250          if (aks_return == kAKSReturnBadPassword) {
251              ACMContextRef acm_context_ref = NULL;
252              acm_context_ref = ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data), CFDataGetLength(acm_context_data));
253              if (acm_context_ref) {
254                  ACMContextRemovePassphraseCredentialsByPurposeAndScope(acm_context_ref, kACMPassphrasePurposeGeneral, kACMScopeContext);
255                  ACMContextDelete(acm_context_ref, false);
256              }
257          }
258  
259          /* Item needed authentication. */
260          ks_access_control_needed_error(error, access_control_data, operation);
261      } else if (aks_return == kAKSReturnError || aks_return == kAKSReturnPolicyInvalid || aks_return == kAKSReturnDecodeError) {
262          /* Item can't be decrypted on this device, ever, so drop the item. */
263          SecError(errSecDecode, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."),
264                            aks_return, operation_string, keyclass, keybag);
265  
266      } else if (aks_return == kAKSReturnNotFound) {
267          return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), aks_return, operation, keyclass, keybag);
268      } else {
269          SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32")"),
270                            aks_return, operation_string, keyclass, keybag);
271      }
272  
273      return false;
274  }
275  
276  bool ks_encrypt_acl(keybag_handle_t keybag, keyclass_t keyclass, uint32_t textLength, const uint8_t *source,
277                      CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context,
278                      SecAccessControlRef access_control, CFErrorRef *error) {
279      void *params = NULL, *der = NULL;
280      size_t params_len = 0, der_len = 0;
281      CFDataRef access_control_data = SecAccessControlCopyData(access_control);
282      int aks_return = kAKSReturnSuccess;
283      aks_ref_key_t key_handle = NULL;
284  
285      /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
286      bool ok = false;
287      if (!acm_context || !SecAccessControlIsBound(access_control)) {
288          require_quiet(ok = ks_access_control_needed_error(error, access_control_data, SecAccessControlIsBound(access_control) ? kAKSKeyOpEncrypt : CFSTR("")), out);
289      }
290  
291      aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data), CFDataGetLength(auth_data), CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_len);
292      require_noerr_action_quiet(aks_return = aks_ref_key_create(keybag, keyclass, key_type_sym, params, params_len, &key_handle), out,
293                                 create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error));
294      require_noerr_action_quiet(aks_return = aks_ref_key_encrypt(key_handle, params, params_len, source, textLength, &der, &der_len), out,
295                                 create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error));
296      size_t key_blob_len;
297      const void *key_blob = aks_ref_key_get_blob(key_handle, &key_blob_len);
298      require_action_quiet(key_blob, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to invalid key data, so drop the item."),
299                                             aks_return, "encrypt", keyclass, keybag));
300  
301      require_action_quiet(merge_der_in_to_data(der, der_len, key_blob, key_blob_len, dest), out,
302                     SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to merge failed, so drop the item."),
303                              aks_return, "encrypt", keyclass, keybag));
304  
305      ok = true;
306  
307  out:
308      if (key_handle)
309          aks_ref_key_free(&key_handle);
310      if(params)
311          free(params);
312      if(der)
313          free(der);
314      CFReleaseSafe(access_control_data);
315      return ok;
316  }
317  
318  bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDataRef dest,
319                    CFDataRef acm_context, CFDataRef caller_access_groups,
320                    SecAccessControlRef access_control, CFErrorRef *error) {
321      void *params = NULL, *der = NULL;
322      const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL;
323      size_t params_len = 0, der_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0;
324      CFDataRef access_control_data = SecAccessControlCopyData(access_control);
325      int aks_return = kAKSReturnSuccess;
326  
327      /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
328      bool ok = false;
329      if (!acm_context) {
330          require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out);
331      }
332  
333      aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_len);
334      require_noerr_action_quiet(aks_return = aks_ref_key_decrypt(ref_key, params, params_len, CFDataGetBytePtr(encrypted_data), CFDataGetLength(encrypted_data), &der, &der_len), out,
335                                 create_cferror_from_aks(aks_return, kAKSKeyOpDecrypt, 0, 0, access_control_data, acm_context, error));
336      require_action_quiet(der, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to invalid der data, so drop the item."),
337                                                    aks_return, "decrypt"));
338  
339      CFPropertyListRef decoded_data = NULL;
340      der_decode_plist(kCFAllocatorDefault, &decoded_data, NULL, der, der + der_len);
341      require_action_quiet(decoded_data, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to failed decode der, so drop the item."),
342                                                             aks_return, "decrypt"));
343      if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) {
344          CFDataSetLength(dest, 0);
345          CFDataAppend(dest, decoded_data);
346          CFRelease(decoded_data);
347      }
348      else {
349          CFRelease(decoded_data);
350          require_action_quiet(false, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to wrong data, so drop the item."),
351                                                          aks_return, "decrypt"));
352      }
353  
354      ok = true;
355  
356  out:
357      if(params)
358          free(params);
359      if(der)
360          free(der);
361      CFReleaseSafe(access_control_data);
362      return ok;
363  }
364  
365  bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, 
366                    CFDataRef acm_context, CFDataRef caller_access_groups,
367                    SecAccessControlRef access_control, CFErrorRef *error) {
368      void *params = NULL;
369      CFDataRef access_control_data = NULL;
370      int aks_return = kAKSReturnSuccess;
371      bool ok = false;
372  
373      nrequire_action_quiet(CFEqualSafe(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true);
374  
375      /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
376      if (!acm_context) {
377          require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out);
378      }
379  
380      access_control_data = SecAccessControlCopyData(access_control);
381      const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL;
382      size_t params_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0;
383      aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_len);
384      require_noerr_action_quiet(aks_return = aks_ref_key_delete(ref_key, params, params_len), out,
385                                 create_cferror_from_aks(aks_return, kAKSKeyOpDelete, 0, 0, access_control_data, acm_context, error));
386  
387      ok = true;
388  
389  out:
390      if(params)
391          free(params);
392      CFReleaseSafe(access_control_data);
393      return ok;
394  }
395  
396  const void* ks_ref_key_get_external_data(keybag_handle_t keybag, CFDataRef key_data, aks_ref_key_t *ref_key, size_t *external_data_len, CFErrorRef *error) {
397      int aks_return = aks_ref_key_create_with_blob(keybag, CFDataGetBytePtr(key_data), CFDataGetLength(key_data), ref_key);
398      if (aks_return == kAKSReturnBadArgument) {
399          SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob because bad data (bag: %"PRId32")"), keybag);
400          return NULL;
401      // As of this writing the only other error code is kAKSReturnInternalError but we don't want to rely on that
402      } else if (aks_return != kAKSReturnSuccess) {
403          SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob: %x (bag: %"PRId32")"), aks_return, keybag);
404          return NULL;
405      }
406      return aks_ref_key_get_external_data(*ref_key, external_data_len);
407  }
408  #endif
409  
410  bool use_hwaes(void) {
411  #if !TARGET_OS_BRIDGE
412      static bool use_hwaes;
413      static dispatch_once_t check_once;
414      dispatch_once(&check_once, ^{
415          use_hwaes = hwaes_key_available();
416          if (use_hwaes) {
417              secinfo("aks", "using hwaes key");
418          } else {
419              secerror("unable to access hwaes key");
420          }
421      });
422      return use_hwaes;
423  #else
424      return false;
425  #endif // TARGET_OS_BRIDGE
426  }
427  
428  bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) {
429  #if USE_KEYSTORE
430      kern_return_t kernResult;
431      if (!asData(keybag, error)) return false;
432      kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle);
433      if (kernResult)
434          return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag);
435  
436      if (password) {
437          kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password));
438          if (kernResult) {
439              aks_unload_bag(*handle);
440              return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed"));
441          }
442      }
443      return true;
444  #else /* !USE_KEYSTORE */
445      *handle = KEYBAG_NONE;
446      return true;
447  #endif /* USE_KEYSTORE */
448  }
449  
450  bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) {
451  #if USE_KEYSTORE
452  	IOReturn kernResult = aks_unload_bag(keybag);
453      if (kernResult) {
454          return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed"));
455      }
456  #endif /* USE_KEYSTORE */
457      return true;
458  }
459