cprotect.h   [plain text]


/*
 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

#ifndef _SYS_CPROTECT_H_
#define	_SYS_CPROTECT_H_

#ifdef __cplusplus
extern "C" {
#endif

#if KERNEL_PRIVATE

#include <sys/cdefs.h>
#include <sys/content_protection.h>
#include <sys/kernel_types.h>
#include <crypto/aes.h>

#define CP_IV_KEYSIZE             20	/* 16x8 = 128, but SHA1 pushes 20 bytes so keep space for that */
#define CP_MAX_KEYSIZE            32	/* 8x4 = 32, 32x8 = 256 */
#define CP_MAX_WRAPPEDKEYSIZE     128	/* The size of the largest allowed key */
#define CP_INITIAL_WRAPPEDKEYSIZE 40
#define CP_V2_WRAPPEDKEYSIZE      40	/* Size of the wrapped key in a v2 EA */
#define CP_V4_RESERVEDBYTES       20	/* Number of reserved bytes in EA still present */

/* lock events from AppleKeyStore */
#define CP_LOCKED_STATE           0 	/* Device is locked */
#define CP_UNLOCKED_STATE         1 	/* Device is unlocked */

#define CP_MAX_STATE			  1 	/* uint8_t ; maximum # of states is 255 */

#define CP_LOCKED_KEYCHAIN        0
#define CP_UNLOCKED_KEYCHAIN      1

/* For struct cprotect: cp_flags */
#define CP_NEEDS_KEYS             0x01	/* File needs persistent keys */
#define CP_KEY_FLUSHED            0x02	/* File's unwrapped key has been purged from memory */
#define CP_NO_XATTR               0x04	/* Key info has not been saved as EA to the FS */
#define CP_OFF_IV_ENABLED         0x08	/* Only go down relative IV route if this flag is set */
#define CP_RELOCATION_INFLIGHT    0x10	/* File with offset IVs is in the process of being relocated. */
#define CP_SEP_WRAPPEDKEY		  0x20  /* Wrapped key delivered from keybag */

/* Content Protection VNOP Operation flags */
#define CP_READ_ACCESS            0x1
#define CP_WRITE_ACCESS           0x2

/*
 * Check for this version when deciding to enable features
 * For iOS 4, CP_CURRENT_MAJOR_VERS = 2.0
 * For iOS 5, CP_CURRENT_MAJOR_VERS = 4.0
 */
#define CONTENT_PROTECTION_XATTR_NAME	"com.apple.system.cprotect"
#define CP_NEW_MAJOR_VERS         4
#define CP_PREV_MAJOR_VERS        2
#define CP_MINOR_VERS             0

typedef struct cprotect *cprotect_t;
typedef struct cp_wrap_func *cp_wrap_func_t;
typedef struct cp_global_state *cp_global_state_t;
typedef struct cp_xattr *cp_xattr_t;

typedef struct cnode * cnode_ptr_t;
//forward declare the struct.
struct hfsmount;

/* Structures passed between HFS and AKS kext */
typedef struct {
	void     *key;
	unsigned key_len;
	void     *iv_key;
	unsigned iv_key_len;
	uint32_t flags;
} cp_raw_key_s, *cp_raw_key_t;

typedef struct {
	void     *key;
	unsigned key_len;
	uint32_t dp_class;
} cp_wrapped_key_s, *cp_wrapped_key_t;

typedef struct {
	ino64_t  inode;
	uint32_t volume;
	pid_t    pid;
	uid_t    uid;
} cp_cred_s, *cp_cred_t;

/* The wrappers are invoked on the AKS kext */
typedef int unwrapper_t(cp_cred_t access, const cp_wrapped_key_t wrapped_key_in, cp_raw_key_t key_out);
typedef int rewrapper_t(cp_cred_t access, uint32_t dp_class, const cp_wrapped_key_t wrapped_key_in, cp_wrapped_key_t wrapped_key_out);
typedef int new_key_t(cp_cred_t access, uint32_t dp_class, cp_raw_key_t key_out, cp_wrapped_key_t wrapped_key_out);
typedef int invalidater_t(cp_cred_t access); /* invalidates keys */


/* Flags for Interaction between AKS / Kernel */
#define CP_RAW_KEY_WRAPPEDKEY 0x00000001


/*
 * Runtime-only structure containing the content protection status
 * for the given file.  This is contained within the cnode
 * This is passed down to IOStorageFamily via the bufattr struct
 *
 ******************************************************
 * Some Key calculation information for offset based IV
 ******************************************************
 * Kf  = original 256 bit per file key
 * Kiv = SHA1(Kf), use full Kf, but truncate Kiv to 128 bits
 * Kiv can be cached in the cprotect, so it only has to be calculated once for the file init
 *
 * IVb = Encrypt(Kiv, offset)
 *
 */
struct cprotect {
	uint32_t	cp_flags;
	uint32_t	cp_pclass;
	aes_encrypt_ctx	cp_cache_iv_ctx;
	uint32_t	cp_cache_key_len;
	uint8_t		cp_cache_key[CP_MAX_KEYSIZE];
	uint32_t	cp_persistent_key_len;
	void*		cp_backing_cnode;
	uint8_t		cp_persistent_key[];
};

struct cp_wrap_func {
	new_key_t       *new_key;
	unwrapper_t     *unwrapper;
	rewrapper_t     *rewrapper;
	invalidater_t	*invalidater;
};

struct cp_global_state {
	uint8_t	wrap_functions_set;
	uint8_t	lock_state;
	u_int16_t reserved;
};

/*
 * On-disk structure written as the per-file EA payload
 * All on-disk multi-byte fields for the CP XATTR must be stored
 * little-endian on-disk.  This means they must be endian swapped to
 * L.E on getxattr() and converted to LE on setxattr().
 *
 * This structure is a fixed length and is tightly packed.
 * 56 bytes total.
 */
struct cp_xattr_v2 {
	u_int16_t xattr_major_version;
	u_int16_t xattr_minor_version;
	u_int32_t flags;
	u_int32_t persistent_class;
	u_int32_t key_size;
	uint8_t   persistent_key[CP_V2_WRAPPEDKEYSIZE];
} __attribute__((aligned(2), packed));


/*
 * V4 Content Protection EA On-Disk Layout.
 *
 * This structure must be tightly packed, but the *size can vary*
 * depending on the length of the key.  At MOST, the key length will be
 * CP_MAX_WRAPPEDKEYSIZE, but the length is defined by the key_size field.
 *
 * Either way, the packing must be applied to ensure that the key data is
 * retrievable in the right location relative to the start of the struct.
 *
 * Fully packed, this structure can range from :
 * 		MIN: 36 bytes (no key -- used with directories)
 *		MAX: 164 bytes (with 128 byte key)
 *
 * During runtime we always allocate with the full 128 byte key, but only
 * use as much of the key buffer as needed. It must be tightly packed, though.
 */

struct cp_xattr_v4 {
	u_int16_t xattr_major_version;
	u_int16_t xattr_minor_version;
	u_int32_t flags;
	u_int32_t persistent_class;
	u_int32_t key_size;
	/* CP V4 Reserved Bytes == 20 */
	u_int8_t reserved[CP_V4_RESERVEDBYTES];
	/* All above fields are fixed regardless of key length (36 bytes) */
	/* Max Wrapped Size == 128 */
	uint8_t   persistent_key[CP_MAX_WRAPPEDKEYSIZE];
} __attribute__((aligned(2), packed));


/*
 * The Root Directory's EA (fileid 1) is special; it defines information about
 * what capabilities the filesystem is using.
 *
 * The data is still stored little endian.
 *
 * Note that this structure is tightly packed: 28 bytes total.
 */
 struct cp_root_xattr {
 	u_int16_t major_version;
 	u_int16_t minor_version;
 	u_int64_t flags;
	u_int8_t reserved[16];
} __attribute__((aligned(2), packed));


/*
 * Functions to check the status of a CP and to query
 * the containing filesystem to see if it is supported.
 */
int cp_vnode_getclass(vnode_t, int *);
int cp_vnode_setclass(vnode_t, uint32_t);
int cp_vnode_transcode(vnode_t);

int cp_key_store_action(int);
int cp_register_wraps(cp_wrap_func_t);

int cp_entry_init(cnode_ptr_t, struct mount *);
int cp_entry_gentempkeys(struct cprotect **entry_ptr, struct hfsmount *hfsmp);
int cp_needs_tempkeys (struct hfsmount *hfsmp, int* needs);
void cp_entry_destroy(struct cprotect *entry_ptr);
void cp_replace_entry (struct cnode *cp, struct cprotect *newentry);
cnode_ptr_t cp_get_protected_cnode(vnode_t);
int cp_handle_vnop(vnode_t, int, int);
int cp_fs_protected (mount_t);
int cp_getrootxattr (struct hfsmount *hfsmp, struct cp_root_xattr *outxattr);
int cp_setrootxattr (struct hfsmount *hfsmp, struct cp_root_xattr *newxattr);
int cp_setxattr(struct cnode *cp, struct cprotect *entry, struct hfsmount *hfsmp, uint32_t fileid, int options);
int cp_generate_keys (struct hfsmount *hfsmp, struct cnode *cp, int targetclass, struct cprotect **newentry);
int cp_setup_newentry (struct hfsmount *hfsmp, struct cnode *dcp, int32_t suppliedclass, 
		mode_t cmode, struct cprotect **tmpentry);
int cp_handle_relocate (cnode_ptr_t cp, struct hfsmount *hfsmp);
int cp_handle_open(struct vnode *vp, int mode);
int cp_get_root_major_vers (struct vnode *vp, uint32_t *level);
int cp_get_default_level (struct vnode *vp, uint32_t *level);
int cp_is_valid_class (int isdir, int32_t protectionclass);

#endif	/* KERNEL_PRIVATE */

#ifdef __cplusplus
};
#endif

#endif /* !_SYS_CPROTECT_H_ */