#ifndef HFS_CPROTECT_H_
#define HFS_CPROTECT_H_
#if KERNEL_PRIVATE
#include <sys/cprotect.h>
#include <sys/cdefs.h>
#include <sys/content_protection.h>
#include <sys/kernel_types.h>
#include <crypto/aes.h>
#include <sys/kdebug.h>
#include "hfs.h"
#include "hfs_fsctl.h"
__BEGIN_DECLS
#define CP_IV_KEYSIZE 16
#define CP_MAX_KEYSIZE 32
#define CP_MAX_CACHEBUFLEN 64
#define CP_INITIAL_WRAPPEDKEYSIZE 40
#define CP_V2_WRAPPEDKEYSIZE 40
#define CP_V4_RESERVEDBYTES 16
#define CP_LOCKED_KEYCHAIN 0
#define CP_UNLOCKED_KEYCHAIN 1
#define CONTENT_PROTECTION_XATTR_NAME "com.apple.system.cprotect"
#define CONTENT_PROTECTION_XATTR_NAME_CHARS \
{ 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', \
'.', 's', 'y', 's', 't', 'e', 'm', \
'.', 'c', 'p', 'r', 'o', 't', 'e', 'c', 't' }
#define CP_CURRENT_VERS CP_VERS_5
#define CP_VERS_5 5 // iOS 8.1
#define CP_VERS_4 4 // iOS 5
#define CP_VERS_2 2 // iOS 4
#define CP_MINOR_VERS 0
#define CP_EFFECTIVE_CLASSMASK 0x0000001f
typedef uint32_t cp_key_class_t;
typedef uint32_t cp_key_os_version_t;
#define CP_CLASS(x) ((cp_key_class_t)(CP_EFFECTIVE_CLASSMASK & (x)))
#define CP_CRYPTO_G1 0x00000020
typedef struct cp_xattr *cp_xattr_t;
typedef struct cnode * cnode_ptr_t;
struct hfsmount;
#define CP_KEYWRAP_DIFFCLASS 0x00000001
enum {
OFF_RSRC_BIT = 0x4000000000000000,
};
typedef int64_t off_rsrc_t;
static inline bool off_rsrc_is_rsrc(off_rsrc_t off_rsrc)
{
return off_rsrc & OFF_RSRC_BIT;
}
static inline off_t off_rsrc_get_off(off_rsrc_t off_rsrc)
{
return off_rsrc & (OFF_RSRC_BIT - 1);
}
static inline off_rsrc_t off_rsrc_make(off_t offset, bool is_rsrc)
{
return offset | (is_rsrc ? OFF_RSRC_BIT : 0);
}
typedef uint32_t cpx_flags_t;
enum {
CPX_SEP_WRAPPEDKEY = 0x01,
CPX_IV_AES_CTX_INITIALIZED = 0x02,
CPX_USE_OFFSET_FOR_IV = 0x04,
CPX_IV_AES_CTX_HFS = 0x08,
};
struct cpx {
#if DEBUG
uint32_t cpx_magic1;
#endif
cpx_flags_t cpx_flags;
uint16_t cpx_max_key_len;
uint16_t cpx_key_len;
aes_encrypt_ctx cpx_iv_aes_ctx; uint8_t cpx_cached_key[];
} __attribute__((packed));
typedef struct cp_key_pair {
uint16_t cpkp_max_pers_key_len;
uint16_t cpkp_pers_key_len;
struct cpx cpkp_cpx;
} cp_key_pair_t;
typedef uint32_t cp_flags_t;
enum {
CP_NO_XATTR = 0x01,
CP_RELOCATION_INFLIGHT = 0x02,
CP_HAS_A_KEY = 0x08,
};
struct cprotect {
#if DEBUG
uint32_t cp_magic1;
#endif
cp_flags_t cp_flags;
cp_key_class_t cp_pclass;
void* cp_backing_cnode;
cp_key_os_version_t cp_key_os_version;
cp_key_revision_t cp_key_revision;
uint16_t cp_raw_open_count;
cp_key_pair_t cp_keys; };
typedef uint32_t cp_xattr_flags_t;
enum {
CP_XAF_NEEDS_KEYS = 0x0001,
};
struct cp_xattr_v2 {
u_int16_t xattr_major_version;
u_int16_t xattr_minor_version;
cp_xattr_flags_t flags;
u_int32_t persistent_class;
u_int32_t key_size;
uint8_t persistent_key[CP_V2_WRAPPEDKEYSIZE];
} __attribute__((aligned(2), packed));
struct cp_xattr_v4 {
u_int16_t xattr_major_version;
u_int16_t xattr_minor_version;
cp_xattr_flags_t flags;
cp_key_class_t persistent_class;
u_int32_t key_size;
cp_key_os_version_t key_os_version;
u_int8_t reserved[CP_V4_RESERVEDBYTES];
uint8_t persistent_key[CP_MAX_WRAPPEDKEYSIZE];
} __attribute__((aligned(2), packed));
struct cp_xattr_v5 {
uint16_t xattr_major_version;
uint16_t xattr_minor_version;
cp_xattr_flags_t flags;
cp_key_class_t persistent_class;
cp_key_os_version_t key_os_version;
cp_key_revision_t key_revision;
uint16_t key_len;
uint8_t persistent_key[CP_MAX_WRAPPEDKEYSIZE];
uint8_t spare[512];
} __attribute__((aligned(2), packed));
enum {
CP_XATTR_MIN_LEN = 20, };
struct cp_root_xattr {
u_int16_t major_version;
u_int16_t minor_version;
u_int64_t flags;
} __attribute__((aligned(2), packed));
enum {
CP_ROOT_XATTR_MIN_LEN = 12,
};
int cp_entry_init(cnode_ptr_t, struct mount *);
int cpx_gentempkeys(cpx_t *pcpx, struct hfsmount *hfsmp);
void cp_entry_destroy(struct hfsmount *hfsmp, struct cprotect *entry_ptr);
void cp_replace_entry (struct hfsmount *hfsmp, struct cnode *cp, struct cprotect *newentry);
cnode_ptr_t cp_get_protected_cnode(vnode_t);
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_generate_keys (struct hfsmount *hfsmp, struct cnode *cp,
cp_key_class_t targetclass, uint32_t flags,
struct cprotect **newentry);
int cp_setup_newentry (struct hfsmount *hfsmp, struct cnode *dcp,
cp_key_class_t suppliedclass, mode_t cmode,
struct cprotect **tmpentry);
int cp_is_valid_class (int isdir, int32_t protectionclass);
int cp_set_trimmed(struct hfsmount*);
int cp_set_rewrapped(struct hfsmount *);
int cp_flop_generation (struct hfsmount*);
bool cp_is_supported_version(uint16_t version);
typedef struct cp_io_params {
cpx_t cpx;
off_t phys_offset;
off_t max_len;
} cp_io_params_t;
void cp_io_params(struct hfsmount *hfsmp, cprotect_t cpr, off_rsrc_t off_rsrc,
int direction, cp_io_params_t *io_params);
int cp_setxattr(struct cnode *cp, struct cprotect *entry, struct hfsmount *hfsmp,
uint32_t fileid, int xattr_opts);
typedef void * (* cp_new_alloc_fn)(const void *old, uint16_t pers_key_len,
uint16_t cached_key_len,
cp_key_pair_t **pcpkp);
int cp_new(cp_key_class_t *newclass_eff, struct hfsmount *hfsmp,
struct cnode *cp, mode_t cmode, int32_t keyflags,
cp_key_revision_t key_revision,
cp_new_alloc_fn alloc_fn, void **pholder);
int cp_rewrap(struct cnode *cp, __unused struct hfsmount *hfsmp,
cp_key_class_t *newclass, cp_key_pair_t *cpkp, const void *old_holder,
cp_new_alloc_fn alloc_fn, void **pholder);
cprotect_t cp_entry_alloc(cprotect_t old, uint16_t pers_keylen,
uint16_t cached_key_len, cp_key_pair_t **pcpkp);
cp_key_os_version_t cp_os_version(void);
cp_key_revision_t cp_next_key_revision(cp_key_revision_t rev);
typedef uint32_t cp_getxattr_options_t;
enum {
CP_GET_XATTR_BASIC_INFO = 1,
};
int cp_read_xattr_v5(struct hfsmount *hfsmp, struct cp_xattr_v5 *xattr,
size_t xattr_len, cprotect_t *pcpr, cp_getxattr_options_t options);
errno_t cp_handle_strategy(buf_t bp);
size_t cpkp_size(uint16_t pers_key_len, uint16_t cached_key_len);
size_t cpkp_sizex(const cp_key_pair_t *cpkp);
void cpkp_init(cp_key_pair_t *cpkp, uint16_t max_pers_key_len,
uint16_t max_cached_key_len);
void cpkp_flush(cp_key_pair_t *cpkp);
void cpkp_copy(const cp_key_pair_t *src, cp_key_pair_t *dst);
uint16_t cpkp_max_pers_key_len(const cp_key_pair_t *cpkp);
uint16_t cpkp_pers_key_len(const cp_key_pair_t *cpkp);
bool cpkp_can_copy(const cp_key_pair_t *src, const cp_key_pair_t *dst);
void cpx_init(cpx_t, size_t key_len);
bool cpx_has_key(const struct cpx *cpx);
uint16_t cpx_max_key_len(const struct cpx *cpx);
cpx_t cpkp_cpx(const cp_key_pair_t *cpkp);
void cpx_copy(const struct cpx *src, cpx_t dst);
static inline int cp_get_crypto_generation (cp_key_class_t protclass) {
if (protclass & CP_CRYPTO_G1) {
return 1;
}
else return 0;
}
__END_DECLS
#endif
#endif