]>
Commit | Line | Data |
---|---|---|
39037602 A |
1 | /* |
2 | * Copyright (c) 2015 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_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. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | #include <sys/cprotect.h> | |
30 | #include <sys/malloc.h> | |
31 | #include <sys/mount_internal.h> | |
32 | #include <sys/filio.h> | |
33 | #include <sys/content_protection.h> | |
34 | #include <libkern/crypto/sha1.h> | |
35 | #include <libkern/libkern.h> | |
36 | ||
37 | #define PTR_ADD(type, base, offset) (type)((uintptr_t)(base) + (offset)) | |
38 | ||
39 | // -- struct cpx -- | |
40 | ||
41 | /* | |
42 | * This structure contains the unwrapped key and is passed to the lower layers. | |
43 | * It is private so users must use the accessors declared in sys/cprotect.h | |
44 | * to read/write it. | |
45 | */ | |
46 | ||
47 | // cpx_flags | |
48 | typedef uint32_t cpx_flags_t; | |
49 | enum { | |
50 | CPX_SEP_WRAPPEDKEY = 0x01, | |
51 | CPX_IV_AES_CTX_INITIALIZED = 0x02, | |
52 | CPX_USE_OFFSET_FOR_IV = 0x04, | |
53 | ||
54 | // Using AES IV context generated from key | |
55 | CPX_IV_AES_CTX_VFS = 0x08, | |
56 | CPX_SYNTHETIC_OFFSET_FOR_IV = 0x10, | |
57 | }; | |
58 | ||
59 | struct cpx { | |
60 | #if DEBUG | |
61 | uint32_t cpx_magic1; | |
62 | #endif | |
63 | cpx_flags_t cpx_flags; | |
64 | uint16_t cpx_max_key_len; | |
65 | uint16_t cpx_key_len; | |
66 | aes_encrypt_ctx cpx_iv_aes_ctx; // Context used for generating the IV | |
67 | uint8_t cpx_cached_key[]; | |
68 | } __attribute__((packed)); | |
69 | ||
70 | // -- cpx_t accessors -- | |
71 | ||
72 | size_t cpx_size(size_t key_size) | |
73 | { | |
74 | size_t size = sizeof(struct cpx) + key_size; | |
75 | ||
76 | #if DEBUG | |
77 | size += 4; // Extra for magic | |
78 | #endif | |
79 | ||
80 | return size; | |
81 | } | |
82 | ||
83 | size_t cpx_sizex(const struct cpx *cpx) | |
84 | { | |
85 | return cpx_size(cpx->cpx_max_key_len); | |
86 | } | |
87 | ||
88 | cpx_t cpx_alloc(size_t key_len) | |
89 | { | |
90 | cpx_t cpx; | |
91 | ||
92 | MALLOC(cpx, cpx_t, cpx_size(key_len), M_TEMP, M_WAITOK); | |
93 | ||
94 | cpx_init(cpx, key_len); | |
95 | ||
96 | return cpx; | |
97 | } | |
98 | ||
99 | #if DEBUG | |
100 | static const uint32_t cpx_magic1 = 0x7b787063; // cpx{ | |
101 | static const uint32_t cpx_magic2 = 0x7870637d; // }cpx | |
102 | #endif | |
103 | ||
104 | void cpx_free(cpx_t cpx) | |
105 | { | |
106 | #if DEBUG | |
107 | assert(cpx->cpx_magic1 == cpx_magic1); | |
108 | assert(*PTR_ADD(uint32_t *, cpx, cpx_sizex(cpx) - 4) == cpx_magic2); | |
109 | #endif | |
110 | bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len); | |
111 | FREE(cpx, M_TEMP); | |
112 | } | |
113 | ||
114 | void cpx_init(cpx_t cpx, size_t key_len) | |
115 | { | |
116 | #if DEBUG | |
117 | cpx->cpx_magic1 = cpx_magic1; | |
118 | *PTR_ADD(uint32_t *, cpx, cpx_size(key_len) - 4) = cpx_magic2; | |
119 | #endif | |
120 | cpx->cpx_flags = 0; | |
121 | cpx->cpx_key_len = 0; | |
122 | cpx->cpx_max_key_len = key_len; | |
123 | } | |
124 | ||
125 | bool cpx_is_sep_wrapped_key(const struct cpx *cpx) | |
126 | { | |
127 | return ISSET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY); | |
128 | } | |
129 | ||
130 | void cpx_set_is_sep_wrapped_key(struct cpx *cpx, bool v) | |
131 | { | |
132 | if (v) | |
133 | SET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY); | |
134 | else | |
135 | CLR(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY); | |
136 | } | |
137 | ||
138 | bool cpx_use_offset_for_iv(const struct cpx *cpx) | |
139 | { | |
140 | return ISSET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV); | |
141 | } | |
142 | ||
143 | void cpx_set_use_offset_for_iv(struct cpx *cpx, bool v) | |
144 | { | |
145 | if (v) | |
146 | SET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV); | |
147 | else | |
148 | CLR(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV); | |
149 | } | |
150 | ||
151 | bool cpx_synthetic_offset_for_iv(const struct cpx *cpx) | |
152 | { | |
153 | return ISSET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV); | |
154 | } | |
155 | ||
156 | void cpx_set_synthetic_offset_for_iv(struct cpx *cpx, bool v) | |
157 | { | |
158 | if (v) | |
159 | SET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV); | |
160 | else | |
161 | CLR(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV); | |
162 | } | |
163 | ||
164 | uint16_t cpx_max_key_len(const struct cpx *cpx) | |
165 | { | |
166 | return cpx->cpx_max_key_len; | |
167 | } | |
168 | ||
169 | uint16_t cpx_key_len(const struct cpx *cpx) | |
170 | { | |
171 | return cpx->cpx_key_len; | |
172 | } | |
173 | ||
174 | void cpx_set_key_len(struct cpx *cpx, uint16_t key_len) | |
175 | { | |
176 | cpx->cpx_key_len = key_len; | |
177 | ||
178 | if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS)) { | |
179 | /* | |
180 | * We assume that if the key length is being modified, the key | |
181 | * has changed. As a result, un-set any bits related to the | |
182 | * AES context, if needed. They should be re-generated | |
183 | * on-demand. | |
184 | */ | |
185 | CLR(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_IV_AES_CTX_VFS); | |
186 | } | |
187 | } | |
188 | ||
189 | bool cpx_has_key(const struct cpx *cpx) | |
190 | { | |
191 | return cpx->cpx_key_len > 0; | |
192 | } | |
193 | ||
194 | #pragma clang diagnostic push | |
195 | #pragma clang diagnostic ignored "-Wcast-qual" | |
196 | void *cpx_key(const struct cpx *cpx) | |
197 | { | |
198 | return (void *)cpx->cpx_cached_key; | |
199 | } | |
200 | #pragma clang diagnostic pop | |
201 | ||
202 | void cpx_set_aes_iv_key(struct cpx *cpx, void *iv_key) | |
203 | { | |
204 | aes_encrypt_key128(iv_key, &cpx->cpx_iv_aes_ctx); | |
205 | SET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_USE_OFFSET_FOR_IV); | |
206 | CLR(cpx->cpx_flags, CPX_IV_AES_CTX_VFS); | |
207 | } | |
208 | ||
209 | aes_encrypt_ctx *cpx_iv_aes_ctx(struct cpx *cpx) | |
210 | { | |
211 | if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED)) | |
212 | return &cpx->cpx_iv_aes_ctx; | |
213 | ||
214 | SHA1_CTX sha1ctxt; | |
215 | uint8_t digest[SHA_DIGEST_LENGTH]; /* Kiv */ | |
216 | ||
217 | /* First init the cp_cache_iv_key[] */ | |
218 | SHA1Init(&sha1ctxt); | |
219 | ||
220 | /* | |
221 | * We can only use this when the keys are generated in the AP; As a result | |
222 | * we only use the first 32 bytes of key length in the cache key | |
223 | */ | |
224 | SHA1Update(&sha1ctxt, cpx->cpx_cached_key, cpx->cpx_key_len); | |
225 | SHA1Final(digest, &sha1ctxt); | |
226 | ||
227 | cpx_set_aes_iv_key(cpx, digest); | |
228 | SET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS); | |
229 | ||
230 | return &cpx->cpx_iv_aes_ctx; | |
231 | } | |
232 | ||
233 | void cpx_flush(cpx_t cpx) | |
234 | { | |
235 | bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len); | |
236 | bzero(&cpx->cpx_iv_aes_ctx, sizeof(cpx->cpx_iv_aes_ctx)); | |
237 | cpx->cpx_flags = 0; | |
238 | cpx->cpx_key_len = 0; | |
239 | } | |
240 | ||
241 | bool cpx_can_copy(const struct cpx *src, const struct cpx *dst) | |
242 | { | |
243 | return src->cpx_key_len <= dst->cpx_max_key_len; | |
244 | } | |
245 | ||
246 | void cpx_copy(const struct cpx *src, cpx_t dst) | |
247 | { | |
248 | uint16_t key_len = cpx_key_len(src); | |
249 | cpx_set_key_len(dst, key_len); | |
250 | memcpy(cpx_key(dst), cpx_key(src), key_len); | |
251 | dst->cpx_flags = src->cpx_flags; | |
252 | if (ISSET(dst->cpx_flags, CPX_IV_AES_CTX_INITIALIZED)) | |
253 | dst->cpx_iv_aes_ctx = src->cpx_iv_aes_ctx; | |
254 | } | |
255 | ||
256 | static struct cp_wrap_func g_cp_wrap_func = {}; | |
257 | ||
258 | static int | |
259 | cp_lock_vfs_callback(mount_t mp, void *arg) | |
260 | { | |
261 | VFS_IOCTL(mp, FIODEVICELOCKED, arg, 0, vfs_context_kernel()); | |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
266 | int | |
267 | cp_key_store_action(cp_key_store_action_t action) | |
268 | { | |
269 | switch (action) { | |
270 | case CP_ACTION_LOCKED: | |
271 | case CP_ACTION_UNLOCKED:; | |
272 | cp_lock_state_t state = (action == CP_ACTION_LOCKED | |
273 | ? CP_LOCKED_STATE : CP_UNLOCKED_STATE); | |
274 | return vfs_iterate(0, cp_lock_vfs_callback, (void *)(uintptr_t)state); | |
275 | default: | |
276 | return -1; | |
277 | } | |
278 | } | |
279 | ||
280 | int | |
281 | cp_register_wraps(cp_wrap_func_t key_store_func) | |
282 | { | |
283 | g_cp_wrap_func.new_key = key_store_func->new_key; | |
284 | g_cp_wrap_func.unwrapper = key_store_func->unwrapper; | |
285 | g_cp_wrap_func.rewrapper = key_store_func->rewrapper; | |
286 | /* do not use invalidater until rdar://12170050 goes in ! */ | |
287 | g_cp_wrap_func.invalidater = key_store_func->invalidater; | |
288 | g_cp_wrap_func.backup_key = key_store_func->backup_key; | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
293 | int cp_rewrap_key(cp_cred_t access, uint32_t dp_class, | |
294 | const cp_wrapped_key_t wrapped_key_in, | |
295 | cp_wrapped_key_t wrapped_key_out) | |
296 | { | |
297 | if (!g_cp_wrap_func.rewrapper) | |
298 | return ENXIO; | |
299 | return g_cp_wrap_func.rewrapper(access, dp_class, wrapped_key_in, | |
300 | wrapped_key_out); | |
301 | } | |
302 | ||
303 | int cp_new_key(cp_cred_t access, uint32_t dp_class, cp_raw_key_t key_out, | |
304 | cp_wrapped_key_t wrapped_key_out) | |
305 | { | |
306 | if (!g_cp_wrap_func.new_key) | |
307 | return ENXIO; | |
308 | return g_cp_wrap_func.new_key(access, dp_class, key_out, wrapped_key_out); | |
309 | } | |
310 | ||
311 | int cp_unwrap_key(cp_cred_t access, const cp_wrapped_key_t wrapped_key_in, | |
312 | cp_raw_key_t key_out) | |
313 | { | |
314 | if (!g_cp_wrap_func.unwrapper) | |
315 | return ENXIO; | |
316 | return g_cp_wrap_func.unwrapper(access, wrapped_key_in, key_out); | |
317 | } | |
318 | ||
319 | int cp_get_backup_key(cp_cred_t access, const cp_wrapped_key_t wrapped_key_in, | |
320 | cp_wrapped_key_t wrapped_key_out) | |
321 | { | |
322 | if (!g_cp_wrap_func.backup_key) | |
323 | return ENXIO; | |
324 | return g_cp_wrap_func.backup_key(access, wrapped_key_in, wrapped_key_out); | |
325 | } | |
326 | ||
327 | int | |
328 | cp_is_valid_class(int isdir, int32_t protectionclass) | |
329 | { | |
330 | /* | |
331 | * The valid protection classes are from 0 -> N | |
332 | * We use a signed argument to detect unassigned values from | |
333 | * directory entry creation time in HFS. | |
334 | */ | |
335 | if (isdir) { | |
336 | /* Directories are not allowed to have F, but they can have "NONE" */ | |
337 | return ((protectionclass >= PROTECTION_CLASS_DIR_NONE) && | |
338 | (protectionclass <= PROTECTION_CLASS_D)); | |
339 | } | |
340 | else { | |
341 | return ((protectionclass >= PROTECTION_CLASS_A) && | |
342 | (protectionclass <= PROTECTION_CLASS_F)); | |
343 | } | |
344 | } | |
345 | ||
346 | /* | |
347 | * Parses versions of the form 12A316, i.e. <major><minor><revision> and | |
348 | * returns a uint32_t in the form 0xaabbcccc where aa = <major>, | |
349 | * bb = <ASCII char>, cccc = <revision>. | |
350 | */ | |
351 | static cp_key_os_version_t | |
352 | parse_os_version(const char *vers) | |
353 | { | |
354 | const char *p = vers; | |
355 | ||
356 | int a = 0; | |
357 | while (*p >= '0' && *p <= '9') { | |
358 | a = a * 10 + *p - '0'; | |
359 | ++p; | |
360 | } | |
361 | ||
362 | if (!a) | |
363 | return 0; | |
364 | ||
365 | int b = *p++; | |
366 | if (!b) | |
367 | return 0; | |
368 | ||
369 | int c = 0; | |
370 | while (*p >= '0' && *p <= '9') { | |
371 | c = c * 10 + *p - '0'; | |
372 | ++p; | |
373 | } | |
374 | ||
375 | if (!c) | |
376 | return 0; | |
377 | ||
378 | return (a & 0xff) << 24 | b << 16 | (c & 0xffff); | |
379 | } | |
380 | ||
381 | cp_key_os_version_t | |
382 | cp_os_version(void) | |
383 | { | |
384 | static cp_key_os_version_t cp_os_version; | |
385 | ||
386 | if (cp_os_version) | |
387 | return cp_os_version; | |
388 | ||
389 | if (!osversion[0]) | |
390 | return 0; | |
391 | ||
392 | cp_os_version = parse_os_version(osversion); | |
393 | if (!cp_os_version) { | |
394 | printf("cp_os_version: unable to parse osversion `%s'\n", osversion); | |
395 | cp_os_version = 1; | |
396 | } | |
397 | ||
398 | return cp_os_version; | |
399 | } |