/ kcm / store.c
store.c
  1  /*
  2   * Copyright (c) 2011 Kungliga Tekniska Högskolan
  3   * (Royal Institute of Technology, Stockholm, Sweden).
  4   * All rights reserved.
  5   *
  6   * Portions Copyright (c) 2011 Apple Inc. All rights reserved.
  7   *
  8   * Redistribution and use in source and binary forms, with or without
  9   * modification, are permitted provided that the following conditions
 10   * are met:
 11   *
 12   * 1. Redistributions of source code must retain the above copyright
 13   *    notice, this list of conditions and the following disclaimer.
 14   *
 15   * 2. Redistributions in binary form must reproduce the above copyright
 16   *    notice, this list of conditions and the following disclaimer in the
 17   *    documentation and/or other materials provided with the distribution.
 18   *
 19   * 3. Neither the name of the Institute nor the names of its contributors
 20   *    may be used to endorse or promote products derived from this software
 21   *    without specific prior written permission.
 22   *
 23   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 24   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 26   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 27   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 29   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 30   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 31   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 32   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 33   * SUCH DAMAGE.
 34   */
 35  
 36  #include "kcm_locl.h"
 37  
 38  #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
 39  #include <IOKit/IOBSD.h>
 40  #include <IOKit/IOKitLib.h>
 41  
 42  #include <uuid/uuid.h>
 43  #include <stdio.h>
 44  #include <stdarg.h>
 45  
 46  static io_connect_t
 47  openiodev(void)
 48  {
 49      io_registry_entry_t service;
 50      CFMutableDictionaryRef matching;
 51      io_connect_t conn;
 52      kern_return_t kr;
 53      
 54      matching = IOServiceMatching(kAppleFDEKeyStoreServiceName);
 55      if (matching == NULL)
 56  	return IO_OBJECT_NULL;
 57  
 58      service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
 59      if (service == IO_OBJECT_NULL)
 60  	return IO_OBJECT_NULL;
 61      
 62      kr = IOServiceOpen(service, mach_task_self(), 0, &conn);
 63      IOObjectRelease(service);
 64      if (kr != KERN_SUCCESS)
 65  	return IO_OBJECT_NULL;
 66      
 67      kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
 68      if (kr != KERN_SUCCESS) {
 69  	IOServiceClose(conn);
 70  	return IO_OBJECT_NULL;
 71      }
 72      
 73      return conn;
 74  }
 75  
 76  static void
 77  closeiodev(io_connect_t conn)
 78  {
 79      kern_return_t kr;
 80  
 81      kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
 82      if (kr != KERN_SUCCESS)
 83  	return;
 84  
 85      IOServiceClose(conn);
 86  }
 87  
 88  krb5_error_code
 89  kcm_create_key(krb5_uuid uuid)
 90  {
 91      io_connect_t conn;
 92      createKeyGetUUID_InStruct_t createKey;
 93      kern_return_t kr;
 94      uuid_OutStruct_t key;
 95      size_t outputStructSize = sizeof(key);
 96  
 97      conn = openiodev();
 98      if (conn == IO_OBJECT_NULL)
 99  	return EINVAL;
100      
101      createKey.keySizeInBytes = V1_KEYSIZE;
102      createKey.algorithm = fDE_ALG_AESXTS;
103      
104      memset(&key, 0, sizeof(key));
105      
106      kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_createKeyGetUUID,
107  			     NULL, 0,
108  			     &createKey, sizeof(createKey),
109  			     NULL, 0,
110  			     &key, &outputStructSize);
111      closeiodev(conn);
112      if (kr != KERN_SUCCESS)
113  	return EINVAL;
114      
115      memcpy(uuid, key.uuid, sizeof(key.uuid));
116      
117      return 0;
118  }
119  
120  krb5_error_code
121  kcm_store_io(krb5_context context,
122  	     krb5_uuid uuid,
123  	     void *ptr,
124  	     size_t length,
125  	     krb5_data *data,
126  	     bool encrypt)
127  {
128      xtsEncrypt_InStruct_t xtsEncrypt_InStruct;
129      size_t inseed_size = 64;
130      io_connect_t conn;
131      kern_return_t kr;
132      uint8_t *inseed;
133      krb5_crypto crypto = NULL;
134      krb5_error_code ret;
135      
136      krb5_data_zero(data);
137  
138      inseed = malloc(inseed_size);
139      if (inseed == NULL)
140  	err(1, "malloc");
141  
142      memset(inseed, 0, inseed_size);
143      
144      conn = openiodev();
145      if (conn == IO_OBJECT_NULL) {
146  	free(inseed);
147  	return EINVAL;
148      }
149  
150      uuid_copy(xtsEncrypt_InStruct.key_uuid, uuid);
151      xtsEncrypt_InStruct.bufferAddress = (uint64_t) (intptr_t) inseed;
152      xtsEncrypt_InStruct.bufferLength = (uint64_t) inseed_size;
153      memset(xtsEncrypt_InStruct.tweak, 0, XTS_TWEAK_BYTES);
154      
155      kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_xtsEncrypt, 
156  			     NULL, 0, 
157  			     & xtsEncrypt_InStruct, sizeof(xtsEncrypt_InStruct), 
158  			     NULL, 0,
159  			     NULL, 0);
160      closeiodev(conn);
161      if (kr != KERN_SUCCESS) {
162  	free(inseed);
163  	return EINVAL;
164      }
165      
166      CC_SHA256(inseed, (CC_LONG)inseed_size, inseed);
167  
168      krb5_keyblock keyblock;
169      keyblock.keytype = ETYPE_AES128_CTS_HMAC_SHA1_96;
170      keyblock.keyvalue.data = inseed;
171      keyblock.keyvalue.length = 16;
172      
173      ret = krb5_crypto_init(context, &keyblock, 0, &crypto);
174      free(inseed);
175      if (ret)
176  	return ret;
177  
178      if (encrypt)
179  	ret = krb5_encrypt(context, crypto, 1, ptr, length, data);
180      else
181  	ret = krb5_decrypt(context, crypto, 1, ptr, length, data);
182  
183      krb5_crypto_destroy(context, crypto);
184      
185      return ret;
186  }