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 46static io_connect_t 47openiodev(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 76static void 77closeiodev(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 88krb5_error_code 89kcm_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 120krb5_error_code 121kcm_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} 187